Compare commits

..

24 Commits

Author SHA1 Message Date
aniampio 28177d5d5d Run fmt 2024-07-24 22:58:26 +01:00
aniampio 10b63f8667 Move functions around 2024-07-24 22:42:44 +01:00
aniampio 9989c226ae Add type attribute 2024-07-24 22:41:36 +01:00
Jędrzej Stuczyński 31f85e61f0 fixed sdk-wasm build 2024-07-24 09:31:59 +01:00
Jędrzej Stuczyński 73ac5eb19b post rebase fixes 2024-07-24 09:26:58 +01:00
Jędrzej Stuczyński f1f06ceca2 fixed incorrect naming of the ecash contract lib 2024-07-24 09:12:51 +01:00
Jędrzej Stuczyński f5841b2b60 chore: log info -> debug 2024-07-24 09:12:50 +01:00
Jędrzej Stuczyński 413ef2e11a chore: fix unit tests 2024-07-24 09:12:50 +01:00
Jędrzej Stuczyński 96a4e8b636 updated ecash-contract parameters and generated schema 2024-07-24 09:12:50 +01:00
Jędrzej Stuczyński 4e79ef1b12 updated all ecash-related parameters - bloomfilter, expiration, sizes, etc. 2024-07-24 09:12:50 +01:00
Jędrzej Stuczyński b5956933d9 improve client errors 2024-07-24 09:12:49 +01:00
Jędrzej Stuczyński 765589c444 testnet manager: create client against specific nym-node 2024-07-24 09:12:49 +01:00
Jędrzej Stuczyński 38663e41c3 testnet manager: start multiple gateways 2024-07-24 09:12:49 +01:00
Jędrzej Stuczyński 1463ddd339 fixed client crashing upon having bandwidth revoked 2024-07-24 09:12:49 +01:00
Jędrzej Stuczyński d9a2e87fc6 fixed incorrect bloomfilter cutoff date calculation 2024-07-24 09:12:48 +01:00
Jędrzej Stuczyński 4630eb6cd4 improved bandwidth information propagation within the client 2024-07-24 09:12:48 +01:00
Jędrzej Stuczyński aa00711138 fixed nym-node zk-nym config debug settings not being applied 2024-07-24 09:12:48 +01:00
Jędrzej Stuczyński 6b3292ddbc changed the number of tickets to 100 2024-07-24 09:12:48 +01:00
Jędrzej Stuczyński a5214af0df Update README.md 2024-07-24 09:12:47 +01:00
Jędrzej Stuczyński 34d25f4faf readme 2024-07-24 09:12:47 +01:00
Jędrzej Stuczyński 54e024962c slightly less ghetto handling of .env files 2024-07-24 09:12:47 +01:00
Jędrzej Stuczyński e552ebb736 removed outdated error 2024-07-24 09:12:44 +01:00
Jędrzej Stuczyński 39aa3b624f fixed query for client bandwidth 2024-07-24 09:12:44 +01:00
Simon Wicky 2d2121b331 Another Grand Ecash Squasheroo
add offline ecash library

minor changes in coconut benchmarks

add ecash smart contract

change contract traits from coconut to ecash

first wave of andrew's suggestion

first wave of andrew's suggestion

second wave of andrew's suggestion for ecash lib

andrew's suggestion for ecash contract

licensing commit

safety comments for most unwraps

more unwrap handling

change chrono crate for time

latest cargo lock

error revamp

small visibility fix

small fix

remove indexedmap from contract + some tweaks

add cw2 version in ecash contract

remove envryption key from contract

change types from coconut to ecash types

adapt api model for credential issuance

adapt issued credential storage on API

add signatures cache on API

change API routes for new blind signing

modify issued_credential table

add issuance logic client-side

credential and signature storage client side

utils for credential issuance

first wave of fix

some of andrew's suggestions

remove encryption key from deposit

freepass issuance client side

freepass issuance API side

andrew's suggested fixes

other suggested fix

adapt change from PR below

allow offline verification flag

credential spending models

credential spending models for client

credential preperation for the client

credential preperation for the client

credential storage for spending on client

bloom filter for API

spent credential storage on validators

API route for spending online and offline ecash

API routes in the client lib

credential storage on gateway

ecash verifier to replace coconut verifier

accept credentials on gateway

bandwidth expiration for gateways

client ask for more bandwidth if it runs out

credential import

adapt nym validator rewarder and sdk

fix tests api tests and add constants

cargo fmt and lock and small test fix

cargo fmt and lock and small test fix

cargo lock

move stuff where they belong in ecash and static parameters

move some constants, error handling and phase out time crate

error revamp part 2

secret key by ref instead of clone

change l in wallet and v visibility

rework payinfo

rework monster tuples

fix expiration date signature cloning

minor fixes

final bits and bobs fixes

final bits and bobs fixes

rename l accessor to tickets_spent

wave of fixes

second wave of fixes

change hash domain value

removed benchmark flag

remove useless stringification in storage

nuke Bandwidth voucher

change timestamps to offsetdatetime

key name change

post-rebase fixes

update nym-connect 'time' dep due to broken semver

upload ecash contract to the build server

make wasm zknym-lib compile

but it won't work properly just yet

make wasm zknym-lib compile

but it won't work properly just yet

fix typo in ecash contract deps

make sure to use 0.1.0 sphinx packet

optimise pairings in 'check_vk_pairing'

derive serde for ecash types

simplified g1 tuple byte conversion

further optimise the pairing

unified signature type + renamed nym-api coconut module to ecash

using bincode serialiser for more complex binary types

using multimiller loop instead of rayon for verifying coin indices signatures

batching signature verification wherever possible

feature-locked rayon

clippy

refactor ecash contract a bit + introduce deposit storage

reworked find_proposal_id

various minor fixed

add offline_zk_nyms to nym-node everywhere

add missing #query

change test value to fit new serialization

optimised deposits storage

removed duplicate decompression code

using deposit_id instead of transaction hash

removed freepasses

split up ecash handling

unified shared state

fixed deposit_id parsing

log recovered deposit id

removed online verification

add detailed build info to ecash contract

fixed deserialisation of deposit amount received from nyxd queries

changed deposit to only persist attached pubkey

first iteration of split of verification and redemption

basic tool for setting up new network

expanded the tool with the option to bypass DKG

rename + init network without DKG

setting up locally running apis

ecash key migration

more local functionalities

wip fixing sql schemas

gateway immediately submitting redemption proposal

and getting it passed if valid

most of the gateway logic for split redemption with error recovery

fixed gateway not persisting ecash signers

simplify creation of compatible client

create properly serialised ecash key from the beginning

rebuild missing tickets and proposals on startup

stop ticket issuance during DKG transition

fixing build issues

split out ecash storage on nym-api side

master-verification-key route

caching all the signatures and keys

implemented aggregated routes for nym-apis

swagger UI for ecash endpoints

added explicit annotation for index and expiration signatures

revamped client ticketbook storage

save all recovery information in the same underlying storage

wrapper for bloomfilter

being more aggressive with marking tickets as used

ensure client has correct signatures before making deposit

fix deserialisation of AggregatedExpirationDateSignatureResponse + add ticketbook table

split nym-api ecash routes handlers into multiple files

fixed deserialisation of encoded expiration date

add tt_gamma1 to challenge and change naming for paper consistency

rotating double spending bloomfilter

nym-api test fixes + make sure to insert initial BF params

fixed ecash benchmark code

updated contract schema

updated CI to not upload gateway/mixnode binaries

ticket bandwidth revocation

added default deserialisation for zk nym config

post-rebase fixes
2024-07-24 09:12:43 +01:00
358 changed files with 5190 additions and 7407 deletions
@@ -8,6 +8,11 @@ on:
required: true
default: false
type: boolean
enable_wireguard:
description: "Add --features wireguard"
required: true
default: false
type: boolean
enable_deb:
description: "True to enable cargo-deb installation and .deb package building"
required: false
@@ -65,6 +70,9 @@ jobs:
- name: Set CARGO_FEATURES
run: |
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
if: >
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && inputs.enable_wireguard == true)
- name: Install Rust stable
uses: actions-rs/toolchain@v1
+2 -6
View File
@@ -51,10 +51,6 @@ jobs:
echo 'RUSTFLAGS="--cfg tokio_unstable"' >> $GITHUB_ENV
if: github.event_name == 'workflow_dispatch' && inputs.add_tokio_unstable == true
- name: Set CARGO_FEATURES
run: |
echo 'CARGO_FEATURES=--features wireguard' >> $GITHUB_ENV
- name: Install Rust stable
uses: actions-rs/toolchain@v1
with:
@@ -64,8 +60,8 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace --release ${{ env.CARGO_FEATURES }}
args: --workspace --release
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
+1 -38
View File
@@ -4,44 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.9-topdeck] (2024-07-26)
- chore: fix 1.80 lint issues ([#4731])
- Handle clients with different versions in IPR ([#4723])
- Add 1GB/day/user bandwidth cap ([#4717])
- Feature/merge back ([#4710])
- removed mixnode/gateway config migration code and disabled cli without explicit flag ([#4706])
[#4731]: https://github.com/nymtech/nym/pull/4731
[#4723]: https://github.com/nymtech/nym/pull/4723
[#4717]: https://github.com/nymtech/nym/pull/4717
[#4710]: https://github.com/nymtech/nym/pull/4710
[#4706]: https://github.com/nymtech/nym/pull/4706
## [2024.8-wispa] (2024-07-10)
- add event parsing to support cosmos_sdk > 0.50 ([#4697])
- Fix NR config compatibility ([#4690])
- Remove UserAgent constructor since it's weakly typed ([#4689])
- [bugfix]: Node_api_check CLI looked over roles on blacklisted nodes ([#4687])
- Add mixnodes to self describing api cache ([#4684])
- Move and whole bump of crates to workspace and upgrade some ([#4680])
- Remove code that refers to removed nym-network-statistics ([#4679])
- Remove nym-network-statistics ([#4678])
- Create UserAgent that can be passed from the binary to the nym api client ([#4677])
- Add authenticator ([#4667])
[#4697]: https://github.com/nymtech/nym/pull/4697
[#4690]: https://github.com/nymtech/nym/pull/4690
[#4689]: https://github.com/nymtech/nym/pull/4689
[#4687]: https://github.com/nymtech/nym/pull/4687
[#4684]: https://github.com/nymtech/nym/pull/4684
[#4680]: https://github.com/nymtech/nym/pull/4680
[#4679]: https://github.com/nymtech/nym/pull/4679
[#4678]: https://github.com/nymtech/nym/pull/4678
[#4677]: https://github.com/nymtech/nym/pull/4677
[#4667]: https://github.com/nymtech/nym/pull/4667
## [2024.7-doubledecker] (2024-07-04)
- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
@@ -551,6 +513,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[#3187]: https://github.com/nymtech/nym/issues/3187
[#3203]: https://github.com/nymtech/nym/pull/3203
[#3199]: https://github.com/nymtech/nym/pull/3199
>>>>>>> master
## [v1.1.13] (2023-03-15)
Generated
+31 -70
View File
@@ -1471,7 +1471,7 @@ dependencies = [
"bitflags 1.3.2",
"crossterm_winapi",
"libc",
"mio 0.8.11",
"mio",
"parking_lot 0.12.3",
"signal-hook",
"signal-hook-mio",
@@ -1487,7 +1487,7 @@ dependencies = [
"bitflags 1.3.2",
"crossterm_winapi",
"libc",
"mio 0.8.11",
"mio",
"parking_lot 0.12.3",
"signal-hook",
"signal-hook-mio",
@@ -2240,7 +2240,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "explorer-api"
version = "1.1.38"
version = "1.1.36"
dependencies = [
"chrono",
"clap 4.5.7",
@@ -3933,18 +3933,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "mio"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
dependencies = [
"hermit-abi 0.3.9",
"libc",
"wasi",
"windows-sys 0.52.0",
]
[[package]]
name = "mix-fetch-wasm"
version = "1.3.0-rc.0"
@@ -4126,7 +4114,7 @@ dependencies = [
"inotify",
"kqueue",
"libc",
"mio 0.8.11",
"mio",
"walkdir",
"windows-sys 0.45.0",
]
@@ -4204,7 +4192,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "nym-api"
version = "1.1.42"
version = "1.1.40"
dependencies = [
"anyhow",
"async-trait",
@@ -4294,10 +4282,10 @@ dependencies = [
"nym-ecash-time",
"nym-mixnet-contract-common",
"nym-node-requests",
"nym-serde-helpers",
"rocket",
"schemars",
"serde",
"serde-helpers",
"serde_json",
"sha2 0.10.8",
"tendermint 0.37.0",
@@ -4325,7 +4313,6 @@ dependencies = [
"bs58 0.5.1",
"bytes",
"clap 4.5.7",
"defguard_wireguard_rs",
"fastrand 2.1.0",
"futures",
"ipnetwork 0.16.0",
@@ -4425,7 +4412,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.40"
version = "1.1.38"
dependencies = [
"anyhow",
"base64 0.13.1",
@@ -4504,7 +4491,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.39"
version = "1.1.37"
dependencies = [
"bs58 0.5.1",
"clap 4.5.7",
@@ -4563,7 +4550,6 @@ dependencies = [
"nym-config",
"nym-country-group",
"nym-credential-storage",
"nym-credentials-interface",
"nym-crypto",
"nym-ecash-time",
"nym-explorer-client",
@@ -4810,10 +4796,10 @@ dependencies = [
"log",
"nym-bandwidth-controller",
"nym-client-core",
"nym-compact-ecash",
"nym-config",
"nym-credential-storage",
"nym-credentials",
"nym-credentials-interface",
"nym-ecash-time",
"nym-validator-client",
"thiserror",
@@ -4850,10 +4836,8 @@ dependencies = [
"bls12_381",
"nym-compact-ecash",
"nym-ecash-time",
"nym-network-defaults",
"rand 0.8.5",
"serde",
"strum 0.25.0",
"thiserror",
"time",
]
@@ -5013,7 +4997,6 @@ dependencies = [
"nym-ecash-contract-common",
"nym-ecash-double-spending",
"nym-gateway-requests",
"nym-gateway-storage",
"nym-ip-packet-router",
"nym-mixnet-client",
"nym-mixnode-common",
@@ -5103,24 +5086,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "nym-gateway-storage"
version = "0.1.0"
dependencies = [
"async-trait",
"bincode",
"defguard_wireguard_rs",
"log",
"nym-credentials-interface",
"nym-gateway-requests",
"nym-sphinx",
"sqlx",
"thiserror",
"time",
"tokio",
"tracing",
]
[[package]]
name = "nym-group-contract-common"
version = "0.1.0"
@@ -5412,7 +5377,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.40"
version = "1.1.38"
dependencies = [
"addr",
"anyhow",
@@ -5463,7 +5428,7 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.1.6"
version = "1.1.4"
dependencies = [
"anyhow",
"bip39",
@@ -5683,7 +5648,6 @@ dependencies = [
"nym-credential-storage",
"nym-credential-utils",
"nym-credentials",
"nym-credentials-interface",
"nym-crypto",
"nym-gateway-requests",
"nym-network-defaults",
@@ -5709,15 +5673,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "nym-serde-helpers"
version = "0.1.0"
dependencies = [
"base64 0.21.7",
"bs58 0.5.1",
"serde",
]
[[package]]
name = "nym-service-providers-common"
version = "0.1.0"
@@ -5737,7 +5692,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.39"
version = "1.1.37"
dependencies = [
"bs58 0.5.1",
"clap 4.5.7",
@@ -6162,14 +6117,12 @@ dependencies = [
"nym-compact-ecash",
"nym-config",
"nym-credentials",
"nym-credentials-interface",
"nym-crypto",
"nym-ecash-time",
"nym-network-defaults",
"nym-task",
"nym-validator-client",
"nyxd-scraper",
"rand_chacha 0.3.1",
"serde",
"serde_with",
"sha2 0.10.8",
@@ -6220,14 +6173,12 @@ name = "nym-wireguard"
version = "0.1.0"
dependencies = [
"base64 0.21.7",
"bincode",
"chrono",
"dashmap",
"defguard_wireguard_rs",
"ip_network",
"log",
"nym-crypto",
"nym-gateway-storage",
"nym-network-defaults",
"nym-task",
"nym-wireguard-types",
@@ -6242,6 +6193,7 @@ name = "nym-wireguard-types"
version = "0.1.0"
dependencies = [
"base64 0.21.7",
"dashmap",
"hmac",
"log",
"nym-config",
@@ -6258,7 +6210,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.5"
version = "0.1.3"
dependencies = [
"anyhow",
"bytes",
@@ -7962,6 +7914,15 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde-helpers"
version = "0.1.0"
dependencies = [
"base64 0.21.7",
"bs58 0.5.1",
"serde",
]
[[package]]
name = "serde-json-wasm"
version = "0.5.0"
@@ -8218,7 +8179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
dependencies = [
"libc",
"mio 0.8.11",
"mio",
"signal-hook",
]
@@ -9065,21 +9026,22 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.39.2"
version = "1.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio 1.0.1",
"mio",
"num_cpus",
"parking_lot 0.12.3",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"tracing",
"windows-sys 0.52.0",
"windows-sys 0.48.0",
]
[[package]]
@@ -9094,9 +9056,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "2.4.0"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [
"proc-macro2",
"quote",
@@ -10076,7 +10038,6 @@ dependencies = [
name = "wasm-utils"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"futures",
"getrandom",
"gloo-net",
+8 -9
View File
@@ -52,8 +52,6 @@ members = [
"common/ecash-time",
"common/execute",
"common/exit-policy",
"common/gateway-requests",
"common/gateway-storage",
"common/http-api-client",
"common/http-api-common",
"common/inclusion-probability",
@@ -98,6 +96,7 @@ members = [
"explorer-api/explorer-api-requests",
"explorer-api/explorer-client",
"gateway",
"gateway/gateway-requests",
"integrations/bity",
"mixnode",
"sdk/lib/socks5-listener",
@@ -140,7 +139,7 @@ default-members = [
"tools/nymvisor",
"explorer-api",
"nym-validator-rewarder",
"nym-node",
"nym-node"
]
exclude = [
@@ -291,11 +290,11 @@ tar = "0.4.40"
tempfile = "3.5.0"
thiserror = "1.0.48"
time = "0.3.30"
tokio = "1.39"
tokio-stream = "0.1.15"
tokio-test = "0.4.4"
tokio = "1.33.0"
tokio-stream = "0.1.14"
tokio-test = "0.4.2"
tokio-tungstenite = { version = "0.20.1" }
tokio-util = "0.7.11"
tokio-util = "0.7.10"
toml = "0.8.14"
tower = "0.4.13"
tower-http = "0.5.2"
@@ -347,8 +346,8 @@ bip32 = { version = "0.5.1", default-features = false }
# plus response message parsing (which is, as of the time of writing this message, waiting to get merged)
#cosmrs = { path = "../cosmos-rust-fork/cosmos-rust/cosmrs" }
cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" } # unfortuntely we need a fork by yours truly to get the staking support
tendermint = "0.37.0" # same version as used by cosmrs
tendermint-rpc = "0.37.0" # same version as used by cosmrs
tendermint = "0.37.0" # same version as used by cosmrs
tendermint-rpc = "0.37.0" # same version as used by cosmrs
prost = { version = "0.12", default-features = false }
# wasm-related dependencies
+7 -23
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.39"
version = "1.1.37"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
@@ -26,46 +26,30 @@ clap = { workspace = true, features = ["cargo", "derive"] }
dirs = { workspace = true }
log = { workspace = true } # self explanatory
rand = { workspace = true }
serde = { workspace = true, features = [
"derive",
] } # for config serialization/deserialization
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
thiserror = { workspace = true }
tap = { workspace = true }
time = { workspace = true }
tokio = { workspace = true, features = [
"rt-multi-thread",
"net",
"signal",
] } # async runtime
tokio = { workspace = true, features = ["rt-multi-thread", "net", "signal"] } # async runtime
tokio-tungstenite = { workspace = true }
zeroize = { workspace = true }
## internal
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-bin-common = { path = "../../common/bin-common", features = [
"output_format",
"clap",
] }
nym-client-core = { path = "../../common/client-core", features = [
"fs-credentials-storage",
"fs-surb-storage",
"fs-gateways-storage",
"cli",
] }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format", "clap"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] }
nym-config = { path = "../../common/config" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credentials = { path = "../../common/credentials" }
nym-crypto = { path = "../../common/crypto" }
nym-gateway-requests = { path = "../../common/gateway-requests" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-pemstore = { path = "../../common/pemstore" }
nym-task = { path = "../../common/task" }
nym-topology = { path = "../../common/topology" }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = [
"http-client",
] }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
nym-client-websocket-requests = { path = "websocket-requests" }
nym-id = { path = "../../common/nym-id" }
+1 -1
View File
@@ -422,7 +422,7 @@ impl Handler {
) {
// We don't want a crash in the connection handler to trigger a shutdown of the whole
// process.
task_client.disarm();
task_client.mark_as_success();
let ws_stream = match accept_async(socket).await {
Ok(ws_stream) => ws_stream,
+6 -18
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.39"
version = "1.1.37"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
@@ -11,9 +11,7 @@ license.workspace = true
bs58 = { workspace = true }
clap = { workspace = true, features = ["cargo", "derive"] }
log = { workspace = true }
serde = { workspace = true, features = [
"derive",
] } # for config serialization/deserialization
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
serde_json = { workspace = true }
tap = { workspace = true }
thiserror = { workspace = true }
@@ -24,21 +22,13 @@ url = { workspace = true }
zeroize = { workspace = true }
# internal
nym-bin-common = { path = "../../common/bin-common", features = [
"output_format",
"clap",
] }
nym-client-core = { path = "../../common/client-core", features = [
"fs-credentials-storage",
"fs-surb-storage",
"fs-gateways-storage",
"cli",
] }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] }
nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] }
nym-config = { path = "../../common/config" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-credentials = { path = "../../common/credentials" }
nym-crypto = { path = "../../common/crypto" }
nym-gateway-requests = { path = "../../common/gateway-requests" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-id = { path = "../../common/nym-id" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
@@ -46,9 +36,7 @@ nym-pemstore = { path = "../../common/pemstore" }
nym-socks5-client-core = { path = "../../common/socks5-client-core" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-topology = { path = "../../common/topology" }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = [
"http-client",
] }
nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["http-client"] }
[features]
default = []
@@ -8,7 +8,6 @@ use nym_credential_storage::storage::Storage;
use nym_credentials::ecash::bandwidth::IssuanceTicketBook;
use nym_credentials::ecash::utils::obtain_aggregate_wallet;
use nym_credentials::IssuedTicketBook;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use nym_ecash_time::{ecash_default_expiration_date, Date};
use nym_validator_client::coconut::all_ecash_api_clients;
@@ -23,7 +22,6 @@ pub async fn make_deposit<C>(
client: &C,
client_id: &[u8],
expiration: Option<Date>,
ticketbook_type: TicketType,
) -> Result<IssuanceTicketBook, BandwidthControllerError>
where
C: EcashSigningClient + EcashQueryClient + Sync,
@@ -50,7 +48,6 @@ where
deposit_id,
client_id,
signing_key,
ticketbook_type,
expiration,
))
}
+2 -6
View File
@@ -38,7 +38,7 @@ nym-country-group = { path = "../country-group" }
nym-crypto = { path = "../crypto" }
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
nym-gateway-client = { path = "../client-libs/gateway-client" }
nym-gateway-requests = { path = "../gateway-requests" }
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
nym-metrics = { path = "../nym-metrics" }
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
nym-sphinx = { path = "../nymsphinx" }
@@ -46,12 +46,9 @@ nym-pemstore = { path = "../pemstore" }
nym-topology = { path = "../topology", features = ["serializable"] }
nym-validator-client = { path = "../client-libs/validator-client", default-features = false }
nym-task = { path = "../task" }
nym-credentials-interface = { path = "../credentials-interface" }
nym-credential-storage = { path = "../credential-storage" }
nym-network-defaults = { path = "../network-defaults" }
nym-client-core-config-types = { path = "./config-types", features = [
"disk-persistence",
] }
nym-client-core-config-types = { path = "./config-types", features = ["disk-persistence"] }
nym-client-core-surb-storage = { path = "./surb-storage" }
nym-client-core-gateways-storage = { path = "./gateways-storage" }
nym-ecash-time = { path = "../ecash-time" }
@@ -118,7 +115,6 @@ tempfile = { workspace = true }
[features]
default = []
cli = ["clap", "comfy-table"]
fs-credentials-storage = ["nym-credential-storage/persistent-storage"]
fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"]
fs-gateways-storage = ["nym-client-core-gateways-storage/fs-gateways-storage"]
wasm = ["nym-gateway-client/wasm"]
@@ -18,7 +18,7 @@ url.workspace = true
zeroize = { workspace = true, features = ["zeroize_derive"] }
nym-crypto = { path = "../../crypto", features = ["asymmetric"] }
nym-gateway-requests = { path = "../../gateway-requests" }
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
workspace = true
@@ -27,12 +27,7 @@ optional = true
[build-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
sqlx = { workspace = true, features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
] }
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
[features]
fs-gateways-storage = ["sqlx"]
fs-gateways-storage = ["sqlx"]
@@ -5,15 +5,14 @@ use crate::cli_helpers::{CliClient, CliClientConfig};
use crate::error::ClientCoreError;
use nym_credential_storage::models::BasicTicketbookInformation;
use nym_credential_storage::storage::Storage;
use nym_credentials_interface::TicketType;
use nym_ecash_time::ecash_today;
use nym_network_defaults::TicketbookType::MixnetEntry;
use serde::{Deserialize, Serialize};
use time::Date;
#[derive(Serialize, Deserialize)]
pub struct AvailableTicketbook {
pub id: i64,
pub typ: TicketType,
pub expiration: Date,
pub issued_tickets: u32,
pub claimed_tickets: u32,
@@ -46,7 +45,6 @@ impl AvailableTicketbook {
vec![
comfy_table::Cell::new(self.id.to_string()),
comfy_table::Cell::new(self.typ),
expiration,
comfy_table::Cell::new(format!("{issued} ({si_issued})")),
comfy_table::Cell::new(format!("{claimed} ({si_claimed})")),
@@ -57,22 +55,17 @@ impl AvailableTicketbook {
}
}
impl TryFrom<BasicTicketbookInformation> for AvailableTicketbook {
type Error = ClientCoreError;
fn try_from(value: BasicTicketbookInformation) -> Result<Self, Self::Error> {
let typ = value
.ticketbook_type
.parse()
.map_err(|_| ClientCoreError::UnknownTicketType)?;
Ok(AvailableTicketbook {
impl From<BasicTicketbookInformation> for AvailableTicketbook {
fn from(value: BasicTicketbookInformation) -> Self {
AvailableTicketbook {
id: value.id,
typ,
expiration: value.expiration_date,
issued_tickets: value.total_tickets,
claimed_tickets: value.used_tickets,
ticket_size: typ.to_repr().bandwidth_value(),
})
// TODO: this will change when 'type' field is introduced; for now doesn't matter what we put there
ticket_size: MixnetEntry.bandwidth_value(),
}
}
}
@@ -86,7 +79,6 @@ impl std::fmt::Display for AvailableTicketbooks {
let mut table = comfy_table::Table::new();
table.set_header(vec![
"id",
"type",
"expiration",
"issued tickets (bandwidth)",
"claimed tickets (bandwidth)",
@@ -132,9 +124,6 @@ where
})?;
Ok(AvailableTicketbooks(
ticketbooks
.into_iter()
.map(TryInto::<AvailableTicketbook>::try_into)
.collect::<Result<_, _>>()?,
ticketbooks.into_iter().map(Into::into).collect(),
))
}
@@ -455,7 +455,7 @@ where
Err(ClientCoreError::CustomGatewaySelectionExpected)
} else {
// and make sure to invalidate the task client so we wouldn't cause premature shutdown
shutdown.disarm();
shutdown.mark_as_success();
custom_gateway_transceiver.set_packet_router(packet_router)?;
Ok(custom_gateway_transceiver)
};
@@ -562,7 +562,7 @@ where
if topology_config.disable_refreshing {
// if we're not spawning the refresher, don't cause shutdown immediately
info!("The topology refesher is not going to be started");
shutdown.disarm();
shutdown.mark_as_success();
} else {
// don't spawn the refresher if we don't want to be refreshing the topology.
// only use the initial values obtained
@@ -23,7 +23,7 @@ use crate::{
config::{self, disk_persistence::CommonClientPaths},
error::ClientCoreError,
};
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-credentials-storage"))]
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage;
pub use nym_client_core_gateways_storage as gateways_storage;
@@ -474,6 +474,13 @@ where
Poll::Ready(Some((real_messages, conn_id))) => {
log::trace!("handling real_messages: size: {}", real_messages.len());
// This is the last step in the pipeline where we know the type of the message, so
// lets count the number of retransmissions here.
if conn_id == TransmissionLane::Retransmission {
self.stats_tx
.report(PacketStatisticsEvent::RetransmissionQueued);
}
// First store what we got for the given connection id
self.transmission_buffer.store(&conn_id, real_messages);
let real_next = self.pop_next_message().expect("we just added one");
-3
View File
@@ -68,9 +68,6 @@ pub enum ClientCoreError {
source: Box<dyn Error + Send + Sync>,
},
#[error("the provided ticket type is invalid")]
UnknownTicketType,
#[error("the gateway id is invalid - {0}")]
UnableToCreatePublicKeyFromGatewayId(Ed25519RecoveryError),
+18 -40
View File
@@ -46,34 +46,13 @@ const MEASUREMENTS: usize = 3;
const CONN_TIMEOUT: Duration = Duration::from_millis(1500);
const PING_TIMEOUT: Duration = Duration::from_millis(1000);
// The abstraction that some of these helpers use
pub trait ConnectableGateway {
fn identity(&self) -> &identity::PublicKey;
fn clients_address(&self) -> String;
fn is_wss(&self) -> bool;
}
impl ConnectableGateway for gateway::Node {
fn identity(&self) -> &identity::PublicKey {
self.identity()
}
fn clients_address(&self) -> String {
self.clients_address()
}
fn is_wss(&self) -> bool {
self.clients_wss_port.is_some()
}
}
struct GatewayWithLatency<'a, G: ConnectableGateway> {
gateway: &'a G,
struct GatewayWithLatency<'a> {
gateway: &'a gateway::Node,
latency: Duration,
}
impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
fn new(gateway: &'a G, latency: Duration) -> Self {
impl<'a> GatewayWithLatency<'a> {
fn new(gateway: &'a gateway::Node, latency: Duration) -> Self {
GatewayWithLatency { gateway, latency }
}
}
@@ -151,14 +130,11 @@ async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
JSWebsocket::new(endpoint).map_err(|_| ClientCoreError::GatewayJsConnectionFailure)
}
async fn measure_latency<G>(gateway: &G) -> Result<GatewayWithLatency<G>, ClientCoreError>
where
G: ConnectableGateway,
{
async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency, ClientCoreError> {
let addr = gateway.clients_address();
trace!(
"establishing connection to {} ({addr})...",
gateway.identity(),
gateway.identity_key,
);
let mut stream = connect(&addr).await?;
@@ -201,7 +177,7 @@ where
let count = results.len() as u64;
if count == 0 {
return Err(ClientCoreError::NoGatewayMeasurements {
identity: gateway.identity().to_base58_string(),
identity: gateway.identity_key.to_base58_string(),
});
}
@@ -211,11 +187,11 @@ where
Ok(GatewayWithLatency::new(gateway, avg))
}
pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone>(
pub async fn choose_gateway_by_latency<R: Rng>(
rng: &mut R,
gateways: &[G],
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<G, ClientCoreError> {
) -> Result<gateway::Node, ClientCoreError> {
let gateways = filter_by_tls(gateways, must_use_tls)?;
info!(
@@ -247,19 +223,21 @@ pub async fn choose_gateway_by_latency<'a, R: Rng, G: ConnectableGateway + Clone
info!(
"chose gateway {} with average latency of {:?}",
chosen.gateway.identity(),
chosen.latency
chosen.gateway.identity_key, chosen.latency
);
Ok(chosen.gateway.clone())
}
fn filter_by_tls<G: ConnectableGateway>(
gateways: &[G],
fn filter_by_tls(
gateways: &[gateway::Node],
must_use_tls: bool,
) -> Result<Vec<&G>, ClientCoreError> {
) -> Result<Vec<&gateway::Node>, ClientCoreError> {
if must_use_tls {
let filtered = gateways.iter().filter(|g| g.is_wss()).collect::<Vec<_>>();
let filtered = gateways
.iter()
.filter(|g| g.clients_wss_port.is_some())
.collect::<Vec<_>>();
if filtered.is_empty() {
return Err(ClientCoreError::NoWssGateways);
-2
View File
@@ -2,9 +2,7 @@ use std::future::Future;
#[cfg(all(
not(target_arch = "wasm32"),
feature = "cli",
feature = "fs-surb-storage",
feature = "fs-credentials-storage",
feature = "fs-gateways-storage"
))]
pub mod cli_helpers;
+1 -1
View File
@@ -24,7 +24,7 @@ nym-bandwidth-controller = { path = "../../bandwidth-controller" }
nym-credentials = { path = "../../credentials" }
nym-credential-storage = { path = "../../credential-storage" }
nym-crypto = { path = "../../crypto" }
nym-gateway-requests = { path = "../../gateway-requests" }
nym-gateway-requests = { path = "../../../gateway/gateway-requests" }
nym-network-defaults = { path = "../../network-defaults" }
nym-sphinx = { path = "../../nymsphinx" }
nym-pemstore = { path = "../../pemstore" }
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::error::GatewayClientError;
use nym_network_defaults::TicketTypeRepr::V1MixnetEntry;
use nym_network_defaults::TicketbookType::MixnetEntry;
use si_scale::helpers::bibytes2;
use std::time::Duration;
@@ -103,7 +103,7 @@ impl BandwidthTickets {
// 20% of entry ticket value
pub const DEFAULT_REMAINING_BANDWIDTH_THRESHOLD: i64 =
(V1MixnetEntry.bandwidth_value() / 5) as i64;
(MixnetEntry.bandwidth_value() / 5) as i64;
pub const DEFAULT_CUTOFF_REMAINING_BANDWIDTH_THRESHOLD: Option<i64> = None;
@@ -70,8 +70,8 @@ impl PacketRouter {
Ok(())
}
pub fn disarm(&mut self) {
self.shutdown.disarm();
pub fn mark_as_success(&mut self) {
self.shutdown.mark_as_success();
}
}
@@ -113,8 +113,8 @@ impl PartiallyDelegatedRouter {
let return_res = match ret {
Err(err) => self.stream_return.send(Err(err)),
Ok(_) => {
self.packet_router.disarm();
task_client.disarm();
self.packet_router.mark_as_success();
task_client.mark_as_success();
self.stream_return.send(Ok(split_stream))
}
};
@@ -23,8 +23,8 @@ use nym_api_requests::ecash::VerificationKeyResponse;
pub use nym_api_requests::{
ecash::{
models::{
EpochCredentialsResponse, IssuedCredentialResponse, IssuedCredentialsResponse,
IssuedTicketbook, IssuedTicketbookBody, SpentCredentialsResponse,
EpochCredentialsResponse, IssuedCredential, IssuedCredentialBody,
IssuedCredentialResponse, IssuedCredentialsResponse, SpentCredentialsResponse,
},
BlindSignRequestBody, BlindedSignatureResponse, CredentialsRequestBody,
PartialCoinIndicesSignatureResponse, PartialExpirationDateSignatureResponse,
@@ -683,24 +683,6 @@ pub trait MixnetSigningClient {
.await
}
async fn migrate_vested_mixnode(&self, fee: Option<Fee>) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(fee, MixnetExecuteMsg::MigrateVestedMixNode {}, vec![])
.await
}
async fn migrate_vested_delegation(
&self,
mix_id: MixId,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
self.execute_mixnet_contract(
fee,
MixnetExecuteMsg::MigrateVestedDelegation { mix_id },
vec![],
)
.await
}
#[cfg(feature = "contract-testing")]
async fn testing_resolve_all_pending_events(
&self,
@@ -946,12 +928,6 @@ mod tests {
MixnetExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, owner } => client
.withdraw_delegator_reward_on_behalf(owner.parse().unwrap(), mix_id, None)
.ignore(),
MixnetExecuteMsg::MigrateVestedMixNode { .. } => {
client.migrate_vested_mixnode(None).ignore()
}
MixnetExecuteMsg::MigrateVestedDelegation { mix_id } => {
client.migrate_vested_delegation(mix_id, None).ignore()
}
#[cfg(feature = "contract-testing")]
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
@@ -437,7 +437,6 @@ where
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
use nym_vesting_contract_common::ExecuteMsg;
// it's enough that this compiles and clippy is happy about it
#[allow(dead_code)]
@@ -561,9 +560,6 @@ mod tests {
VestingExecuteMsg::UpdateLockedPledgeCap { address, cap } => client
.update_locked_pledge_cap(address.parse().unwrap(), cap, None)
.ignore(),
// those will never be manually called by clients
ExecuteMsg::TrackMigratedMixnode { .. } => "explicitly_ignored".ignore(),
ExecuteMsg::TrackMigratedDelegation { .. } => "explicitly_ignored".ignore(),
};
}
}
@@ -1,11 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// TEMPORARY WORKAROUND:
// those features are expected as the below should only get activated whenever
// the corresponding features in tendermint-rpc are enabled transitively
#![allow(unexpected_cfgs)]
use crate::nyxd::cosmwasm_client::client_traits::SigningCosmWasmClient;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{Config, GasPrice, Hash, Height};
@@ -1,11 +1,6 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// TEMPORARY WORKAROUND:
// those features are expected as the below should only get activated whenever
// the corresponding features in tendermint-rpc are enabled transitively
#![allow(unexpected_cfgs)]
use crate::nyxd::contract_traits::{NymContractsProvider, TypedNymContracts};
use crate::nyxd::cosmwasm_client::types::{
ChangeAdminResult, ContractCodeId, ExecuteResult, InstantiateOptions, InstantiateResult,
@@ -1,11 +1,6 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// TEMPORARY WORKAROUND:
// those features are expected as the below should only get activated whenever
// the corresponding features in tendermint-rpc are enabled transitively
#![allow(unexpected_cfgs)]
use async_trait::async_trait;
use cosmrs::tendermint::{self, abci, block::Height, evidence::Evidence, Genesis, Hash};
use serde::{de::DeserializeOwned, Serialize};
@@ -7,16 +7,11 @@ use anyhow::bail;
use clap::Parser;
use nym_credential_storage::initialise_persistent_storage;
use nym_credential_utils::utils;
use nym_credentials_interface::TicketType;
use nym_crypto::asymmetric::identity;
use std::path::PathBuf;
#[derive(Debug, Parser)]
pub struct Args {
/// Specify which type of ticketbook should be issued
#[clap(long, default_value_t = TicketType::default())]
pub(crate) ticketbook_type: TicketType,
/// Config file of the client that is supposed to use the credential.
#[clap(long)]
pub(crate) client_config: PathBuf,
@@ -44,13 +39,7 @@ pub async fn execute(args: Args, client: SigningClient) -> anyhow::Result<()> {
let persistent_storage = initialise_persistent_storage(credentials_store).await;
let private_id_key: identity::PrivateKey = nym_pemstore::load_key(private_id_key)?;
utils::issue_credential(
&client,
&persistent_storage,
&private_id_key.to_bytes(),
args.ticketbook_type,
)
.await?;
utils::issue_credential(&client, &persistent_storage, &private_id_key.to_bytes()).await?;
Ok(())
}
@@ -1,26 +1,15 @@
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::Parser;
use cosmwasm_std::Decimal;
use log::{debug, info};
use nym_mixnet_contract_common::{
InitialRewardingParams, InstantiateMsg, OperatingCostRange, Percent, ProfitMarginRange,
};
use nym_network_defaults::mainnet::MIX_DENOM;
use nym_network_defaults::TOTAL_SUPPLY;
use nym_validator_client::nyxd::{AccountId, Coin};
use cosmwasm_std::Decimal;
use nym_mixnet_contract_common::{InitialRewardingParams, InstantiateMsg, Percent};
use nym_validator_client::nyxd::AccountId;
use std::str::FromStr;
use std::time::Duration;
pub fn default_maximum_operating_cost() -> Coin {
Coin::new(TOTAL_SUPPLY, MIX_DENOM.base)
}
pub fn default_minimum_operating_cost() -> Coin {
Coin::new(0, MIX_DENOM.base)
}
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
@@ -61,18 +50,6 @@ pub struct Args {
#[clap(long, default_value_t = 240)]
pub active_set_size: u32,
#[clap(long, default_value_t = Percent::zero())]
pub minimum_profit_margin_percent: Percent,
#[clap(long, default_value_t = Percent::hundred())]
pub maximum_profit_margin_percent: Percent,
#[clap(long, default_value_t = default_minimum_operating_cost())]
pub minimum_interval_operating_cost: Coin,
#[clap(long, default_value_t = default_maximum_operating_cost())]
pub maximum_interval_operating_cost: Coin,
}
pub async fn generate(args: Args) {
@@ -120,10 +97,6 @@ pub async fn generate(args: Args) {
.expect("Rewarding (mix) denom has to be set")
});
if args.minimum_interval_operating_cost.denom != args.maximum_interval_operating_cost.denom {
panic!("different denoms for operating cost bounds")
}
let instantiate_msg = InstantiateMsg {
rewarding_validator_address: rewarding_validator_address.to_string(),
vesting_contract_address: vesting_contract_address.to_string(),
@@ -131,14 +104,6 @@ pub async fn generate(args: Args) {
epochs_in_interval: args.epochs_in_interval,
epoch_duration: Duration::from_secs(args.epoch_duration),
initial_rewarding_params,
profit_margin: ProfitMarginRange {
minimum: args.minimum_profit_margin_percent,
maximum: args.maximum_profit_margin_percent,
},
interval_operating_cost: OperatingCostRange {
minimum: args.minimum_interval_operating_cost.amount.into(),
maximum: args.maximum_interval_operating_cost.amount.into(),
},
};
debug!("instantiate_msg: {:?}", instantiate_msg);
@@ -1,42 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, MixnetSigningClient};
#[derive(Debug, Parser)]
pub struct Args {
#[clap(long)]
pub mix_id: Option<MixId>,
#[clap(long)]
pub identity_key: Option<String>,
}
pub async fn migrate_vested_delegation(args: Args, client: SigningClient) {
let mix_id = match args.mix_id {
Some(mix_id) => mix_id,
None => {
let identity_key = args
.identity_key
.expect("either mix_id or mix_identity has to be specified");
let node_details = client
.get_mixnode_details_by_identity(identity_key)
.await
.expect("contract query failed")
.mixnode_details
.expect("mixnode with the specified identity doesnt exist");
node_details.mix_id()
}
};
let res = client
.migrate_vested_delegation(mix_id, None)
.await
.expect("failed to migrate delegation!");
info!("migration result: {:?}", res)
}
@@ -7,7 +7,6 @@ pub mod rewards;
pub mod delegate_to_mixnode;
pub mod delegate_to_multiple_mixnodes;
pub mod migrate_vested_delegation;
pub mod query_for_delegations;
pub mod undelegate_from_mixnode;
pub mod vesting_delegate_to_mixnode;
@@ -36,6 +35,4 @@ pub enum MixnetDelegatorsCommands {
DelegateVesting(vesting_delegate_to_mixnode::Args),
/// Undelegate from a mixnode (when originally using locked tokens)
UndelegateVesting(vesting_undelegate_from_mixnode::Args),
/// Migrate the delegation to use liquid tokens
MigrateVestedDelegation(migrate_vested_delegation::Args),
}
@@ -96,7 +96,6 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
mix_id,
amount,
proxy,
..
} => {
if owner.as_str() == client.nyxd.address().as_ref() {
table.add_row(vec![
@@ -112,7 +111,6 @@ async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &Signin
owner,
mix_id,
proxy,
..
} => {
if owner.as_str() == client.nyxd.address().as_ref() {
table.add_row(vec![
@@ -8,7 +8,7 @@ use cosmwasm_std::Coin;
use nym_bin_common::output_format::OutputFormat;
use nym_mixnet_contract_common::construct_gateway_bonding_sign_payload;
use nym_network_defaults::{DEFAULT_CLIENT_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT};
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
#[derive(Debug, Parser)]
pub struct Args {
@@ -39,6 +39,10 @@ pub struct Args {
)]
pub amount: u128,
/// Indicates whether the gateway is going to get bonded via a vesting account
#[arg(long)]
pub with_vesting_account: bool,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
@@ -70,8 +74,15 @@ pub async fn create_payload(args: Args, client: SigningClient) {
};
let address = account_id_to_cw_addr(&client.address());
let proxy = if args.with_vesting_account {
Some(account_id_to_cw_addr(
client.vesting_contract_address().unwrap(),
))
} else {
None
};
let payload = construct_gateway_bonding_sign_payload(nonce, address, coin, gateway);
let payload = construct_gateway_bonding_sign_payload(nonce, address, proxy, coin, gateway);
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
println!("{}", args.output.format(&wrapper))
}
@@ -5,21 +5,33 @@ use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// Label that is going to be used for creating the family
#[arg(long)]
pub family_label: String,
/// Indicates whether the family is going to get created via a vesting account
#[arg(long)]
pub with_vesting_account: bool,
}
pub async fn create_family(args: Args, client: SigningClient) {
info!("Create family");
let res = client
.create_family(args.family_label, None)
.await
.expect("failed to create family");
let res = if args.with_vesting_account {
client
.vesting_create_family(args.family_label, None)
.await
.expect("failed to create family with vesting account")
} else {
client
.create_family(args.family_label, None)
.await
.expect("failed to create family")
};
info!("Family creation result: {:?}", res);
}
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use crate::context::QueryClient;
use crate::utils::DataWrapper;
use crate::utils::{account_id_to_cw_addr, DataWrapper};
use clap::Parser;
use cosmrs::AccountId;
use log::info;
@@ -10,7 +10,7 @@ use nym_bin_common::output_format::OutputFormat;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::construct_family_join_permit;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
#[derive(Debug, Parser)]
pub struct Args {
@@ -18,6 +18,10 @@ pub struct Args {
#[arg(long)]
pub address: AccountId,
/// Indicates whether the member joining the family is going to use the vesting account for joining.
#[arg(long)]
pub with_vesting_account: bool,
// might as well validate the value when parsing the arguments
/// Identity of the member for whom we're issuing the permit
#[arg(long)]
@@ -64,9 +68,18 @@ pub async fn create_family_join_permit_sign_payload(args: Args, client: QueryCli
}
};
// let address = account_id_to_cw_addr(&args.address);
let proxy = if args.with_vesting_account {
Some(account_id_to_cw_addr(
client.vesting_contract_address().unwrap(),
))
} else {
None
};
let head = FamilyHead::new(mixnode.bond_information.identity());
let payload = construct_family_join_permit(nonce, head, args.member.to_base58_string());
let payload = construct_family_join_permit(nonce, head, proxy, args.member.to_base58_string());
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
println!("{}", args.output.format(&wrapper))
}
@@ -8,6 +8,7 @@ use nym_contracts_common::signing::MessageSignature;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
@@ -15,6 +16,10 @@ pub struct Args {
#[arg(long)]
pub family_head: identity::PublicKey,
/// Indicates whether the member joining the family is going to do so via the vesting contract
#[arg(long)]
pub with_vesting_account: bool,
/// Permission, as provided by the family head, for joining the family
#[arg(long)]
pub join_permit: MessageSignature,
@@ -25,10 +30,17 @@ pub async fn join_family(args: Args, client: SigningClient) {
let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = client
.join_family(args.join_permit, family_head, None)
.await
.expect("failed to join family");
let res = if args.with_vesting_account {
client
.vesting_join_family(args.join_permit, family_head, None)
.await
.expect("failed to join family with vesting account")
} else {
client
.join_family(args.join_permit, family_head, None)
.await
.expect("failed to join family")
};
info!("Family join result: {:?}", res);
}
@@ -7,12 +7,17 @@ use log::info;
use nym_crypto::asymmetric::identity;
use nym_mixnet_contract_common::families::FamilyHead;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
use nym_validator_client::nyxd::contract_traits::VestingSigningClient;
#[derive(Debug, Parser)]
pub struct Args {
/// The head of the family that we intend to leave
#[arg(long)]
pub family_head: identity::PublicKey,
/// Indicates whether we joined the family via the vesting contract
#[arg(long)]
pub with_vesting_account: bool,
}
pub async fn leave_family(args: Args, client: SigningClient) {
@@ -20,10 +25,17 @@ pub async fn leave_family(args: Args, client: SigningClient) {
let family_head = FamilyHead::new(args.family_head.to_base58_string());
let res = client
.leave_family(family_head, None)
.await
.expect("failed to leave family");
let res = if args.with_vesting_account {
client
.vesting_leave_family(family_head, None)
.await
.expect("failed to leave family with vesting account")
} else {
client
.leave_family(family_head, None)
.await
.expect("failed to leave family")
};
info!("Family leave result: {:?}", res);
}
@@ -1,19 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::context::SigningClient;
use clap::Parser;
use log::info;
use nym_validator_client::nyxd::contract_traits::MixnetSigningClient;
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn migrate_vested_mixnode(_args: Args, client: SigningClient) {
let res = client
.migrate_vested_mixnode(None)
.await
.expect("failed to migrate mixnode!");
info!("migration result: {:?}", res)
}
@@ -11,7 +11,7 @@ use nym_mixnet_contract_common::{construct_mixnode_bonding_sign_payload, MixNode
use nym_network_defaults::{
DEFAULT_HTTP_API_LISTENING_PORT, DEFAULT_MIX_LISTENING_PORT, DEFAULT_VERLOC_LISTENING_PORT,
};
use nym_validator_client::nyxd::contract_traits::MixnetQueryClient;
use nym_validator_client::nyxd::contract_traits::{MixnetQueryClient, NymContractsProvider};
use nym_validator_client::nyxd::CosmWasmCoin;
#[derive(Debug, Parser)]
@@ -52,6 +52,10 @@ pub struct Args {
)]
pub amount: u128,
/// Indicates whether the mixnode is going to get bonded via a vesting account
#[arg(long)]
pub with_vesting_account: bool,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
@@ -96,9 +100,16 @@ pub async fn create_payload(args: Args, client: SigningClient) {
};
let address = account_id_to_cw_addr(&client.address());
let proxy = if args.with_vesting_account {
Some(account_id_to_cw_addr(
client.vesting_contract_address().unwrap(),
))
} else {
None
};
let payload =
construct_mixnode_bonding_sign_payload(nonce, address, coin, mixnode, cost_params);
construct_mixnode_bonding_sign_payload(nonce, address, proxy, coin, mixnode, cost_params);
let wrapper = DataWrapper::new(payload.to_base58_string().unwrap());
println!("{}", args.output.format(&wrapper))
}
@@ -7,7 +7,6 @@ pub mod bond_mixnode;
pub mod decrease_pledge;
pub mod families;
pub mod keys;
pub mod migrate_vested_mixnode;
pub mod mixnode_bonding_sign_payload;
pub mod pledge_more;
pub mod rewards;
@@ -53,6 +52,4 @@ pub enum MixnetOperatorsMixnodeCommands {
DecreasePledge(decrease_pledge::Args),
/// Decrease pledge with locked tokens
DecreasePledgeVesting(vesting_decrease_pledge::Args),
/// Migrate the mixnode to use liquid tokens
MigrateVestedNode(migrate_vested_mixnode::Args),
}
@@ -218,6 +218,7 @@ where
#[derive(Serialize)]
pub struct ContractMessageContent<T> {
pub sender: Addr,
pub proxy: Option<Addr>,
pub funds: Vec<Coin>,
pub data: T,
}
@@ -232,17 +233,25 @@ where
}
impl<T> ContractMessageContent<T> {
pub fn new(sender: Addr, funds: Vec<Coin>, data: T) -> Self {
pub fn new(sender: Addr, proxy: Option<Addr>, funds: Vec<Coin>, data: T) -> Self {
ContractMessageContent {
sender,
proxy,
funds,
data,
}
}
pub fn new_with_info(info: MessageInfo, signer: Addr, data: T) -> Self {
let proxy = if info.sender == signer {
None
} else {
Some(info.sender)
};
ContractMessageContent {
sender: signer,
proxy,
funds: info.funds,
data,
}
@@ -7,5 +7,6 @@ use cosmwasm_std::Coin;
#[cw_serde]
pub struct PoolCounters {
pub total_deposited: Coin,
pub total_redeemed: Coin,
pub total_redeemed_gateways: Coin,
pub total_redeemed_holding: Coin,
}
@@ -65,6 +65,7 @@ impl Delegation {
cumulative_reward_ratio: Decimal,
amount: Coin,
height: u64,
proxy: Option<Addr>,
) -> Self {
assert!(
amount.amount <= TOKEN_SUPPLY,
@@ -77,7 +78,7 @@ impl Delegation {
cumulative_reward_ratio,
amount,
height,
proxy: None,
proxy,
}
}
@@ -1,9 +1,8 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{EpochEventId, EpochState, IdentityKey, MixId, OperatingCostRange, ProfitMarginRange};
use crate::{EpochEventId, EpochState, IdentityKey, MixId};
use contracts_common::signing::verifier::ApiVerifierError;
use contracts_common::Percent;
use cosmwasm_std::{Addr, Coin, Decimal, Uint128};
use thiserror::Error;
@@ -77,11 +76,21 @@ pub enum MixnetContractError {
#[error("Received multiple coin types during staking")]
MultipleDenoms,
#[error("Proxy address mismatch, expected {existing}, got {incoming}")]
ProxyMismatch { existing: String, incoming: String },
#[error("Proxy address ({received}) is not set to the vesting contract ({vesting_contract})")]
ProxyIsNotVestingContract {
received: Addr,
vesting_contract: Addr,
},
#[error(
"Sender of this message ({received}) is not the vesting contract ({vesting_contract})"
)]
SenderIsNotVestingContract {
received: Addr,
vesting_contract: Addr,
},
#[error("Failed to recover ed25519 public key from its base58 representation - {0}")]
MalformedEd25519IdentityKey(String),
@@ -230,30 +239,6 @@ pub enum MixnetContractError {
#[from]
source: ApiVerifierError,
},
#[error("this operation is no longer allowed to be performed with vesting tokens. please move them to your liquid balance and try again")]
DisabledVestingOperation,
#[error(
"this mixnode has not been bonded with the vesting tokens or has already been migrated"
)]
NotAVestingMixnode,
#[error("this delegation has not been performed with the vesting tokens or has already been migrated")]
NotAVestingDelegation,
#[error("the provided profit margin ({provided}) is outside the allowed range: {range}")]
ProfitMarginOutsideRange {
provided: Percent,
range: ProfitMarginRange,
},
#[error("the provided interval operating cost ({provided}{denom}) is outside the allowed range: {range}")]
OperatingCostOutsideRange {
denom: String,
provided: Uint128,
range: OperatingCostRange,
},
}
impl MixnetContractError {
@@ -103,6 +103,7 @@ impl Display for MixnetEventType {
// attributes that are used in multiple places
pub const OWNER_KEY: &str = "owner";
pub const AMOUNT_KEY: &str = "amount";
pub const PROXY_KEY: &str = "proxy";
// event-specific attributes
@@ -162,6 +163,7 @@ pub const NEW_EPOCHS_IN_INTERVAL: &str = "new_epochs_in_interval";
pub fn new_delegation_event(
created_at: BlockHeight,
delegator: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
mix_id: MixId,
unit_reward: Decimal,
@@ -169,34 +171,58 @@ pub fn new_delegation_event(
Event::new(MixnetEventType::Delegation)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(DELEGATOR_KEY, delegator)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
.add_attribute(UNIT_REWARD_KEY, unit_reward.to_string())
}
pub fn new_delegation_on_unbonded_node_event(delegator: &Addr, mix_id: MixId) -> Event {
pub fn new_delegation_on_unbonded_node_event(
delegator: &Addr,
proxy: &Option<Addr>,
mix_id: MixId,
) -> Event {
Event::new(MixnetEventType::Delegation)
.add_attribute(DELEGATOR_KEY, delegator)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
}
pub fn new_pending_delegation_event(delegator: &Addr, amount: &Coin, mix_id: MixId) -> Event {
pub fn new_pending_delegation_event(
delegator: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
mix_id: MixId,
) -> Event {
Event::new(MixnetEventType::PendingDelegation)
.add_attribute(DELEGATOR_KEY, delegator)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
}
pub fn new_withdraw_operator_reward_event(owner: &Addr, amount: Coin, mix_id: MixId) -> Event {
pub fn new_withdraw_operator_reward_event(
owner: &Addr,
proxy: &Option<Addr>,
amount: Coin,
mix_id: MixId,
) -> Event {
Event::new(MixnetEventType::WithdrawOperatorReward)
.add_attribute(OWNER_KEY, owner.as_str())
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
}
pub fn new_withdraw_delegator_reward_event(delegator: &Addr, amount: Coin, mix_id: MixId) -> Event {
pub fn new_withdraw_delegator_reward_event(
delegator: &Addr,
proxy: &Option<Addr>,
amount: Coin,
mix_id: MixId,
) -> Event {
Event::new(MixnetEventType::WithdrawDelegatorReward)
.add_attribute(DELEGATOR_KEY, delegator)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(AMOUNT_KEY, amount.to_string())
.add_attribute(DELEGATION_TARGET_KEY, mix_id.to_string())
}
@@ -252,43 +278,59 @@ pub fn new_pending_rewarding_params_update_event(
)
}
pub fn new_undelegation_event(created_at: BlockHeight, delegator: &Addr, mix_id: MixId) -> Event {
pub fn new_undelegation_event(
created_at: BlockHeight,
delegator: &Addr,
proxy: &Option<Addr>,
mix_id: MixId,
) -> Event {
Event::new(MixnetEventType::Undelegation)
.add_attribute(EVENT_CREATION_HEIGHT_KEY, created_at.to_string())
.add_attribute(DELEGATOR_KEY, delegator)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
}
pub fn new_pending_undelegation_event(delegator: &Addr, mix_id: MixId) -> Event {
pub fn new_pending_undelegation_event(
delegator: &Addr,
proxy: &Option<Addr>,
mix_id: MixId,
) -> Event {
Event::new(MixnetEventType::PendingUndelegation)
.add_attribute(DELEGATOR_KEY, delegator)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(MIX_ID_KEY, mix_id.to_string())
}
pub fn new_gateway_bonding_event(
owner: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
identity: IdentityKeyRef<'_>,
) -> Event {
Event::new(MixnetEventType::GatewayBonding)
.add_attribute(OWNER_KEY, owner)
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_gateway_unbonding_event(
owner: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
identity: IdentityKeyRef<'_>,
) -> Event {
Event::new(MixnetEventType::GatewayUnbonding)
.add_attribute(OWNER_KEY, owner)
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(AMOUNT_KEY, amount.to_string())
}
pub fn new_mixnode_bonding_event(
owner: &Addr,
proxy: &Option<Addr>,
amount: &Coin,
identity: IdentityKeyRef<'_>,
mix_id: MixId,
@@ -299,6 +341,7 @@ pub fn new_mixnode_bonding_event(
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(OWNER_KEY, owner)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(ASSIGNED_LAYER_KEY, assigned_layer)
.add_attribute(AMOUNT_KEY, amount.to_string())
}
@@ -337,6 +380,7 @@ pub fn new_mixnode_unbonding_event(created_at: BlockHeight, mix_id: MixId) -> Ev
pub fn new_pending_mixnode_unbonding_event(
owner: &Addr,
proxy: &Option<Addr>,
identity: IdentityKeyRef<'_>,
mix_id: MixId,
) -> Event {
@@ -344,33 +388,43 @@ pub fn new_pending_mixnode_unbonding_event(
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(NODE_IDENTITY_KEY, identity)
.add_attribute(OWNER_KEY, owner)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
}
pub fn new_mixnode_config_update_event(
mix_id: MixId,
owner: &Addr,
proxy: &Option<Addr>,
update: &MixNodeConfigUpdate,
) -> Event {
Event::new(MixnetEventType::MixnodeConfigUpdate)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(OWNER_KEY, owner)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(UPDATED_MIXNODE_CONFIG_KEY, update.to_inline_json())
}
pub fn new_gateway_config_update_event(owner: &Addr, update: &GatewayConfigUpdate) -> Event {
pub fn new_gateway_config_update_event(
owner: &Addr,
proxy: &Option<Addr>,
update: &GatewayConfigUpdate,
) -> Event {
Event::new(MixnetEventType::GatewayConfigUpdate)
.add_attribute(OWNER_KEY, owner)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(UPDATED_GATEWAY_CONFIG_KEY, update.to_inline_json())
}
pub fn new_mixnode_pending_cost_params_update_event(
mix_id: MixId,
owner: &Addr,
proxy: &Option<Addr>,
new_costs: &MixNodeCostParams,
) -> Event {
Event::new(MixnetEventType::PendingMixnodeCostParamsUpdate)
.add_attribute(MIX_ID_KEY, mix_id.to_string())
.add_attribute(OWNER_KEY, owner)
.add_optional_attribute(PROXY_KEY, proxy.as_ref())
.add_attribute(UPDATED_MIXNODE_COST_PARAMS_KEY, new_costs.to_inline_json())
}
@@ -3,6 +3,7 @@
use crate::{IdentityKey, IdentityKeyRef};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
use schemars::JsonSchema;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{Display, Formatter};
@@ -83,10 +84,10 @@ impl FamilyHead {
}
impl Family {
pub fn new(head: FamilyHead, label: String) -> Self {
pub fn new(head: FamilyHead, proxy: Option<Addr>, label: String) -> Self {
Family {
head,
proxy: None,
proxy: proxy.map(|p| p.to_string()),
label,
}
}
@@ -55,13 +55,19 @@ pub struct GatewayBond {
}
impl GatewayBond {
pub fn new(pledge_amount: Coin, owner: Addr, block_height: u64, gateway: Gateway) -> Self {
pub fn new(
pledge_amount: Coin,
owner: Addr,
block_height: u64,
gateway: Gateway,
proxy: Option<Addr>,
) -> Self {
GatewayBond {
pledge_amount,
owner,
block_height,
gateway,
proxy: None,
proxy,
}
}
@@ -10,10 +10,7 @@ use crate::helpers::IntoBaseDecimal;
use crate::reward_params::{NodeRewardParams, RewardingParams};
use crate::rewarding::helpers::truncate_reward;
use crate::rewarding::RewardDistribution;
use crate::{
Delegation, EpochEventId, EpochId, IdentityKey, MixId, OperatingCostRange, Percent,
ProfitMarginRange, SphinxKey,
};
use crate::{Delegation, EpochEventId, EpochId, IdentityKey, MixId, Percent, SphinxKey};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Coin, Decimal, StdResult, Uint128};
use schemars::JsonSchema;
@@ -155,16 +152,6 @@ impl MixNodeRewarding {
})
}
pub fn normalise_profit_margin(&mut self, allowed_range: ProfitMarginRange) {
self.cost_params.profit_margin_percent =
allowed_range.normalise(self.cost_params.profit_margin_percent)
}
pub fn normalise_operating_cost(&mut self, allowed_range: OperatingCostRange) {
self.cost_params.interval_operating_cost.amount =
allowed_range.normalise(self.cost_params.interval_operating_cost.amount)
}
/// Determines whether this node is still bonded. This is performed via a simple check,
/// if there are no tokens left associated with the operator, it means they have unbonded
/// and those params only exist for the purposes of calculating rewards for delegators that
@@ -531,6 +518,7 @@ impl MixNodeBond {
original_pledge: Coin,
layer: Layer,
mix_node: MixNode,
proxy: Option<Addr>,
bonding_height: u64,
) -> Self {
MixNodeBond {
@@ -539,7 +527,7 @@ impl MixNodeBond {
original_pledge,
layer,
mix_node,
proxy: None,
proxy,
bonding_height,
is_unbonding: false,
}
@@ -1,4 +1,4 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::delegation::{self, OwnerProxySubKey};
@@ -12,7 +12,6 @@ use crate::reward_params::{
IntervalRewardParams, IntervalRewardingParamsUpdate, Performance, RewardingParams,
};
use crate::types::{ContractStateParams, LayerAssignment, MixId};
use crate::{OperatingCostRange, ProfitMarginRange};
use contracts_common::{signing::MessageSignature, IdentityKey, Percent};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Coin, Decimal};
@@ -58,12 +57,6 @@ pub struct InstantiateMsg {
pub epochs_in_interval: u32,
pub epoch_duration: Duration,
pub initial_rewarding_params: InitialRewardingParams,
#[serde(default)]
pub profit_margin: ProfitMarginRange,
#[serde(default)]
pub interval_operating_cost: OperatingCostRange,
}
#[cw_serde]
@@ -276,12 +269,6 @@ pub enum ExecuteMsg {
owner: String,
},
// vesting migration:
MigrateVestedMixNode {},
MigrateVestedDelegation {
mix_id: MixId,
},
// testing-only
#[cfg(feature = "contract-testing")]
TestingResolveAllPendingEvents {
@@ -394,9 +381,6 @@ impl ExecuteMsg {
ExecuteMsg::WithdrawDelegatorRewardOnBehalf { mix_id, .. } => {
format!("withdrawing delegator reward from mixnode {mix_id} on behalf")
}
ExecuteMsg::MigrateVestedMixNode { .. } => "migrate vested mixnode".into(),
ExecuteMsg::MigrateVestedDelegation { .. } => "migrate vested delegation".to_string(),
#[cfg(feature = "contract-testing")]
ExecuteMsg::TestingResolveAllPendingEvents { .. } => {
"resolving all pending events".into()
@@ -38,7 +38,6 @@ pub enum PendingEpochEventKind {
/// Request to create a delegation towards particular mixnode.
/// Note that if such delegation already exists, it will get updated with the provided token amount.
#[serde(alias = "Delegate")]
#[non_exhaustive]
Delegate {
/// The address of the owner of the delegation.
owner: Addr,
@@ -56,7 +55,6 @@ pub enum PendingEpochEventKind {
/// Request to remove delegation from particular mixnode.
#[serde(alias = "Undelegate")]
#[non_exhaustive]
Undelegate {
/// The address of the owner of the delegation.
owner: Addr,
@@ -111,23 +109,6 @@ impl PendingEpochEventKind {
kind: self,
}
}
pub fn new_delegate(owner: Addr, mix_id: MixId, amount: Coin) -> Self {
PendingEpochEventKind::Delegate {
owner,
mix_id,
amount,
proxy: None,
}
}
pub fn new_undelegate(owner: Addr, mix_id: MixId) -> Self {
PendingEpochEventKind::Undelegate {
owner,
mix_id,
proxy: None,
}
}
}
impl From<(EpochEventId, PendingEpochEventData)> for PendingEpochEvent {
@@ -47,6 +47,7 @@ impl SimulatedNode {
self.rewarding_details.total_unit_reward,
delegation,
42,
None,
);
self.delegations.insert(delegator, delegation);
@@ -37,12 +37,13 @@ impl SigningPurpose for MixnodeBondingPayload {
pub fn construct_mixnode_bonding_sign_payload(
nonce: Nonce,
sender: Addr,
proxy: Option<Addr>,
pledge: Coin,
mix_node: MixNode,
cost_params: MixNodeCostParams,
) -> SignableMixNodeBondingMsg {
let payload = MixnodeBondingPayload::new(mix_node, cost_params);
let content = ContractMessageContent::new(sender, vec![pledge], payload);
let content = ContractMessageContent::new(sender, proxy, vec![pledge], payload);
SignableMessage::new(nonce, content)
}
@@ -67,11 +68,12 @@ impl SigningPurpose for GatewayBondingPayload {
pub fn construct_gateway_bonding_sign_payload(
nonce: Nonce,
sender: Addr,
proxy: Option<Addr>,
pledge: Coin,
gateway: Gateway,
) -> SignableGatewayBondingMsg {
let payload = GatewayBondingPayload::new(gateway);
let content = ContractMessageContent::new(sender, vec![pledge], payload);
let content = ContractMessageContent::new(sender, proxy, vec![pledge], payload);
SignableMessage::new(nonce, content)
}
@@ -80,14 +82,17 @@ pub fn construct_gateway_bonding_sign_payload(
pub struct FamilyJoinPermit {
// the granter of this permit
family_head: FamilyHead,
// whether the **member** will want to join via the proxy (i.e. vesting contract)
proxy: Option<Addr>,
// the actual member we want to permit to join
member_node: IdentityKey,
}
impl FamilyJoinPermit {
pub fn new(family_head: FamilyHead, member_node: IdentityKey) -> Self {
pub fn new(family_head: FamilyHead, proxy: Option<Addr>, member_node: IdentityKey) -> Self {
Self {
family_head,
proxy,
member_node,
}
}
@@ -102,9 +107,10 @@ impl SigningPurpose for FamilyJoinPermit {
pub fn construct_family_join_permit(
nonce: Nonce,
family_head: FamilyHead,
proxy: Option<Addr>,
member_node: IdentityKey,
) -> SignableFamilyJoinPermitMsg {
let payload = FamilyJoinPermit::new(family_head, member_node);
let payload = FamilyJoinPermit::new(family_head, proxy, member_node);
// note: we're NOT wrapping it in `ContractMessageContent` because the family head is not going to be the one
// sending the message to the contract
@@ -3,11 +3,9 @@
use crate::error::MixnetContractError;
use crate::Layer;
use contracts_common::Percent;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
use cosmwasm_std::Coin;
use cosmwasm_std::{Addr, Uint128};
use std::fmt::{Display, Formatter};
use std::ops::Index;
// type aliases for better reasoning about available data
@@ -17,65 +15,6 @@ pub type SphinxKeyRef<'a> = &'a str;
pub type MixId = u32;
pub type BlockHeight = u64;
#[cw_serde]
pub struct RangedValue<T> {
pub minimum: T,
pub maximum: T,
}
impl<T> Copy for RangedValue<T> where T: Copy {}
pub type ProfitMarginRange = RangedValue<Percent>;
pub type OperatingCostRange = RangedValue<Uint128>;
impl<T> Display for RangedValue<T>
where
T: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} - {}", self.minimum, self.maximum)
}
}
impl Default for ProfitMarginRange {
fn default() -> Self {
ProfitMarginRange {
minimum: Percent::zero(),
maximum: Percent::hundred(),
}
}
}
impl Default for OperatingCostRange {
fn default() -> Self {
OperatingCostRange {
minimum: Uint128::zero(),
// 1 billion (native tokens, i.e. 1 billion * 1'000'000 base tokens) - the total supply
maximum: Uint128::new(1_000_000_000_000_000),
}
}
}
impl<T> RangedValue<T>
where
T: Copy + PartialOrd + PartialEq,
{
pub fn normalise(&self, value: T) -> T {
if value < self.minimum {
self.minimum
} else if value > self.maximum {
self.maximum
} else {
value
}
}
pub fn within_range(&self, value: T) -> bool {
value >= self.minimum && value <= self.maximum
}
}
/// Specifies layer assignment for the given mixnode.
#[cw_serde]
pub struct LayerAssignment {
@@ -215,14 +154,4 @@ pub struct ContractStateParams {
/// Minimum amount a gateway must pledge to get into the system.
pub minimum_gateway_pledge: Coin,
/// Defines the allowed profit margin range of operators.
/// default: 0% - 100%
#[serde(default)]
pub profit_margin: ProfitMarginRange,
/// Defines the allowed interval operating cost range of operators.
/// default: 0 - 1'000'000'000'000'000 (1 Billion native tokens - the total supply)
#[serde(default)]
pub interval_operating_cost: OperatingCostRange,
}
@@ -167,11 +167,3 @@ pub fn new_track_undelegation_event() -> Event {
pub fn new_track_reward_event() -> Event {
Event::new(TRACK_REWARD_EVENT_TYPE)
}
pub fn new_track_migrate_mixnode_event() -> Event {
Event::new("track_migrate_vesting_mixnode")
}
pub fn new_track_migrate_delegation_event() -> Event {
Event::new("track_migrate_vesting_delegation")
}
@@ -136,14 +136,6 @@ pub enum ExecuteMsg {
address: String,
cap: PledgeCap,
},
TrackMigratedMixnode {
owner: String,
},
// no need to track migrated gateways as there are no vesting gateways on mainnet
TrackMigratedDelegation {
owner: String,
mix_id: MixId,
},
}
impl ExecuteMsg {
@@ -179,10 +171,6 @@ impl ExecuteMsg {
ExecuteMsg::TransferOwnership { .. } => "VestingExecuteMsg::TransferOwnership",
ExecuteMsg::UpdateStakingAddress { .. } => "VestingExecuteMsg::UpdateStakingAddress",
ExecuteMsg::UpdateLockedPledgeCap { .. } => "VestingExecuteMsg::UpdateLockedPledgeCap",
ExecuteMsg::TrackMigratedMixnode { .. } => "VestingExecuteMsg::TrackMigratedMixnode",
ExecuteMsg::TrackMigratedDelegation { .. } => {
"VestingExecuteMsg::TrackMigratedDelegation"
}
}
}
}
@@ -35,9 +35,6 @@ CREATE TABLE ecash_ticketbook
-- introduce a way for us to introduce breaking changes in serialization of data
serialization_revision INTEGER NOT NULL,
-- the type of the associated ticketbook
ticketbook_type TEXT NOT NULL,
-- the actual crypto data of the ticketbook (wallet, keys, etc.)
ticketbook_data BLOB NOT NULL UNIQUE,
@@ -175,7 +175,6 @@ impl MemoryEcachTicketbookManager {
.map(|t| BasicTicketbookInformation {
id: t.ticketbook_id,
expiration_date: t.ticketbook.expiration_date(),
ticketbook_type: t.ticketbook.ticketbook_type().to_string(),
epoch_id: t.ticketbook.epoch_id() as u32,
total_tickets: t.ticketbook.spent_tickets() as u32,
used_tickets: t.ticketbook.params_total_tickets() as u32,
@@ -61,13 +61,11 @@ impl SqliteEcashTicketbookManager {
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub(crate) async fn insert_new_ticketbook(
&self,
serialisation_revision: u8,
data: &[u8],
expiration_date: Date,
typ: &str,
epoch_id: u32,
total_tickets: u32,
used_tickets: u32,
@@ -75,13 +73,12 @@ impl SqliteEcashTicketbookManager {
sqlx::query!(
r#"
INSERT INTO ecash_ticketbook
(serialization_revision, ticketbook_data, expiration_date, ticketbook_type, epoch_id, total_tickets, used_tickets)
VALUES (?, ?, ?, ?, ?, ?, ?)
(serialization_revision, ticketbook_data, expiration_date, epoch_id, total_tickets, used_tickets)
VALUES (?, ?, ?, ?, ?, ?)
"#,
serialisation_revision,
data,
expiration_date,
typ,
epoch_id,
total_tickets,
used_tickets,
@@ -95,7 +92,7 @@ impl SqliteEcashTicketbookManager {
) -> Result<Vec<BasicTicketbookInformation>, sqlx::Error> {
sqlx::query_as(
r#"
SELECT id, expiration_date, ticketbook_type, epoch_id, total_tickets, used_tickets
SELECT id, expiration_date, epoch_id, total_tickets, used_tickets
FROM ecash_ticketbook
"#,
)
-3
View File
@@ -19,7 +19,6 @@ pub struct RetrievedPendingTicketbook {
pub struct BasicTicketbookInformation {
pub id: i64,
pub expiration_date: Date,
pub ticketbook_type: String,
pub epoch_id: u32,
pub total_tickets: u32,
pub used_tickets: u32,
@@ -32,8 +31,6 @@ pub struct StoredIssuedTicketbook {
pub serialization_revision: u8,
pub ticketbook_type: String,
pub ticketbook_data: Vec<u8>,
#[zeroize(skip)]
@@ -114,7 +114,6 @@ impl Storage for PersistentStorage {
serialisation_revision,
&data,
ticketbook.expiration_date(),
&ticketbook.ticketbook_type().to_string(),
ticketbook.epoch_id() as u32,
ticketbook.params_total_tickets() as u32,
ticketbook.spent_tickets() as u32,
+1 -1
View File
@@ -14,9 +14,9 @@ time.workspace = true
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
nym-credentials = { path = "../../common/credentials" }
nym-credentials-interface = { path = "../../common/credentials-interface" }
nym-credential-storage = { path = "../../common/credential-storage", features = ["persistent-storage"] }
nym-validator-client = { path = "../../common/client-libs/validator-client" }
nym-config = { path = "../../common/config" }
nym-client-core = { path = "../../common/client-core" }
nym-compact-ecash = { path = "../../common/nym_offline_compact_ecash" }
nym-ecash-time = { path = "../../common/ecash-time" }
+2 -12
View File
@@ -1,6 +1,3 @@
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::errors::{Error, Result};
use log::*;
use nym_bandwidth_controller::acquire::{
@@ -10,7 +7,6 @@ use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_config::DEFAULT_DATA_DIR;
use nym_credential_storage::persistent_storage::PersistentStorage;
use nym_credential_storage::storage::Storage;
use nym_credentials_interface::TicketType;
use nym_ecash_time::ecash_default_expiration_date;
use nym_validator_client::coconut::all_ecash_api_clients;
use nym_validator_client::nyxd::contract_traits::{
@@ -20,12 +16,7 @@ use std::path::PathBuf;
use std::time::Duration;
use time::OffsetDateTime;
pub async fn issue_credential<C, S>(
client: &C,
storage: &S,
client_id: &[u8],
typ: TicketType,
) -> Result<()>
pub async fn issue_credential<C, S>(client: &C, storage: &S, client_id: &[u8]) -> Result<()>
where
C: DkgQueryClient + EcashSigningClient + EcashQueryClient + Send + Sync,
S: Storage,
@@ -58,7 +49,6 @@ where
client,
client_id,
Some(ticketbook_expiration),
typ,
)
.await?;
info!("Deposit done");
@@ -75,7 +65,7 @@ where
}).map_err(Error::storage_error)?
}
info!("Succeeded adding a ticketbook of type '{typ}'");
info!("Succeeded adding a ticketbook");
Ok(())
}
+1 -3
View File
@@ -14,10 +14,8 @@ license.workspace = true
bls12_381 = { workspace = true, default-features = false }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
strum = { workspace = true, features = ["derive"] }
time = { workspace = true, features = ["serde"] }
rand = { workspace = true }
nym-compact-ecash = { path = "../nym_offline_compact_ecash" }
nym-ecash-time = { path = "../ecash-time" }
nym-network-defaults = { path = "../network-defaults" }
nym-ecash-time = { path = "../ecash-time" }
+5 -117
View File
@@ -1,10 +1,8 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_network_defaults::TicketTypeRepr;
use rand::Rng;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use time::{Date, OffsetDateTime};
pub use nym_compact_ecash::{
@@ -17,6 +15,7 @@ pub use nym_compact_ecash::{
PartialCoinIndexSignature,
},
scheme::expiration_date_signatures::aggregate_expiration_signatures,
scheme::expiration_date_signatures::date_scalar,
scheme::expiration_date_signatures::{
AnnotatedExpirationDateSignature, ExpirationDateSignature, ExpirationDateSignatureShare,
PartialExpirationDateSignature,
@@ -25,10 +24,10 @@ pub use nym_compact_ecash::{
scheme::withdrawal::RequestInfo,
scheme::Payment,
scheme::{Wallet, WalletSignatures},
withdrawal_request, Base58, BlindedSignature, Bytable, EncodedDate, EncodedTicketType,
PartialWallet, PayInfo, PublicKeyUser, SecretKeyUser, VerificationKeyAuth, WithdrawalRequest,
withdrawal_request, Base58, BlindedSignature, Bytable, PartialWallet, PayInfo, PublicKeyUser,
SecretKeyUser, VerificationKeyAuth, WithdrawalRequest,
};
use nym_ecash_time::{ecash_today, EcashTime};
use nym_ecash_time::EcashTime;
#[derive(Debug, Clone)]
pub struct CredentialSigningData {
@@ -39,8 +38,6 @@ pub struct CredentialSigningData {
pub ecash_pub_key: PublicKeyUser,
pub expiration_date: Date,
pub ticketbook_type: TicketType,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
@@ -61,7 +58,7 @@ impl CredentialSpendingData {
self.payment.spend_verify(
verification_key,
&self.pay_info,
self.spend_date.ecash_unix_timestamp(),
date_scalar(self.spend_date.ecash_unix_timestamp()),
)
}
@@ -219,112 +216,3 @@ impl From<PayInfo> for NymPayInfo {
}
}
}
#[derive(
Default,
Copy,
Clone,
Debug,
PartialEq,
Serialize,
Deserialize,
strum::Display,
strum::EnumString,
)]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum TicketType {
#[default]
V1MixnetEntry,
V1MixnetExit,
V1WireguardEntry,
V1WireguardExit,
}
#[derive(Debug, Copy, Clone, Error)]
#[error("provided unknown ticketbook type")]
pub struct UnknownTicketType;
impl TicketType {
pub fn to_repr(&self) -> TicketTypeRepr {
(*self).into()
}
pub fn encode(&self) -> EncodedTicketType {
self.to_repr() as EncodedTicketType
}
pub fn try_from_encoded(val: EncodedTicketType) -> Result<Self, UnknownTicketType> {
match val {
n if n == TicketTypeRepr::V1MixnetEntry as u8 => {
Ok(TicketTypeRepr::V1MixnetEntry.into())
}
n if n == TicketTypeRepr::V1MixnetExit as u8 => Ok(TicketTypeRepr::V1MixnetExit.into()),
n if n == TicketTypeRepr::V1WireguardEntry as u8 => {
Ok(TicketTypeRepr::V1WireguardEntry.into())
}
n if n == TicketTypeRepr::V1WireguardExit as u8 => {
Ok(TicketTypeRepr::V1WireguardExit.into())
}
_ => Err(UnknownTicketType),
}
}
}
impl From<TicketType> for TicketTypeRepr {
fn from(value: TicketType) -> Self {
match value {
TicketType::V1MixnetEntry => TicketTypeRepr::V1MixnetEntry,
TicketType::V1MixnetExit => TicketTypeRepr::V1MixnetExit,
TicketType::V1WireguardEntry => TicketTypeRepr::V1WireguardEntry,
TicketType::V1WireguardExit => TicketTypeRepr::V1WireguardExit,
}
}
}
impl From<TicketTypeRepr> for TicketType {
fn from(value: TicketTypeRepr) -> Self {
match value {
TicketTypeRepr::V1MixnetEntry => TicketType::V1MixnetEntry,
TicketTypeRepr::V1MixnetExit => TicketType::V1MixnetExit,
TicketTypeRepr::V1WireguardEntry => TicketType::V1WireguardEntry,
TicketTypeRepr::V1WireguardExit => TicketType::V1WireguardExit,
}
}
}
#[derive(Clone)]
pub struct ClientTicket {
pub spending_data: CredentialSpendingData,
pub ticket_id: i64,
}
impl ClientTicket {
pub fn new(spending_data: CredentialSpendingData, ticket_id: i64) -> Self {
ClientTicket {
spending_data,
ticket_id,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct AvailableBandwidth {
pub bytes: i64,
pub expiration: OffsetDateTime,
}
impl AvailableBandwidth {
pub fn expired(&self) -> bool {
self.expiration < ecash_today()
}
}
impl Default for AvailableBandwidth {
fn default() -> Self {
Self {
bytes: 0,
expiration: OffsetDateTime::UNIX_EPOCH,
}
}
}
@@ -2,15 +2,14 @@
// SPDX-License-Identifier: Apache-2.0
use crate::ecash::bandwidth::issued::IssuedTicketBook;
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
use crate::ecash::bandwidth::CredentialSigningData;
use crate::ecash::utils::cred_exp_date;
use crate::error::Error;
use nym_api_requests::ecash::BlindSignRequestBody;
use nym_credentials_interface::{
aggregate_wallets, generate_keypair_user_from_seed, issue_verify, withdrawal_request,
BlindedSignature, KeyPairUser, PartialWallet, TicketType, VerificationKeyAuth,
WalletSignatures, WithdrawalRequest,
BlindedSignature, KeyPairUser, PartialWallet, VerificationKeyAuth, WalletSignatures,
WithdrawalRequest,
};
use nym_crypto::asymmetric::identity;
use nym_ecash_contract_common::deposit::DepositId;
@@ -19,6 +18,7 @@ use nym_validator_client::nym_api::EpochId;
use serde::{Deserialize, Serialize};
use time::Date;
use crate::ecash::bandwidth::serialiser::VersionedSerialise;
pub use nym_validator_client::nyxd::{Coin, Hash};
#[derive(Serialize, Deserialize)]
@@ -32,9 +32,6 @@ pub struct IssuanceTicketBook {
/// ecash keypair related to the credential
ecash_keypair: KeyPairUser,
/// the type of the ticketbook to be issued
ticketbook_type: TicketType,
/// expiration_date of that credential
expiration_date: Date,
}
@@ -44,14 +41,12 @@ impl IssuanceTicketBook {
deposit_id: DepositId,
identifier: M,
signing_key: identity::PrivateKey,
ticketbook_type: TicketType,
) -> Self {
//this expiration date will get fed to the ecash library, force midnight to be set
Self::new_with_expiration(
deposit_id,
identifier,
signing_key,
ticketbook_type,
ecash_default_expiration_date(),
)
}
@@ -60,7 +55,6 @@ impl IssuanceTicketBook {
deposit_id: DepositId,
identifier: M,
signing_key: identity::PrivateKey,
ticketbook_type: TicketType,
expiration_date: Date,
) -> Self {
let ecash_keypair = generate_keypair_user_from_seed(identifier);
@@ -68,7 +62,6 @@ impl IssuanceTicketBook {
deposit_id,
signing_key,
ecash_keypair,
ticketbook_type,
expiration_date,
}
}
@@ -83,10 +76,6 @@ impl IssuanceTicketBook {
self.expiration_date
}
pub fn ticketbook_type(&self) -> TicketType {
self.ticketbook_type
}
pub fn request_plaintext(request: &WithdrawalRequest, deposit_id: DepositId) -> Vec<u8> {
let mut message = request.to_bytes();
message.extend_from_slice(&deposit_id.to_be_bytes());
@@ -110,7 +99,6 @@ impl IssuanceTicketBook {
request_signature,
signing_request.ecash_pub_key.clone(),
signing_request.expiration_date,
signing_request.ticketbook_type,
)
}
@@ -145,7 +133,6 @@ impl IssuanceTicketBook {
let (withdrawal_request, request_info) = withdrawal_request(
self.ecash_keypair.secret_key(),
self.expiration_date.ecash_unix_timestamp(),
self.ticketbook_type.encode(),
)
.unwrap();
@@ -154,7 +141,6 @@ impl IssuanceTicketBook {
request_info,
ecash_pub_key: self.ecash_keypair.public_key(),
expiration_date: self.expiration_date,
ticketbook_type: self.ticketbook_type,
}
}
@@ -232,7 +218,6 @@ impl IssuanceTicketBook {
wallet,
epoch_id,
self.ecash_keypair.secret_key().clone(),
self.ticketbook_type,
self.expiration_date,
)
}
@@ -6,8 +6,8 @@ use crate::ecash::bandwidth::CredentialSpendingData;
use crate::ecash::utils::ecash_today;
use crate::error::Error;
use nym_credentials_interface::{
CoinIndexSignature, ExpirationDateSignature, PayInfo, SecretKeyUser, TicketType,
VerificationKeyAuth, Wallet, WalletSignatures,
CoinIndexSignature, ExpirationDateSignature, PayInfo, SecretKeyUser, VerificationKeyAuth,
Wallet, WalletSignatures,
};
use nym_ecash_time::EcashTime;
use nym_validator_client::nym_api::EpochId;
@@ -36,10 +36,6 @@ pub struct IssuedTicketBook {
/// expiration_date for easier discarding
#[zeroize(skip)]
expiration_date: Date,
/// the type of the ticketbook to got issued
#[zeroize(skip)]
ticketbook_type: TicketType,
}
impl IssuedTicketBook {
@@ -47,7 +43,6 @@ impl IssuedTicketBook {
wallet: WalletSignatures,
epoch_id: EpochId,
ecash_secret_key: SecretKeyUser,
ticketbook_type: TicketType,
expiration_date: Date,
) -> Self {
IssuedTicketBook {
@@ -56,7 +51,6 @@ impl IssuedTicketBook {
epoch_id,
ecash_secret_key,
expiration_date,
ticketbook_type,
}
}
@@ -64,7 +58,6 @@ impl IssuedTicketBook {
signatures_wallet: WalletSignatures,
epoch_id: EpochId,
ecash_secret_key: SecretKeyUser,
ticketbook_type: TicketType,
expiration_date: Date,
spent_tickets: u64,
) -> Self {
@@ -74,7 +67,6 @@ impl IssuedTicketBook {
epoch_id,
ecash_secret_key,
expiration_date,
ticketbook_type,
}
}
@@ -86,10 +78,6 @@ impl IssuedTicketBook {
self.epoch_id
}
pub fn ticketbook_type(&self) -> TicketType {
self.ticketbook_type
}
pub fn current_serialization_revision(&self) -> u8 {
CURRENT_SERIALIZATION_REVISION
}
+17 -1
View File
@@ -36,6 +36,22 @@ pub fn aggregate_verification_keys(
)?)
}
pub fn obtain_aggregated_verification_key(
_api_clients: &[EcashApiClient],
) -> Result<VerificationKeyAuth, Error> {
// TODO:
// let total = api_clients.len();
// let mut rng = thread_rng();
// let indices = sample(&mut rng, total, total);
// for index in indices {
// // randomly try apis until we succeed
// // if let Ok(res) = api_clients[index].api_client.get_aggregated_verification_key().await {
// // //
// // }
// }
todo!()
}
pub async fn obtain_expiration_date_signatures(
ecash_api_clients: &[EcashApiClient],
verification_key: &VerificationKeyAuth,
@@ -47,7 +63,7 @@ pub async fn obtain_expiration_date_signatures(
let mut signatures_shares: Vec<_> = Vec::with_capacity(ecash_api_clients.len());
let expiration_date = cred_exp_date().ecash_unix_timestamp();
let expiration_date = cred_exp_date().unix_timestamp() as u64;
for ecash_api_client in ecash_api_clients.iter() {
match ecash_api_client
.api_client
+2 -5
View File
@@ -6,16 +6,13 @@ use time::{Duration, PrimitiveDateTime, Time};
pub use time::{Date, OffsetDateTime};
pub trait EcashTime {
fn ecash_unix_timestamp(&self) -> u32 {
fn ecash_unix_timestamp(&self) -> u64 {
let ts = self.ecash_datetime().unix_timestamp();
// just panic on pre-1970 timestamps...
assert!(ts > 0);
// and on anything in 22nd century...
assert!(ts <= u32::MAX as i64);
ts as u32
ts as u64
}
fn ecash_date(&self) -> Date {
-41
View File
@@ -1,41 +0,0 @@
[package]
name = "nym-gateway-storage"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
async-trait = { workspace = true }
bincode = { workspace = true, optional = true }
defguard_wireguard_rs = { workspace = true, optional = true }
log = { workspace = true }
sqlx = { workspace = true, features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
"time",
] }
time = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
nym-credentials-interface = { path = "../credentials-interface" }
nym-gateway-requests = { path = "../gateway-requests" }
nym-sphinx = { path = "../nymsphinx" }
[build-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
sqlx = { workspace = true, features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
] }
[features]
wireguard = ["defguard_wireguard_rs", "bincode"]
@@ -1,18 +0,0 @@
/*
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
* SPDX-License-Identifier: Apache-2.0
*/
CREATE TABLE wireguard_peer
(
public_key TEXT NOT NULL PRIMARY KEY UNIQUE,
preshared_key TEXT,
protocol_version INTEGER,
endpoint TEXT,
last_handshake TIMESTAMP,
tx_bytes BIGINT NOT NULL,
rx_bytes BIGINT NOT NULL,
persistent_keepalive_interval INTEGER,
allowed_ips BLOB NOT NULL,
suspended BOOLEAN NOT NULL
);
-182
View File
@@ -1,182 +0,0 @@
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::error::StorageError;
use nym_credentials_interface::{AvailableBandwidth, ClientTicket, CredentialSpendingData};
use sqlx::FromRow;
use time::OffsetDateTime;
pub struct PersistedSharedKeys {
#[allow(dead_code)]
pub id: i64,
#[allow(dead_code)]
pub client_address_bs58: String,
pub derived_aes128_ctr_blake3_hmac_keys_bs58: String,
}
pub struct StoredMessage {
pub id: i64,
#[allow(dead_code)]
pub client_address_bs58: String,
pub content: Vec<u8>,
}
#[derive(Debug, Clone, FromRow)]
pub struct PersistedBandwidth {
#[allow(dead_code)]
pub client_id: i64,
pub available: i64,
pub expiration: Option<OffsetDateTime>,
}
impl From<PersistedBandwidth> for AvailableBandwidth {
fn from(value: PersistedBandwidth) -> Self {
AvailableBandwidth {
bytes: value.available,
expiration: value.expiration.unwrap_or(OffsetDateTime::UNIX_EPOCH),
}
}
}
#[derive(FromRow)]
pub struct VerifiedTicket {
pub serial_number: Vec<u8>,
pub ticket_id: i64,
}
#[derive(FromRow)]
pub struct RedemptionProposal {
pub proposal_id: i64,
pub created_at: OffsetDateTime,
}
#[derive(FromRow)]
pub struct UnverifiedTicketData {
pub data: Vec<u8>,
pub ticket_id: i64,
}
impl TryFrom<UnverifiedTicketData> for ClientTicket {
type Error = StorageError;
fn try_from(value: UnverifiedTicketData) -> Result<Self, Self::Error> {
Ok(ClientTicket {
spending_data: CredentialSpendingData::try_from_bytes(&value.data).map_err(|_| {
StorageError::MalformedStoredTicketData {
ticket_id: value.ticket_id,
}
})?,
ticket_id: value.ticket_id,
})
}
}
#[cfg(feature = "wireguard")]
#[derive(Debug, Clone, FromRow)]
pub struct WireguardPeer {
pub public_key: String,
pub preshared_key: Option<String>,
pub protocol_version: Option<i64>,
pub endpoint: Option<String>,
pub last_handshake: Option<sqlx::types::chrono::NaiveDateTime>,
pub tx_bytes: i64,
pub rx_bytes: i64,
pub persistent_keepalive_interval: Option<i64>,
pub allowed_ips: Vec<u8>,
pub suspended: bool,
}
#[cfg(feature = "wireguard")]
impl From<defguard_wireguard_rs::host::Peer> for WireguardPeer {
fn from(value: defguard_wireguard_rs::host::Peer) -> Self {
WireguardPeer {
public_key: value.public_key.to_string(),
preshared_key: value.preshared_key.as_ref().map(|k| k.to_string()),
protocol_version: value.protocol_version.map(|v| v as i64),
endpoint: value.endpoint.map(|e| e.to_string()),
last_handshake: value.last_handshake.and_then(|t| {
if let Ok(d) = t.duration_since(std::time::UNIX_EPOCH) {
if let Ok(millis) = d.as_millis().try_into() {
sqlx::types::chrono::DateTime::from_timestamp_millis(millis)
.map(|d| d.naive_utc())
} else {
None
}
} else {
None
}
}),
tx_bytes: value.tx_bytes as i64,
rx_bytes: value.rx_bytes as i64,
persistent_keepalive_interval: value.persistent_keepalive_interval.map(|v| v as i64),
allowed_ips: bincode::Options::serialize(
bincode::DefaultOptions::new(),
&value.allowed_ips,
)
.unwrap_or_default(),
suspended: false,
}
}
}
#[cfg(feature = "wireguard")]
impl TryFrom<WireguardPeer> for defguard_wireguard_rs::host::Peer {
type Error = crate::error::StorageError;
fn try_from(value: WireguardPeer) -> Result<Self, Self::Error> {
Ok(Self {
public_key: value
.public_key
.as_str()
.try_into()
.map_err(|e| Self::Error::TypeConversion(format!("public key {e}")))?,
preshared_key: value
.preshared_key
.as_deref()
.map(TryFrom::try_from)
.transpose()
.map_err(|e| Self::Error::TypeConversion(format!("preshared key {e}")))?,
protocol_version: value
.protocol_version
.map(TryFrom::try_from)
.transpose()
.map_err(|e| Self::Error::TypeConversion(format!("protocol version {e}")))?,
endpoint: value
.endpoint
.as_deref()
.map(|e| e.parse())
.transpose()
.map_err(|e| Self::Error::TypeConversion(format!("endpoint {e}")))?,
last_handshake: value.last_handshake.and_then(|t| {
let unix_time = std::time::UNIX_EPOCH;
if let Ok(millis) = t.and_utc().timestamp_millis().try_into() {
let duration = std::time::Duration::from_millis(millis);
unix_time.checked_add(duration)
} else {
None
}
}),
tx_bytes: value
.tx_bytes
.try_into()
.map_err(|e| Self::Error::TypeConversion(format!("tx bytes {e}")))?,
rx_bytes: value
.rx_bytes
.try_into()
.map_err(|e| Self::Error::TypeConversion(format!("rx bytes {e}")))?,
persistent_keepalive_interval: value
.persistent_keepalive_interval
.map(TryFrom::try_from)
.transpose()
.map_err(|e| {
Self::Error::TypeConversion(format!("persistent keepalive interval {e}"))
})?,
allowed_ips: bincode::Options::deserialize(
bincode::DefaultOptions::new(),
&value.allowed_ips,
)
.map_err(|e| Self::Error::TypeConversion(format!("allowed ips {e}")))?,
})
}
}
@@ -1,89 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::models::WireguardPeer;
#[derive(Clone)]
pub(crate) struct WgPeerManager {
connection_pool: sqlx::SqlitePool,
}
impl WgPeerManager {
/// Creates new instance of the `WgPeersManager` with the provided sqlite connection pool.
///
/// # Arguments
///
/// * `connection_pool`: database connection pool to use.
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
WgPeerManager { connection_pool }
}
/// Creates a new wireguard peer entry for its particular public key or
/// overwrittes the peer entry data if it already existed.
///
/// # Arguments
///
/// * `peer`: peer information needed by wireguard interface.
pub(crate) async fn insert_peer(&self, peer: &WireguardPeer) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT OR REPLACE INTO wireguard_peer(public_key, preshared_key, protocol_version, endpoint, last_handshake, tx_bytes, rx_bytes, persistent_keepalive_interval, allowed_ips, suspended) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
peer.public_key, peer.preshared_key, peer.protocol_version, peer.endpoint, peer.last_handshake, peer.tx_bytes, peer.rx_bytes, peer.persistent_keepalive_interval, peer.allowed_ips, peer.suspended
)
.execute(&self.connection_pool)
.await?;
Ok(())
}
/// Retrieve the wireguard peer with the provided public key from the storage.
///
/// # Arguments
///
/// * `public_key`: the unique public key of the wireguard peer.
pub(crate) async fn retrieve_peer(
&self,
public_key: &str,
) -> Result<Option<WireguardPeer>, sqlx::Error> {
sqlx::query_as!(
WireguardPeer,
r#"
SELECT * FROM wireguard_peer
WHERE public_key = ?
LIMIT 1
"#,
public_key,
)
.fetch_optional(&self.connection_pool)
.await
}
/// Retrieve all wireguard peers.
pub(crate) async fn retrieve_all_peers(&self) -> Result<Vec<WireguardPeer>, sqlx::Error> {
sqlx::query_as!(
WireguardPeer,
r#"
SELECT *
FROM wireguard_peer;
"#,
)
.fetch_all(&self.connection_pool)
.await
}
/// Retrieve the wireguard peer with the provided public key from the storage.
///
/// # Arguments
///
/// * `public_key`: the unique public key of the wireguard peer.
pub(crate) async fn remove_peer(&self, public_key: &str) -> Result<(), sqlx::Error> {
sqlx::query!(
r#"
DELETE FROM wireguard_peer
WHERE public_key = ?
"#,
public_key,
)
.execute(&self.connection_pool)
.await?;
Ok(())
}
}
@@ -1,69 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{v6, v7};
impl From<v7::response::StaticConnectFailureReason> for v6::response::StaticConnectFailureReason {
fn from(failure: v7::response::StaticConnectFailureReason) -> Self {
match failure {
v7::response::StaticConnectFailureReason::RequestedIpAlreadyInUse => {
v6::response::StaticConnectFailureReason::RequestedIpAlreadyInUse
}
v7::response::StaticConnectFailureReason::RequestedNymAddressAlreadyInUse => {
v6::response::StaticConnectFailureReason::RequestedNymAddressAlreadyInUse
}
v7::response::StaticConnectFailureReason::OutOfDateTimestamp => {
v6::response::StaticConnectFailureReason::Other("out of date timestamp".to_string())
}
v7::response::StaticConnectFailureReason::Other(reason) => {
v6::response::StaticConnectFailureReason::Other(reason)
}
}
}
}
impl From<v7::response::DynamicConnectFailureReason> for v6::response::DynamicConnectFailureReason {
fn from(failure: v7::response::DynamicConnectFailureReason) -> Self {
match failure {
v7::response::DynamicConnectFailureReason::RequestedNymAddressAlreadyInUse => {
v6::response::DynamicConnectFailureReason::RequestedNymAddressAlreadyInUse
}
v7::response::DynamicConnectFailureReason::NoAvailableIp => {
v6::response::DynamicConnectFailureReason::NoAvailableIp
}
v7::response::DynamicConnectFailureReason::Other(err) => {
v6::response::DynamicConnectFailureReason::Other(err)
}
}
}
}
impl From<v7::response::InfoResponseReply> for v6::response::InfoResponseReply {
fn from(reply: v7::response::InfoResponseReply) -> Self {
match reply {
v7::response::InfoResponseReply::Generic { msg } => {
v6::response::InfoResponseReply::Generic { msg }
}
v7::response::InfoResponseReply::VersionMismatch {
request_version,
response_version,
} => v6::response::InfoResponseReply::VersionMismatch {
request_version,
response_version,
},
v7::response::InfoResponseReply::ExitPolicyFilterCheckFailed { dst } => {
v6::response::InfoResponseReply::ExitPolicyFilterCheckFailed { dst }
}
}
}
}
impl From<v7::response::InfoLevel> for v6::response::InfoLevel {
fn from(level: v7::response::InfoLevel) -> Self {
match level {
v7::response::InfoLevel::Info => v6::response::InfoLevel::Info,
v7::response::InfoLevel::Warn => v6::response::InfoLevel::Warn,
v7::response::InfoLevel::Error => v6::response::InfoLevel::Error,
}
}
}
-1
View File
@@ -1,4 +1,3 @@
pub mod conversion;
pub mod request;
pub mod response;
@@ -198,17 +198,6 @@ impl IpPacketRequestData {
| IpPacketRequestData::Health(_) => None,
}
}
pub fn signable_request(&self) -> Option<Result<Vec<u8>, SignatureError>> {
match self {
IpPacketRequestData::StaticConnect(request) => Some(request.request()),
IpPacketRequestData::DynamicConnect(request) => Some(request.request()),
IpPacketRequestData::Disconnect(request) => Some(request.request()),
IpPacketRequestData::Data(_) => None,
IpPacketRequestData::Ping(_) => None,
IpPacketRequestData::Health(_) => None,
}
}
}
// A static connect request is when the client provides the internal IP address it will use on the
+1 -1
View File
@@ -7,7 +7,7 @@ license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bip32 = { workspace = true, features = ["secp256k1", "std"] }
bip32 = { workspace = true }
k256 = { workspace = true }
ledger-transport = { workspace = true }
ledger-transport-hid = { workspace = true }
+1 -1
View File
@@ -57,7 +57,7 @@ impl PacketListener {
// cloning the arc as each accepted socket is handled in separate task
let connection_handler = Arc::clone(&self.connection_handler);
let mut handler_shutdown_listener = self.shutdown.clone();
handler_shutdown_listener.disarm();
handler_shutdown_listener.mark_as_success();
tokio::select! {
socket = listener.accept() => {
+1 -1
View File
@@ -245,7 +245,7 @@ impl VerlocMeasurer {
}
let mut shutdown_listener = self.shutdown_listener.clone().named("VerlocMeasurement");
shutdown_listener.disarm();
shutdown_listener.mark_as_success();
for chunk in nodes_to_test.chunks(self.config.tested_nodes_batch_size) {
let mut chunk_results = Vec::with_capacity(chunk.len());
+1 -1
View File
@@ -84,7 +84,7 @@ impl PacketSender {
tested_node: TestedNode,
) -> Result<VerlocMeasurement, RttError> {
let mut shutdown_listener = self.shutdown_listener.fork(tested_node.address.to_string());
shutdown_listener.disarm();
shutdown_listener.mark_as_success();
let mut conn = match tokio::time::timeout(
self.connection_timeout,
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "nym-mobile-storage"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-trait = { workspace = true }
thiserror = { workspace = true }
+11 -13
View File
@@ -2,24 +2,22 @@
// SPDX-License-Identifier: Apache-2.0
/// Specifies the maximum validity of the issued ticketbooks.
pub const TICKETBOOK_VALIDITY_DAYS: u32 = 7;
pub const TICKETBOOK_VALIDITY_DAYS: u64 = 7;
/// Specifies the number of tickets in each issued ticketbook.
pub const TICKETBOOK_SIZE: u64 = 50;
/// This type is defined mostly for the purposes of having constants (like sizes) associated with given variants
/// It's not meant to be serialised or have any fancy traits defined on it (in this crate)
#[derive(Default, Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum TicketTypeRepr {
pub enum TicketbookType {
#[default]
V1MixnetEntry = 0,
V1MixnetExit = 1,
V1WireguardEntry = 2,
V1WireguardExit = 3,
MixnetEntry = 0,
MixnetExit = 1,
WireguardEntry = 2,
WireguardExit = 3,
}
impl TicketTypeRepr {
impl TicketbookType {
pub const WIREGUARD_ENTRY_TICKET_SIZE: u64 = 500 * 1024 * 1024; // 500 MB
// TBD:
@@ -30,10 +28,10 @@ impl TicketTypeRepr {
/// How much bandwidth (in bytes) one ticket can grant
pub const fn bandwidth_value(&self) -> u64 {
match self {
TicketTypeRepr::V1MixnetEntry => Self::MIXNET_ENTRY_TICKET_SIZE,
TicketTypeRepr::V1MixnetExit => Self::MIXNET_EXIT_TICKET_SIZE,
TicketTypeRepr::V1WireguardEntry => Self::WIREGUARD_ENTRY_TICKET_SIZE,
TicketTypeRepr::V1WireguardExit => Self::WIREGUARD_EXIT_TICKET_SIZE,
TicketbookType::MixnetEntry => Self::MIXNET_ENTRY_TICKET_SIZE,
TicketbookType::MixnetExit => Self::MIXNET_EXIT_TICKET_SIZE,
TicketbookType::WireguardEntry => Self::WIREGUARD_ENTRY_TICKET_SIZE,
TicketbookType::WireguardExit => Self::WIREGUARD_EXIT_TICKET_SIZE,
}
}
}
-5
View File
@@ -4,11 +4,6 @@
pub mod constants;
pub mod ecash;
// if you haven't read the Cargo.toml file, the reason for all the feature-locking is that
// this crate is imported into the ecash contract
//
// so if you're thinking of adding a new thing, consider feature-locking it and then just adding it to default feature
#[cfg(all(feature = "env", feature = "network"))]
pub mod env_setup;
pub mod mainnet;
-2
View File
@@ -32,7 +32,6 @@ pub const NYXD_URL: &str = "https://rpc.nymtech.net";
pub const NYM_API: &str = "https://validator.nymtech.net/api/";
pub const NYXD_WS: &str = "wss://rpc.nymtech.net/websocket";
pub const EXPLORER_API: &str = "https://explorer.nymtech.net/api/";
pub const NYM_VPN_API: &str = "https://nymvpn.net/api/";
// I'm making clippy mad on purpose, because that url HAS TO be updated and deployed before merging
pub const EXIT_POLICY_URL: &str =
@@ -125,7 +124,6 @@ pub fn export_to_env() {
set_var_to_default(var_names::NYXD_WEBSOCKET, NYXD_WS);
set_var_to_default(var_names::EXPLORER_API, EXPLORER_API);
set_var_to_default(var_names::EXIT_POLICY_URL, EXIT_POLICY_URL);
set_var_to_default(var_names::NYM_VPN_API, NYM_VPN_API);
}
#[cfg(all(feature = "env", feature = "network"))]
-17
View File
@@ -33,7 +33,6 @@ pub struct NymNetworkDetails {
pub endpoints: Vec<ValidatorDetails>,
pub contracts: NymContracts,
pub explorer_api: Option<String>,
pub nym_vpn_api_url: Option<String>,
}
// by default we assume the same defaults as mainnet, i.e. same prefixes and denoms
@@ -63,7 +62,6 @@ impl NymNetworkDetails {
endpoints: Default::default(),
contracts: Default::default(),
explorer_api: Default::default(),
nym_vpn_api_url: Default::default(),
}
}
@@ -122,7 +120,6 @@ impl NymNetworkDetails {
.with_multisig_contract(get_optional_env(var_names::MULTISIG_CONTRACT_ADDRESS))
.with_coconut_dkg_contract(get_optional_env(var_names::COCONUT_DKG_CONTRACT_ADDRESS))
.with_explorer_api(get_optional_env(var_names::EXPLORER_API))
.with_nym_vpn_api_url(get_optional_env(var_names::NYM_VPN_API))
}
pub fn new_mainnet() -> Self {
@@ -150,7 +147,6 @@ impl NymNetworkDetails {
),
},
explorer_api: parse_optional_str(mainnet::EXPLORER_API),
nym_vpn_api_url: parse_optional_str(mainnet::NYM_VPN_API),
}
}
@@ -259,19 +255,6 @@ impl NymNetworkDetails {
self.explorer_api = endpoint.map(Into::into);
self
}
#[must_use]
pub fn with_nym_vpn_api_url<S: Into<String>>(mut self, endpoint: Option<S>) -> Self {
self.nym_vpn_api_url = endpoint.map(Into::into);
self
}
pub fn nym_vpn_api_url(&self) -> Option<Url> {
self.nym_vpn_api_url.as_ref().map(|url| {
url.parse()
.expect("the provided nym-vpn api url is invalid!")
})
}
}
#[derive(Debug, Copy, Serialize, Deserialize, Clone, PartialEq, Eq)]
-1
View File
@@ -24,7 +24,6 @@ pub const NYM_API: &str = "NYM_API";
pub const NYXD_WEBSOCKET: &str = "NYXD_WS";
pub const EXPLORER_API: &str = "EXPLORER_API";
pub const EXIT_POLICY_URL: &str = "EXIT_POLICY";
pub const NYM_VPN_API: &str = "NYM_VPN_API";
pub const DKG_TIME_CONFIGURATION: &str = "DKG_TIME_CONFIGURATION";
@@ -35,7 +35,7 @@ fn bench_coin_signing(c: &mut Criterion) {
// ISSUING AUTHORITY BENCHMARK: issue a set of (partial) signatures for coin indices
group.bench_function(
format!(
&format!(
"[IssuingAuthority] sign_coin_indices_L_{}",
params.get_total_coins()
),
@@ -47,7 +47,7 @@ fn bench_coin_signing(c: &mut Criterion) {
verify_coin_indices_signatures(&verification_key, &vk_i_auth, &partial_signatures).is_ok()
);
group.bench_function(
format!(
&format!(
"[Client] verify_coin_indices_signatures_L_{}",
params.get_total_coins()
),
@@ -99,7 +99,7 @@ fn bench_aggregate_coin_indices_signatures(c: &mut Criterion) {
// CLIENT: verify all the partial signature vectors and aggregate into a single vector of signed coin indices
group.bench_function(
format!(
&format!(
"[Client] aggregate_coin_indices_signatures_from_{}_issuing_authorities_L_{}",
authorities_keypairs.len(),
params.get_total_coins(),
@@ -4,6 +4,7 @@
use criterion::{criterion_group, criterion_main, Criterion};
use itertools::izip;
use nym_compact_ecash::identify::{identify, IdentifyResult};
use nym_compact_ecash::scheme::expiration_date_signatures::date_scalar;
use nym_compact_ecash::scheme::keygen::SecretKeyAuth;
use nym_compact_ecash::setup::Parameters;
use nym_compact_ecash::tests::helpers::{
@@ -14,7 +15,6 @@ use nym_compact_ecash::{
ttp_keygen, withdrawal_request, PartialWallet, PayInfo, PublicKeyUser, SecretKeyUser,
VerificationKeyAuth,
};
use nym_network_defaults::TicketTypeRepr;
use rand::seq::SliceRandom;
struct BenchCase {
@@ -30,14 +30,13 @@ fn bench_compact_ecash(c: &mut Criterion) {
// group.sample_size(300);
// group.measurement_time(Duration::from_secs(1500));
let spend_date = 1701907200; // Dec 07 2023 00:00:00
let expiration_date = 1702166400; // Dec 10 2023 00:00:00
let encoded_ticket_type = TicketTypeRepr::default() as u8;
let expiration_date = 1703721600; // Dec 28 2023
let spend_date = 1701907200; // Dec 07 2023
let case = BenchCase {
num_authorities: 100,
threshold_p: 0.7,
ll: 50,
ll: 1000,
spend_vv: 1,
case_nr_pub_keys: 99,
};
@@ -84,29 +83,15 @@ fn bench_compact_ecash(c: &mut Criterion) {
.unwrap();
// ISSUANCE PHASE
let (req, req_info) = withdrawal_request(
user_keypair.secret_key(),
expiration_date,
encoded_ticket_type,
)
.unwrap();
let (req, req_info) = withdrawal_request(user_keypair.secret_key(), expiration_date).unwrap();
// CLIENT BENCHMARK: prepare a single withdrawal request
group.bench_function(
format!(
&format!(
"[Client] withdrawal_request_{}_authorities_{}_L_{}_threshold",
case.num_authorities, case.ll, case.threshold_p,
),
|b| {
b.iter(|| {
withdrawal_request(
user_keypair.secret_key(),
expiration_date,
encoded_ticket_type,
)
.unwrap()
})
},
|b| b.iter(|| withdrawal_request(user_keypair.secret_key(), expiration_date).unwrap()),
);
// ISSUING AUTHRORITY BENCHMARK: Benchmark the issue function
@@ -114,7 +99,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
let mut rng = rand::thread_rng();
let keypair = authorities_keypairs.choose(&mut rng).unwrap();
group.bench_function(
format!(
&format!(
"[Issuing Authority] issue_partial_wallet_with_L_{}",
case.ll,
),
@@ -125,7 +110,6 @@ fn bench_compact_ecash(c: &mut Criterion) {
user_keypair.public_key(),
&req,
expiration_date,
encoded_ticket_type,
)
})
},
@@ -138,7 +122,6 @@ fn bench_compact_ecash(c: &mut Criterion) {
user_keypair.public_key(),
&req,
expiration_date,
encoded_ticket_type,
);
wallet_blinded_signatures.push(blind_signature.unwrap());
}
@@ -147,7 +130,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
let w = wallet_blinded_signatures.first().unwrap();
let vk = verification_keys_auth.first().unwrap();
group.bench_function(
format!("[Client] issue_verify_a_partial_wallet_with_L_{}", case.ll,),
&format!("[Client] issue_verify_a_partial_wallet_with_L_{}", case.ll,),
|b| b.iter(|| issue_verify(vk, user_keypair.secret_key(), w, &req_info, 1).unwrap()),
);
@@ -163,7 +146,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
// CLIENT BENCHMARK: aggregating all partial wallets
group.bench_function(
format!(
&format!(
"[Client] aggregate_wallets_with_L_{}_threshold_{}",
case.ll, case.threshold_p,
),
@@ -196,7 +179,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
};
// CLIENT BENCHMARK: spend a single coin from the wallet
group.bench_function(
format!(
&format!(
"[Client] spend_a_single_coin_L_{}_threshold_{}",
case.ll, case.threshold_p,
),
@@ -233,14 +216,14 @@ fn bench_compact_ecash(c: &mut Criterion) {
// MERCHANT BENCHMARK: verify whether the submitted payment is legit
group.bench_function(
format!(
&format!(
"[Merchant] spend_verify_of_a_single_payment_L_{}_threshold_{}",
case.ll, case.threshold_p,
),
|b| {
b.iter(|| {
payment
.spend_verify(&verification_key, &pay_info, spend_date)
.spend_verify(&verification_key, &pay_info, date_scalar(spend_date))
.unwrap()
})
},
@@ -280,7 +263,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
// MERCHANT BENCHMARK: identify double spending
group.bench_function(
format!(
&format!(
"[Merchant] identify_L_{}_threshold_{}_spend_vv_{}_pks_{}",
case.ll,
case.threshold_p,
@@ -21,7 +21,7 @@ fn bench_partial_sign_expiration_date(c: &mut Criterion) {
// ISSUING AUTHORITY BENCHMARK: issue a set of (partial) signatures for a given expiration date
group.bench_function(
format!(
&format!(
"[IssuingAuthority] sign_expiration_date_{}_validity_period",
constants::CRED_VALIDITY_PERIOD_DAYS,
),
@@ -31,7 +31,7 @@ fn bench_partial_sign_expiration_date(c: &mut Criterion) {
// CLIENT: verify the correctness of the set of (partial) signatures for a given expiration date
assert!(verify_valid_dates_signatures(&vk_i_auth, &partial_exp_sig, expiration_date).is_ok());
group.bench_function(
format!(
&format!(
"[Client] verify_valid_dates_signatures_{}_validity_period",
constants::CRED_VALIDITY_PERIOD_DAYS,
),
@@ -78,7 +78,7 @@ fn bench_aggregate_expiration_date_signatures(c: &mut Criterion) {
// CLIENT: verify all the partial signature vectors and aggregate into a single vector of signed valid dates
group.bench_function(
format!(
&format!(
"[Client] aggregate_expiration_signatures_from_{}_issuing_authorities_{}_validity_period",
constants::CRED_VALIDITY_PERIOD_DAYS, authorities_keypairs.len(),
),
@@ -9,9 +9,9 @@ pub const PUBLIC_ATTRIBUTES_LEN: usize = 2; //expiration date and ticket type
pub const PRIVATE_ATTRIBUTES_LEN: usize = 2; //user and wallet secret
pub const ATTRIBUTES_LEN: usize = PUBLIC_ATTRIBUTES_LEN + PRIVATE_ATTRIBUTES_LEN; // number of attributes encoded in a single zk-nym credential
pub const CRED_VALIDITY_PERIOD_DAYS: u32 = TICKETBOOK_VALIDITY_DAYS;
pub const CRED_VALIDITY_PERIOD_DAYS: u64 = TICKETBOOK_VALIDITY_DAYS;
pub(crate) const SECONDS_PER_DAY: u32 = 86400;
pub(crate) const SECONDS_PER_DAY: u64 = 86400;
/// Total number of tickets in each issued ticket book.
pub const NB_TICKETS: u64 = TICKETBOOK_SIZE;
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use crate::utils::try_deserialize_g1_projective;
use crate::{CompactEcashError, EncodedDate, EncodedTicketType};
use bls12_381::{G1Projective, Scalar};
use crate::CompactEcashError;
use bls12_381::G1Projective;
use group::Curve;
use std::any::{type_name, Any};
@@ -35,27 +35,3 @@ pub(crate) fn recover_g1_tuple<T: Any>(
Ok((first, second))
}
pub fn date_scalar(date: EncodedDate) -> Scalar {
Scalar::from(date as u64)
}
// TODO: this will not work for **all** scalars,
// but timestamps have extremely (relatively speaking) limited range,
// so this should be fine
pub(crate) fn scalar_date(scalar: &Scalar) -> EncodedDate {
let b = scalar.to_bytes();
u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) as EncodedDate
}
pub fn type_scalar(t_type: EncodedTicketType) -> Scalar {
Scalar::from(t_type as u64)
}
// TODO: this will not work for **all** scalars,
// but ticket types have extremely (relatively speaking) limited range,
// so this should be fine
pub(crate) fn scalar_type(scalar: &Scalar) -> EncodedTicketType {
let b = scalar.to_bytes();
u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) as EncodedTicketType
}
@@ -13,7 +13,6 @@ pub use crate::error::CompactEcashError;
pub use crate::traits::Bytable;
pub use bls12_381::G1Projective;
pub use common_types::{BlindedSignature, Signature};
pub use helpers::{date_scalar, type_scalar};
pub use scheme::aggregation::aggregate_verification_keys;
pub use scheme::aggregation::aggregate_wallets;
pub use scheme::identify;
@@ -43,8 +42,6 @@ mod traits;
pub mod utils;
pub type Attribute = Scalar;
pub type EncodedTicketType = u8;
pub type EncodedDate = u32;
pub fn ecash_parameters() -> &'static setup::Parameters {
static ECASH_PARAMS: OnceLock<setup::Parameters> = OnceLock::new();
@@ -1,19 +1,23 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use core::iter::Sum;
use core::ops::Mul;
use bls12_381::{G2Prepared, G2Projective, Scalar};
use group::Curve;
use itertools::Itertools;
use crate::common_types::{PartialSignature, Signature, SignatureShare, SignerIndex};
use crate::error::{CompactEcashError, Result};
use crate::helpers::{scalar_date, scalar_type};
use crate::scheme::expiration_date_signatures::scalar_date;
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::withdrawal::RequestInfo;
use crate::scheme::{PartialWallet, Wallet, WalletSignatures};
use crate::utils::{check_bilinear_pairing, perform_lagrangian_interpolation_at_origin};
use crate::utils::{
check_bilinear_pairing, perform_lagrangian_interpolation_at_origin, scalar_type,
};
use crate::{ecash_group_parameters, Attribute};
use bls12_381::{G2Prepared, G2Projective, Scalar};
use core::iter::Sum;
use core::ops::Mul;
use group::Curve;
use itertools::Itertools;
pub(crate) trait Aggregatable: Sized {
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
@@ -2,12 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
use crate::common_types::{Signature, SignerIndex};
use crate::constants;
use crate::error::{CompactEcashError, Result};
use crate::helpers::date_scalar;
use crate::scheme::keygen::{SecretKeyAuth, VerificationKeyAuth};
use crate::utils::generate_lagrangian_coefficients_at_origin;
use crate::utils::{batch_verify_signatures, hash_g1};
use crate::{constants, EncodedDate};
use bls12_381::{G1Projective, Scalar};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
@@ -20,8 +19,8 @@ pub type PartialExpirationDateSignature = ExpirationDateSignature;
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct AnnotatedExpirationDateSignature {
pub signature: ExpirationDateSignature,
pub expiration_timestamp: EncodedDate,
pub spending_timestamp: EncodedDate,
pub expiration_timestamp: u64,
pub spending_timestamp: u64,
}
impl Borrow<ExpirationDateSignature> for AnnotatedExpirationDateSignature {
@@ -67,17 +66,17 @@ where
/// The validity period is determined by the constant `CRED_VALIDITY_PERIOD` in the `constants` module.
pub fn sign_expiration_date(
sk_auth: &SecretKeyAuth,
expiration_unix_timestamp: EncodedDate,
expiration_unix_timestamp: u64,
) -> Result<Vec<AnnotatedExpirationDateSignature>> {
if sk_auth.ys.len() < 3 {
return Err(CompactEcashError::KeyTooShort);
}
let m0: Scalar = date_scalar(expiration_unix_timestamp);
let m0: Scalar = Scalar::from(expiration_unix_timestamp);
let m2: Scalar = constants::TYPE_EXP;
let partial_s_exponent = sk_auth.x + sk_auth.ys[0] * m0 + sk_auth.ys[2] * m2;
let sign_expiration = |offset: u32| {
let sign_expiration = |offset: u64| {
// we produce tuples of (assuming CRED_VALIDITY_PERIOD_DAYS = 30):
// (expiration, expiration - 29)
// (expiration, expiration - 28)
@@ -85,7 +84,7 @@ pub fn sign_expiration_date(
// (expiration, expiration)
let spending_unix_timestamp = expiration_unix_timestamp
- ((constants::CRED_VALIDITY_PERIOD_DAYS - offset - 1) * constants::SECONDS_PER_DAY);
let m1: Scalar = date_scalar(spending_unix_timestamp);
let m1: Scalar = Scalar::from(spending_unix_timestamp);
// Compute the hash
let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat());
// Sign the attributes by performing scalar-point multiplications and accumulating the result
@@ -137,22 +136,22 @@ pub fn sign_expiration_date(
pub fn verify_valid_dates_signatures<B>(
vk: &VerificationKeyAuth,
signatures: &[B],
expiration_date: EncodedDate,
expiration_date: u64,
) -> Result<()>
where
B: Borrow<ExpirationDateSignature>,
{
let m0: Scalar = date_scalar(expiration_date);
let m0: Scalar = Scalar::from(expiration_date);
let m2: Scalar = constants::TYPE_EXP;
let partially_signed = vk.alpha + vk.beta_g2[0] * m0 + vk.beta_g2[2] * m2;
let mut pairing_terms = Vec::with_capacity(signatures.len());
for (i, sig) in signatures.iter().enumerate() {
let l = i as u32;
let l = i as u64;
let valid_date = expiration_date
- ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY);
let m1: Scalar = date_scalar(valid_date);
let m1: Scalar = Scalar::from(valid_date);
// Compute the hash
let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat());
@@ -200,7 +199,7 @@ where
///
fn _aggregate_expiration_signatures<B>(
vk: &VerificationKeyAuth,
expiration_date: EncodedDate,
expiration_date: u64,
signatures_shares: &[ExpirationDateSignatureShare<B>],
validate_shares: bool,
) -> Result<Vec<ExpirationDateSignature>>
@@ -245,12 +244,12 @@ where
let mut aggregated_date_signatures: Vec<ExpirationDateSignature> =
Vec::with_capacity(constants::CRED_VALIDITY_PERIOD_DAYS as usize);
let m0: Scalar = date_scalar(expiration_date);
let m0: Scalar = Scalar::from(expiration_date);
for l in 0..constants::CRED_VALIDITY_PERIOD_DAYS {
let valid_date = expiration_date
- ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY);
let m1: Scalar = date_scalar(valid_date);
let m1: Scalar = Scalar::from(valid_date);
// Compute the hash
let h = hash_g1([m0.to_bytes(), m1.to_bytes()].concat());
@@ -300,7 +299,7 @@ where
///
pub fn aggregate_expiration_signatures<B>(
vk: &VerificationKeyAuth,
expiration_date: EncodedDate,
expiration_date: u64,
signatures_shares: &[ExpirationDateSignatureShare<B>],
) -> Result<Vec<ExpirationDateSignature>>
where
@@ -315,7 +314,7 @@ where
/// It further annotates the result with timestamp information
pub fn aggregate_annotated_expiration_signatures(
vk: &VerificationKeyAuth,
expiration_date: EncodedDate,
expiration_date: u64,
signatures_shares: &[ExpirationDateSignatureShare<AnnotatedExpirationDateSignature>],
) -> Result<Vec<AnnotatedExpirationDateSignature>> {
// it's sufficient to just verify the first share as if the rest of them don't match,
@@ -333,7 +332,7 @@ pub fn aggregate_annotated_expiration_signatures(
return Err(CompactEcashError::ExpirationDateSignatureVerification);
}
let l = i as u32;
let l = i as u64;
let expected_spending = sig.expiration_timestamp
- ((constants::CRED_VALIDITY_PERIOD_DAYS - l - 1) * constants::SECONDS_PER_DAY);
@@ -362,7 +361,7 @@ pub fn aggregate_annotated_expiration_signatures(
/// It is expected the caller has already pre-validated them via manual calls to `verify_valid_dates_signatures`
pub fn unchecked_aggregate_expiration_signatures(
vk: &VerificationKeyAuth,
expiration_date: EncodedDate,
expiration_date: u64,
signatures_shares: &[ExpirationDateSignatureShare],
) -> Result<Vec<ExpirationDateSignature>> {
_aggregate_expiration_signatures(vk, expiration_date, signatures_shares, false)
@@ -384,13 +383,13 @@ pub fn unchecked_aggregate_expiration_signatures(
/// If a valid index is found, returns `Ok(index)`. If no valid index is found
/// (i.e., `spend_date` is earlier than `expiration_date - 30`), returns `Err(InvalidDateError)`.
///
pub fn find_index(spend_date: EncodedDate, expiration_date: EncodedDate) -> Result<usize> {
pub fn find_index(spend_date: u64, expiration_date: u64) -> Result<usize> {
let start_date =
expiration_date - ((constants::CRED_VALIDITY_PERIOD_DAYS - 1) * constants::SECONDS_PER_DAY);
if spend_date >= start_date {
let index_a = ((spend_date - start_date) / constants::SECONDS_PER_DAY) as usize;
if index_a as u32 >= constants::CRED_VALIDITY_PERIOD_DAYS {
if index_a as u64 >= constants::CRED_VALIDITY_PERIOD_DAYS {
Err(CompactEcashError::SpendDateTooLate)
} else {
Ok(index_a)
@@ -400,6 +399,18 @@ pub fn find_index(spend_date: EncodedDate, expiration_date: EncodedDate) -> Resu
}
}
pub fn date_scalar(date: u64) -> Scalar {
Scalar::from(date)
}
// TODO: this will not work for **all** scalars,
// but timestamps have extremely (relatively speaking) limited range,
// so this should be fine
pub fn scalar_date(scalar: &Scalar) -> u64 {
let b = scalar.to_bytes();
u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
}
#[cfg(test)]
mod tests {
use super::*;
@@ -54,6 +54,7 @@ pub fn identify(
#[cfg(test)]
mod tests {
use crate::scheme::expiration_date_signatures::date_scalar;
use crate::scheme::identify::{identify, IdentifyResult};
use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser};
use crate::setup::Parameters;
@@ -164,12 +165,12 @@ mod tests {
.unwrap();
assert!(payment1
.spend_verify(&verification_key, &pay_info1, spend_date)
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
.is_ok());
let payment2 = payment1.clone();
assert!(payment2
.spend_verify(&verification_key, &pay_info1, spend_date)
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
.is_ok());
let identify_result = identify(&payment1, &payment2, pay_info1, pay_info1);
@@ -274,7 +275,7 @@ mod tests {
.unwrap();
assert!(payment1
.spend_verify(&verification_key, &pay_info1, spend_date)
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
.is_ok());
let pay_info2 = PayInfo {
@@ -294,7 +295,7 @@ mod tests {
.unwrap();
assert!(payment2
.spend_verify(&verification_key, &pay_info2, spend_date)
.spend_verify(&verification_key, &pay_info2, date_scalar(spend_date))
.is_ok());
let identify_result = identify(&payment1, &payment2, pay_info1, pay_info2);
@@ -410,7 +411,7 @@ mod tests {
.unwrap();
assert!(payment1
.spend_verify(&verification_key, &pay_info1, spend_date)
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
.is_ok());
// let's reverse the spending counter in the wallet to create a double spending payment
@@ -434,7 +435,7 @@ mod tests {
.unwrap();
assert!(payment2
.spend_verify(&verification_key, &pay_info2, spend_date)
.spend_verify(&verification_key, &pay_info2, date_scalar(spend_date))
.is_ok());
let identify_result = identify(&payment1, &payment2, pay_info1, pay_info2);
@@ -554,7 +555,7 @@ mod tests {
.unwrap();
assert!(payment1
.spend_verify(&verification_key, &pay_info1, spend_date)
.spend_verify(&verification_key, &pay_info1, date_scalar(spend_date))
.is_ok());
// let's reverse the spending counter in the wallet to create a double spending payment
@@ -97,6 +97,10 @@ impl SecretKeyAuth {
self.ys.len()
}
pub(crate) fn get_y_by_idx(&self, i: usize) -> Option<&Scalar> {
self.ys.get(i)
}
pub fn verification_key(&self) -> VerificationKeyAuth {
let params = ecash_group_parameters();
let g1 = params.gen1();
@@ -3,18 +3,17 @@
use crate::common_types::{Signature, SignerIndex};
use crate::error::{CompactEcashError, Result};
use crate::helpers::{date_scalar, type_scalar};
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
use crate::scheme::coin_indices_signatures::CoinIndexSignature;
use crate::scheme::expiration_date_signatures::{find_index, ExpirationDateSignature};
use crate::scheme::expiration_date_signatures::{date_scalar, find_index, ExpirationDateSignature};
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::setup::{GroupParameters, Parameters};
use crate::traits::Bytable;
use crate::utils::{
batch_verify_signatures, check_bilinear_pairing, hash_to_scalar, try_deserialize_scalar,
};
use crate::Base58;
use crate::{constants, ecash_group_parameters};
use crate::{Base58, EncodedDate, EncodedTicketType};
use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar};
use group::Curve;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -229,7 +228,7 @@ impl Wallet {
spend_value: u64,
valid_dates_signatures: &[ExpirationDateSignature],
coin_indices_signatures: &[CoinIndexSignature],
spend_date_timestamp: EncodedDate,
spend_date_timestamp: u64,
) -> Result<Payment> {
self.check_remaining_allowance(params, spend_value)?;
@@ -270,8 +269,8 @@ pub struct WalletSignatures {
#[zeroize(skip)]
sig: Signature,
v: Scalar,
expiration_date_timestamp: EncodedDate,
t_type: EncodedTicketType,
expiration_date_timestamp: u64,
t_type: u64,
}
impl WalletSignatures {
@@ -315,8 +314,8 @@ pub fn compute_pay_info_hash(pay_info: &PayInfo, k: u64) -> Scalar {
}
impl WalletSignatures {
// signature size (96) + secret size (32) + expiration size (4) + t_type (1)
pub const SERIALISED_SIZE: usize = 133;
// signature size (96) + secret size (32) + expiration size (8) + t_type (8)
pub const SERIALISED_SIZE: usize = 144;
pub fn signature(&self) -> &Signature {
&self.sig
@@ -336,8 +335,8 @@ impl WalletSignatures {
let mut bytes = [0u8; Self::SERIALISED_SIZE];
bytes[0..96].copy_from_slice(&self.sig.to_bytes());
bytes[96..128].copy_from_slice(&self.v.to_bytes());
bytes[128..132].copy_from_slice(&self.expiration_date_timestamp.to_be_bytes());
bytes[132] = self.t_type;
bytes[128..136].copy_from_slice(&self.expiration_date_timestamp.to_be_bytes());
bytes[136..144].copy_from_slice(&self.t_type.to_be_bytes());
bytes
}
@@ -357,12 +356,15 @@ impl WalletSignatures {
let v_bytes: &[u8; 32] = &bytes[96..128].try_into().unwrap();
#[allow(clippy::unwrap_used)]
let expiration_date_bytes = bytes[128..132].try_into().unwrap();
let expiration_date_bytes = bytes[128..136].try_into().unwrap();
#[allow(clippy::unwrap_used)]
let t_type_bytes = bytes[136..].try_into().unwrap();
let sig = Signature::try_from(sig_bytes.as_slice())?;
let v = Scalar::from_bytes(v_bytes).unwrap();
let expiration_date_timestamp = EncodedDate::from_be_bytes(expiration_date_bytes);
let t_type = bytes[132];
let expiration_date_timestamp = u64::from_be_bytes(expiration_date_bytes);
let t_type = u64::from_be_bytes(t_type_bytes);
Ok(WalletSignatures {
sig,
@@ -399,7 +401,7 @@ impl WalletSignatures {
spend_value: u64,
valid_dates_signatures: &[BE],
coin_indices_signatures: &[BI],
spend_date_timestamp: EncodedDate,
spend_date_timestamp: u64,
) -> Result<Payment>
where
BI: Borrow<CoinIndexSignature>,
@@ -594,7 +596,7 @@ fn pseudorandom_f_g_v(params: &GroupParameters, v: &Scalar, l: u64) -> Result<G1
/// * `params` - A reference to the group parameters required for the computation.
/// * `verification_key` - The global verification key of the signing authorities.
/// * `attributes` - A slice of private attributes associated with the wallet.
/// * `blinding_factor` - The blinding factor used to randomise the wallet's signature.
/// * `blinding_factor` - The blinding factor used used to randomise the wallet's signature.
///
/// # Returns
///
@@ -687,7 +689,7 @@ pub struct Payment {
pub aa: Vec<G1Projective>,
pub spend_value: u64,
pub cc: G1Projective,
pub t_type: EncodedTicketType,
pub t_type: u64,
pub zk_proof: SpendProof,
}
@@ -718,7 +720,7 @@ impl Payment {
return Err(CompactEcashError::SpendSignaturesValidity);
}
let kappa_type = self.kappa + verification_key.beta_g2[3] * type_scalar(self.t_type);
let kappa_type = self.kappa + verification_key.beta_g2[3] * Scalar::from(self.t_type);
if !check_bilinear_pairing(
&self.sig.h.to_affine(),
&G2Prepared::from(kappa_type.to_affine()),
@@ -948,7 +950,7 @@ impl Payment {
&self,
verification_key: &VerificationKeyAuth,
pay_info: &PayInfo,
spend_date: EncodedDate,
spend_date: Scalar,
) -> Result<()> {
// check if all serial numbers are different
self.no_duplicate_serial_numbers()?;
@@ -957,7 +959,7 @@ impl Payment {
// Verify whether the payment signature and kappa are correct
self.check_signature_validity(verification_key)?;
// Verify whether the expiration date signature and kappa_e are correct
self.check_exp_signature_validity(verification_key, date_scalar(spend_date))?;
self.check_exp_signature_validity(verification_key, spend_date)?;
// Verify whether the coin indices signatures and kappa_k are correct
self.batch_check_coin_index_signatures(verification_key)?;
@@ -3,7 +3,6 @@
use crate::common_types::{BlindedSignature, Signature, SignerIndex};
use crate::error::{CompactEcashError, Result};
use crate::helpers::{date_scalar, type_scalar};
use crate::proofs::proof_withdrawal::{
WithdrawalReqInstance, WithdrawalReqProof, WithdrawalReqWitness,
};
@@ -11,7 +10,7 @@ use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser, Verific
use crate::scheme::setup::GroupParameters;
use crate::scheme::PartialWallet;
use crate::utils::{check_bilinear_pairing, hash_g1};
use crate::{constants, ecash_group_parameters, Attribute, EncodedDate, EncodedTicketType};
use crate::{constants, ecash_group_parameters, Attribute};
use bls12_381::{multi_miller_loop, G1Projective, G2Prepared, G2Projective, Scalar};
use group::{Curve, Group, GroupEncoding};
use serde::{Deserialize, Serialize};
@@ -142,25 +141,28 @@ fn compute_private_attribute_commitments(
/// openings for private attributes, `v`, and the expiration date.
pub fn withdrawal_request(
sk_user: &SecretKeyUser,
expiration_date: EncodedDate,
t_type: EncodedTicketType,
expiration_date: u64,
t_type: u64,
) -> Result<(WithdrawalRequest, RequestInfo)> {
let params = ecash_group_parameters();
// Generate random and unique wallet secret
let v = params.random_scalar();
let joined_commitment_opening = params.random_scalar();
let gamma = params.gammas();
let expiration_date = date_scalar(expiration_date);
let t_type = type_scalar(t_type);
// Compute joined commitment for all attributes (public and private)
let joined_commitment =
params.gen1() * joined_commitment_opening + gamma[0] * sk_user.sk + gamma[1] * v;
//SAFETY: params is static with length 3
#[allow(clippy::unwrap_used)]
let joined_commitment: G1Projective = params.gen1() * joined_commitment_opening
+ params.gamma_idx(0).unwrap() * sk_user.sk
+ params.gamma_idx(1).unwrap() * v;
// Compute commitment hash h
let joined_commitment_hash =
hash_g1((joined_commitment + gamma[2] * expiration_date + gamma[3] * t_type).to_bytes());
#[allow(clippy::unwrap_used)]
let joined_commitment_hash = hash_g1(
(joined_commitment
+ params.gamma_idx(2).unwrap() * Scalar::from(expiration_date)
+ params.gamma_idx(3).unwrap() * Scalar::from(t_type))
.to_bytes(),
);
// Compute Pedersen commitments for private attributes (wallet secret and user's secret)
let private_attributes = vec![sk_user.sk, v];
@@ -197,8 +199,8 @@ pub fn withdrawal_request(
joined_commitment_opening,
private_attributes_openings: private_attributes_openings.clone(),
wallet_secret: v,
expiration_date,
t_type,
expiration_date: Scalar::from(expiration_date),
t_type: Scalar::from(t_type),
},
))
}
@@ -220,17 +222,18 @@ pub fn withdrawal_request(
pub fn request_verify(
req: &WithdrawalRequest,
pk_user: PublicKeyUser,
expiration_date: EncodedDate,
t_type: EncodedTicketType,
expiration_date: u64,
t_type: u64,
) -> Result<()> {
let params = ecash_group_parameters();
let gamma = params.gammas();
let expiration_date = date_scalar(expiration_date);
let t_type = type_scalar(t_type);
// Verify the joined commitment hash
//SAFETY: params is static with length 3
#[allow(clippy::unwrap_used)]
let expected_commitment_hash = hash_g1(
(req.joined_commitment + gamma[2] * expiration_date + gamma[3] * t_type).to_bytes(),
(req.joined_commitment
+ params.gamma_idx(2).unwrap() * Scalar::from(expiration_date)
+ params.gamma_idx(3).unwrap() * Scalar::from(t_type))
.to_bytes(),
);
if req.joined_commitment_hash != expected_commitment_hash {
return Err(CompactEcashError::WithdrawalRequestVerification);
@@ -267,10 +270,13 @@ pub fn request_verify(
/// authentication secret key index is out of bounds.
fn sign_expiration_date(
joined_commitment_hash: &G1Projective,
expiration_date: EncodedDate,
expiration_date: u64,
sk_auth: &SecretKeyAuth,
) -> G1Projective {
joined_commitment_hash * (sk_auth.ys[2] * date_scalar(expiration_date))
//SAFETY : this fn assumes a long enough key
#[allow(clippy::unwrap_used)]
let yi = sk_auth.get_y_by_idx(2).unwrap();
joined_commitment_hash * (yi * Scalar::from(expiration_date))
}
/// Signs a transaction type using a joined commitment hash and a secret key.
@@ -290,10 +296,13 @@ fn sign_expiration_date(
/// The resulting G1Projective point representing the signed ticket type.
fn sign_t_type(
joined_commitment_hash: &G1Projective,
t_type: EncodedTicketType,
t_type: u64,
sk_auth: &SecretKeyAuth,
) -> G1Projective {
joined_commitment_hash * (sk_auth.ys[3] * type_scalar(t_type))
//SAFETY : this fn assumes a long enough key
#[allow(clippy::unwrap_used)]
let yi = sk_auth.get_y_by_idx(3).unwrap();
joined_commitment_hash * (yi * Scalar::from(t_type))
}
/// Issues a blinded signature for a withdrawal request, after verifying its integrity.
@@ -318,8 +327,8 @@ pub fn issue(
sk_auth: &SecretKeyAuth,
pk_user: PublicKeyUser,
withdrawal_req: &WithdrawalRequest,
expiration_date: EncodedDate,
t_type: EncodedTicketType,
expiration_date: u64,
t_type: u64,
) -> Result<BlindedSignature> {
// Verify the withdrawal request
request_verify(withdrawal_req, pk_user, expiration_date, t_type)?;
@@ -5,6 +5,7 @@
mod tests {
use crate::error::Result;
use crate::scheme::aggregation::{aggregate_verification_keys, aggregate_wallets};
use crate::scheme::expiration_date_signatures::date_scalar;
use crate::scheme::keygen::{
generate_keypair_user, ttp_keygen, SecretKeyAuth, VerificationKeyAuth,
};
@@ -124,7 +125,7 @@ mod tests {
)?;
assert!(payment
.spend_verify(&verification_key, &pay_info, spend_date)
.spend_verify(&verification_key, &pay_info, date_scalar(spend_date))
.is_ok());
let payment_bytes = payment.to_bytes();
@@ -15,13 +15,12 @@ use crate::scheme::Payment;
use crate::setup::Parameters;
use crate::{
aggregate_verification_keys, aggregate_wallets, constants, generate_keypair_user, issue,
issue_verify, withdrawal_request, EncodedDate, EncodedTicketType, PartialWallet, PayInfo,
VerificationKeyAuth,
issue_verify, withdrawal_request, PartialWallet, PayInfo, VerificationKeyAuth,
};
use itertools::izip;
pub fn generate_expiration_date_signatures(
expiration_date: EncodedDate,
expiration_date: u64,
secret_keys_authorities: &[&SecretKeyAuth],
verification_keys_auth: &[VerificationKeyAuth],
verification_key: &VerificationKeyAuth,
@@ -83,8 +82,8 @@ pub fn generate_coin_indices_signatures(
pub fn payment_from_keys_and_expiration_date(
ecash_keypairs: &Vec<KeyPairAuth>,
indices: &[SignerIndex],
expiration_date: EncodedDate,
t_type: EncodedTicketType,
expiration_date: u64,
t_type: u64,
) -> Result<(Payment, PayInfo)> {
let total_coins = 32;
let params = Parameters::new(total_coins);

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