Merge branch 'feature/nym-wallet-rename' of github.com:nymtech/nym into feature/nym-wallet-rename

This commit is contained in:
Dave Hrycyszyn
2021-11-11 10:50:12 +00:00
115 changed files with 6449 additions and 909 deletions
+29 -69
View File
@@ -9,14 +9,24 @@ on:
- 'explorer/**'
jobs:
matrix_prep:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from build_matrix_includes.json
- uses: actions/checkout@v2
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/build_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
build:
needs: matrix_prep
strategy:
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.os == 'windows-latest' }}
strategy:
matrix:
rust: [stable, beta, nightly]
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
@@ -51,6 +61,13 @@ jobs:
command: fmt
args: --all -- --check
- uses: actions-rs/clippy-check@v1
name: Clippy checks
# if: matrix.os == 'ubuntu-latest' && matrix.rust == 'stable'
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
- name: Run clippy
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
@@ -65,78 +82,21 @@ jobs:
with:
command: clean
# BUILD
- name: Build gateway with coconut feature
- name: Build all binaries with coconut enabled
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-gateway --features=coconut
args: --all --features=coconut
- name: Build native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-client --features=coconut
- name: Build socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-socks5-client --features=coconut
- name: Build validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: build
args: --bin nym-validator-api --features=coconut
# TEST
- name: Test gateway with coconut feature
- name: Run all tests with coconut enabled
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-gateway --features=coconut
args: --all --features=coconut
- name: Test native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-client --features=coconut
- name: Test socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-socks5-client --features=coconut
- name: Test validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: test
args: --bin nym-validator-api --features=coconut
# CLIPPY
- name: Run clippy on gateway with coconut feature
- name: Run clippy with coconut enabled
uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --bin nym-gateway --features=coconut -- -D warnings
- name: Run clippy on native client with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-client --features=coconut -- -D warnings
- name: Run clippy on socks5 client with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-socks5-client --features=coconut -- -D warnings
- name: Run clippy on validator-api with coconut feature
uses: actions-rs/cargo@v1
with:
command: clippy
args: --bin nym-validator-api --features=coconut -- -D warnings
args: --features=coconut -- -D warnings
@@ -0,0 +1,50 @@
[
{
"os":"ubuntu-latest",
"rust":"stable",
"runOnEvent":"always"
},
{
"os":"windows-latest",
"rust":"stable",
"runOnEvent":"pull_request"
},
{
"os":"macos-latest",
"rust":"stable",
"runOnEvent":"pull_request"
},
{
"os":"ubuntu-latest",
"rust":"beta",
"runOnEvent":"pull_request"
},
{
"os":"windows-latest",
"rust":"beta",
"runOnEvent":"pull_request"
},
{
"os":"macos-latest",
"rust":"beta",
"runOnEvent":"pull_request"
},
{
"os":"ubuntu-latest",
"rust":"nightly",
"runOnEvent":"pull_request"
},
{
"os":"windows-latest",
"rust":"nightly",
"runOnEvent":"pull_request"
},
{
"os":"macos-latest",
"rust":"nightly",
"runOnEvent":"pull_request"
}
]
-17
View File
@@ -1,17 +0,0 @@
name: Clippy check
on:
push:
paths-ignore:
- 'explorer/**'
jobs:
clippy_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: rustup component add clippy
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features
@@ -0,0 +1,14 @@
[
{
"rust":"stable",
"runOnEvent":"always"
},
{
"rust":"beta",
"runOnEvent":"pull_request"
},
{
"rust":"nightly",
"runOnEvent":"pull_request"
}
]
@@ -0,0 +1,58 @@
name: ERC20 Bridge Contract
on: [ push, pull_request ]
jobs:
matrix_prep:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from build_matrix_includes.json
- uses: actions/checkout@v2
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/contract_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
erc20-bridge-contract:
needs: matrix_prep
strategy:
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
# since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.rust == 'nightly' }}
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
target: wasm32-unknown-unknown
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
env:
RUSTFLAGS: '-C link-arg=-s'
with:
command: build
args: --manifest-path contracts/erc20-bridge/Cargo.toml --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path contracts/erc20-bridge/Cargo.toml
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path contracts/erc20-bridge/Cargo.toml -- --check
- uses: actions-rs/cargo@v1
if: ${{ matrix.rust != 'nightly' }}
with:
command: clippy
args: --manifest-path contracts/erc20-bridge/Cargo.toml -- -D warnings
+16 -2
View File
@@ -9,14 +9,26 @@ on:
- 'explorer/**'
jobs:
matrix_prep:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from build_matrix_includes.json
- uses: actions/checkout@v2
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/contract_matrix_includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
mixnet-contract:
# since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.rust == 'nightly' }}
needs: matrix_prep
strategy:
matrix:
rust: [ stable, beta, nightly ]
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
steps:
- uses: actions/checkout@v2
@@ -29,6 +41,8 @@ jobs:
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
env:
RUSTFLAGS: '-C link-arg=-s'
with:
command: build
args: --manifest-path contracts/mixnet/Cargo.toml --target wasm32-unknown-unknown
+1 -1
View File
@@ -11,7 +11,7 @@ defaults:
jobs:
build:
runs-on: ubuntu-latest
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
+1 -1
View File
@@ -11,7 +11,7 @@ defaults:
jobs:
build:
runs-on: ubuntu-latest
runs-on: custom-runner-linux
steps:
- uses: actions/checkout@v2
- name: Install rsync
+1 -1
View File
@@ -11,7 +11,7 @@ on:
jobs:
nym-wallet-types:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
if: ${{ github.event_name != 'pull_request' }}
steps:
- name: Prepare
run: sudo apt-get update && sudo apt-get install -y libpango1.0-dev libatk1.0-dev libgdk-pixbuf2.0-dev libsoup2.4-dev librust-gdk-dev libwebkit2gtk-4.0-dev
+6 -8
View File
@@ -1,9 +1,6 @@
name: Wasm Client
on:
push:
paths-ignore:
- 'explorer/**'
pull_request:
paths-ignore:
- 'explorer/**'
@@ -22,10 +19,11 @@ jobs:
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
# token credentials (non-coconut) don't work for wasm right now
# - uses: actions-rs/cargo@v1
# with:
# command: build
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
- uses: actions-rs/cargo@v1
with:
@@ -47,4 +45,4 @@ jobs:
# - uses: actions-rs/cargo@v1
# with:
# command: clippy
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
+5
View File
@@ -29,3 +29,8 @@ validator-api/v4.json
validator-api/v6.json
**/node_modules
validator-api/keypair
contracts/mixnet/code_id
contracts/mixnet/Justfile
contracts/mixnet/Makefile
validator-config
*.patch
Generated
+379 -1
View File
@@ -93,6 +93,12 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "arrayvec"
version = "0.7.1"
@@ -228,6 +234,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
[[package]]
name = "base-x"
version = "0.2.8"
@@ -296,6 +308,18 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitvec"
version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "blake2"
version = "0.8.1"
@@ -315,7 +339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcd555c66291d5f836dbb6883b48660ece810fe25a31f3bdfb911945dff2691f"
dependencies = [
"arrayref",
"arrayvec",
"arrayvec 0.7.1",
"cc",
"cfg-if 1.0.0",
"constant_time_eq",
@@ -405,12 +429,24 @@ version = "3.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
[[package]]
name = "byte-slice-cast"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca0796d76a983651b4a0ddda16203032759f2fd9103d9181f7c65c06ee8872e6"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -943,6 +979,8 @@ name = "credentials"
version = "0.1.0"
dependencies = [
"coconut-interface",
"crypto",
"network-defaults",
"thiserror",
"url",
"validator-client",
@@ -1538,6 +1576,14 @@ dependencies = [
"termcolor",
]
[[package]]
name = "erc20-bridge-contract"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
]
[[package]]
name = "error-chain"
version = "0.12.4"
@@ -1547,6 +1593,49 @@ dependencies = [
"version_check",
]
[[package]]
name = "ethabi"
version = "14.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01317735d563b3bad2d5f90d2e1799f414165408251abb762510f40e790e69a"
dependencies = [
"anyhow",
"ethereum-types",
"hex",
"serde",
"serde_json",
"sha3",
"thiserror",
"uint",
]
[[package]]
name = "ethbloom"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8"
dependencies = [
"crunchy",
"fixed-hash",
"impl-rlp",
"impl-serde",
"tiny-keccak",
]
[[package]]
name = "ethereum-types"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64b5df66a228d85e4b17e5d6c6aa43b0310898ffe8a85988c4c032357aaabfd"
dependencies = [
"ethbloom",
"fixed-hash",
"impl-rlp",
"impl-serde",
"primitive-types",
"uint",
]
[[package]]
name = "explorer-api"
version = "0.1.0"
@@ -1642,6 +1731,30 @@ dependencies = [
"winapi",
]
[[package]]
name = "fixed"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d333a26ec13a023c6dff4b7584de4d323cfee2e508f5dd2bbee6669e4f7efdf"
dependencies = [
"az",
"bytemuck",
"half",
"typenum",
]
[[package]]
name = "fixed-hash"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c"
dependencies = [
"byteorder",
"rand 0.8.4",
"rustc-hex",
"static_assertions",
]
[[package]]
name = "flate2"
version = "1.0.22"
@@ -1738,6 +1851,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "funty"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
[[package]]
name = "futf"
version = "0.1.4"
@@ -1847,6 +1966,12 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
[[package]]
name = "futures-timer"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]]
name = "futures-util"
version = "0.3.17"
@@ -1882,20 +2007,27 @@ name = "gateway-client"
version = "0.1.0"
dependencies = [
"coconut-interface",
"credentials",
"crypto",
"fluvio-wasm-timer",
"futures",
"gateway-requests",
"getrandom 0.2.3",
"json",
"log",
"network-defaults",
"nymsphinx",
"rand 0.7.3",
"secp256k1",
"thiserror",
"tokio",
"tokio-tungstenite",
"tungstenite",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-utils",
"web3",
]
[[package]]
@@ -2271,6 +2403,12 @@ dependencies = [
"tracing",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "handlebars"
version = "3.5.5"
@@ -2352,6 +2490,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hex-literal"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b"
[[package]]
name = "hkd32"
version = "0.6.0"
@@ -2583,6 +2727,44 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "impl-codec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443"
dependencies = [
"parity-scale-codec",
]
[[package]]
name = "impl-rlp"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808"
dependencies = [
"rlp",
]
[[package]]
name = "impl-serde"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f"
dependencies = [
"serde",
]
[[package]]
name = "impl-trait-for-tuples"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5dacb10c5b3bb92d46ba347505a9041e676bb20ad220101326bffb0c93031ee"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "indenter"
version = "0.3.3"
@@ -2741,6 +2923,27 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
[[package]]
name = "jsonrpc-core"
version = "18.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb"
dependencies = [
"futures",
"futures-executor",
"futures-util",
"log",
"serde",
"serde_derive",
"serde_json",
]
[[package]]
name = "k256"
version = "0.9.6"
@@ -2986,10 +3189,15 @@ dependencies = [
name = "mixnet-contract"
version = "0.1.0"
dependencies = [
"az",
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
"thiserror",
"ts-rs",
]
@@ -3107,6 +3315,7 @@ checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d"
name = "network-defaults"
version = "0.1.0"
dependencies = [
"hex-literal",
"serde",
"time 0.3.3",
"url",
@@ -3299,6 +3508,7 @@ dependencies = [
name = "nym-gateway"
version = "0.11.0"
dependencies = [
"bip39",
"clap",
"coconut-interface",
"config",
@@ -3307,12 +3517,15 @@ dependencies = [
"dashmap",
"dirs",
"dotenv",
"erc20-bridge-contract",
"futures",
"gateway-client",
"gateway-requests",
"humantime-serde",
"log",
"mixnet-client",
"mixnode-common",
"network-defaults",
"nymsphinx",
"pemstore",
"pretty_env_logger",
@@ -3327,6 +3540,7 @@ dependencies = [
"url",
"validator-client",
"version-checker",
"web3",
]
[[package]]
@@ -3438,6 +3652,8 @@ dependencies = [
"pin-project",
"pretty_env_logger",
"rand 0.7.3",
"rand 0.8.4",
"rand_chacha 0.3.1",
"reqwest",
"rocket",
"rocket_cors",
@@ -3713,6 +3929,32 @@ dependencies = [
"system-deps 3.2.0",
]
[[package]]
name = "parity-scale-codec"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909"
dependencies = [
"arrayvec 0.7.1",
"bitvec",
"byte-slice-cast",
"impl-trait-for-tuples",
"parity-scale-codec-derive",
"serde",
]
[[package]]
name = "parity-scale-codec-derive"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27"
dependencies = [
"proc-macro-crate 1.1.0",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "parking"
version = "2.0.0"
@@ -4079,6 +4321,19 @@ dependencies = [
"log",
]
[[package]]
name = "primitive-types"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06345ee39fbccfb06ab45f3a1a5798d9dafa04cb8921a76d227040003a234b0e"
dependencies = [
"fixed-hash",
"impl-codec",
"impl-rlp",
"impl-serde",
"uint",
]
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
@@ -4249,6 +4504,12 @@ dependencies = [
"scheduled-thread-pool",
]
[[package]]
name = "radium"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
[[package]]
name = "rand"
version = "0.6.5"
@@ -4648,6 +4909,16 @@ dependencies = [
"opaque-debug 0.3.0",
]
[[package]]
name = "rlp"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5"
dependencies = [
"bytes",
"rustc-hex",
]
[[package]]
name = "rocket"
version = "0.5.0-rc.1"
@@ -4796,6 +5067,12 @@ dependencies = [
"quote",
]
[[package]]
name = "rustc-hex"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
[[package]]
name = "rustc_version"
version = "0.2.3"
@@ -4926,6 +5203,24 @@ dependencies = [
"untrusted",
]
[[package]]
name = "secp256k1"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a"
dependencies = [
"secp256k1-sys",
]
[[package]]
name = "secp256k1-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "827cb7cce42533829c792fc51b82fbf18b125b45a702ef2c8be77fce65463a7b"
dependencies = [
"cc",
]
[[package]]
name = "security-framework"
version = "2.4.2"
@@ -5292,6 +5587,21 @@ dependencies = [
"ordered-buffer",
]
[[package]]
name = "soketto"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4919971d141dbadaa0e82b5d369e2d7666c98e4625046140615ca363e50d4daa"
dependencies = [
"base64",
"bytes",
"futures",
"httparse",
"log",
"rand 0.8.4",
"sha-1 0.9.8",
]
[[package]]
name = "soup-sys"
version = "0.10.0"
@@ -5891,6 +6201,12 @@ dependencies = [
"x11-dl",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tar"
version = "0.4.37"
@@ -6283,6 +6599,15 @@ dependencies = [
"syn",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tokio"
version = "1.12.0"
@@ -6380,6 +6705,7 @@ checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd"
dependencies = [
"bytes",
"futures-core",
"futures-io",
"futures-sink",
"log",
"pin-project-lite",
@@ -6851,6 +7177,52 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "web3"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd24abe6f2b68e0677f843059faea87bcbd4892e39f02886f366d8222c3c540d"
dependencies = [
"arrayvec 0.5.2",
"base64",
"bytes",
"derive_more",
"ethabi",
"ethereum-types",
"futures",
"futures-timer",
"headers",
"hex",
"jsonrpc-core",
"log",
"parking_lot",
"pin-project",
"reqwest",
"rlp",
"secp256k1",
"serde",
"serde_json",
"soketto",
"tiny-keccak",
"tokio",
"tokio-stream",
"tokio-util",
"url",
"web3-async-native-tls",
]
[[package]]
name = "web3-async-native-tls"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f6d8d1636b2627fe63518d5a9b38a569405d9c9bc665c43c9c341de57227ebb"
dependencies = [
"native-tls",
"thiserror",
"tokio",
"url",
]
[[package]]
name = "webkit2gtk"
version = "0.14.0"
@@ -7061,6 +7433,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "wyz"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "x11-dl"
version = "2.19.1"
+2 -1
View File
@@ -25,6 +25,7 @@ members = [
"common/config",
"common/credentials",
"common/crypto",
"common/erc20-bridge-contract",
"common/mixnet-contract",
"common/mixnode-common",
"common/network-defaults",
@@ -62,4 +63,4 @@ default-members = [
"validator-api",
]
exclude = ["explorer", "contracts"]
exclude = ["explorer", "contracts", "tokenomics-py"]
+39 -2
View File
@@ -5,8 +5,6 @@ SPDX-License-Identifier: Apache-2.0
## The Nym Privacy Platform
This repository contains the Nym mixnet.
The platform is composed of multiple Rust crates. Top-level executable binary crates include:
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
@@ -33,6 +31,45 @@ There's a `.env.sample-dev` file provided which you can rename to `.env` if you
You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel.
### Rewards
Node, node operator and delegator rewards are determined according to the principles laid out in the section 6 of [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf). Below is a TLDR of the variables and formulas involved in calculating the epoch rewards. Initial reward pool is set to 250 million Nym, making the circulating supply 750 million Nym.
|Symbol|Definition|
|---|---|
|<img src="https://render.githubusercontent.com/render/math?math=R">|global share of rewards available, starts at 2% of the reward pool.
|<img src="https://render.githubusercontent.com/render/math?math=R_{i}">|node reward for mixnode `i`.
|<img src="https://render.githubusercontent.com/render/math?math=\sigma_{i}">|ratio of total node stake (node bond + all delegations) to the token circulating supply.
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}">|ratio of stake operator has plaged to their node to the token circulating supply.
|<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}">|fraction of total effort undertaken by node `i`, set to `1/k` in testnet Milhon.
|<img src="https://render.githubusercontent.com/render/math?math=k">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `active set` size, and set to 5000 in testnet Milhon.
|<img src="https://render.githubusercontent.com/render/math?math=\alpha">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitivness gets for a Sybil attacker.
|<img src="https://render.githubusercontent.com/render/math?math=PM_{i}">|declared profit margin of operator `i`, defaults to 10% in testnet Milhon.
|<img src="https://render.githubusercontent.com/render/math?math=PF_{i}">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch
|<img src="https://render.githubusercontent.com/render/math?math=PP_{i}">|cost of operating node `i` for the duration of the rewarding eopoch, set to 40 Nym for testnet Milhon.
Node reward for node `i` is determined as:
<img src="https://render.githubusercontent.com/render/math?math=R_{i}=PF_{i} \cdot R \cdot (\sigma^'_{i} \cdot \omega_{i} \cdot k %2b \alpha \cdot \lambda^'_{i} \cdot \sigma^'_{i} \cdot k)/(1 %2b \alpha)">
where:
<img src="https://render.githubusercontent.com/render/math?math=\sigma^'_{i} = min\{\sigma_{i}, 1/k\}">
and
<img src="https://render.githubusercontent.com/render/math?math=\lambda^'_{i} = min\{\lambda_{i}, 1/k\}">
Operator of node `i` is credited with the following amount:
<img src="https://render.githubusercontent.com/render/math?math=min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}">
Delegate with stake `s` recieves:
<img src="https://render.githubusercontent.com/render/math?math=max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}">
where `s'` is stake `s` scaled over total token circulating supply.
### Licensing and copyright information
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
+3
View File
@@ -30,3 +30,6 @@ validator-client = { path = "../../common/client-libs/validator-client" }
[dev-dependencies]
tempfile = "3.1.0"
[features]
coconut = []
+65 -1
View File
@@ -22,7 +22,10 @@ const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20)
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500);
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
// bandwidth bridging protocol, we can come back to a smaller timeout value
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
pub fn missing_string_value() -> String {
MISSING_VALUE.to_string()
@@ -100,6 +103,17 @@ impl<T: NymConfig> Config<T> {
self::Client::<T>::default_reply_encryption_key_store_path(&id);
}
#[cfg(not(feature = "coconut"))]
if self
.client
.backup_bandwidth_token_keys_dir
.as_os_str()
.is_empty()
{
self.client.backup_bandwidth_token_keys_dir =
self::Client::<T>::default_backup_bandwidth_token_keys_dir(&id);
}
self.client.id = id;
}
@@ -111,6 +125,16 @@ impl<T: NymConfig> Config<T> {
self.client.gateway_listener = gateway_listener.into();
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_private_key<S: Into<String>>(&mut self, eth_private_key: S) {
self.client.eth_private_key = eth_private_key.into();
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_endpoint<S: Into<String>>(&mut self, eth_endpoint: S) {
self.client.eth_endpoint = eth_endpoint.into();
}
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
self.client.validator_api_urls = validator_api_urls;
}
@@ -173,6 +197,21 @@ impl<T: NymConfig> Config<T> {
self.client.gateway_listener.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_backup_bandwidth_token_keys_dir(&self) -> PathBuf {
self.client.backup_bandwidth_token_keys_dir.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_eth_endpoint(&self) -> String {
self.client.eth_endpoint.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_eth_private_key(&self) -> String {
self.client.eth_private_key.clone()
}
// Debug getters
pub fn get_average_packet_delay(&self) -> Duration {
self.debug.average_packet_delay
@@ -268,6 +307,20 @@ pub struct Client<T> {
/// Address of the gateway listener to which all client requests should be sent.
gateway_listener: String,
/// Path to directory containing public/private keys used for bandwidth token purchase.
/// Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
/// The public key is the name of the file, while the private key is the content.
#[cfg(not(feature = "coconut"))]
backup_bandwidth_token_keys_dir: PathBuf,
/// Ethereum private key.
#[cfg(not(feature = "coconut"))]
eth_private_key: String,
/// Address to an Ethereum full node.
#[cfg(not(feature = "coconut"))]
eth_endpoint: String,
/// nym_home_directory specifies absolute path to the home nym Clients directory.
/// It is expected to use default value and hence .toml file should not redefine this field.
nym_root_directory: PathBuf,
@@ -292,6 +345,12 @@ impl<T: NymConfig> Default for Client<T> {
reply_encryption_key_store_path: Default::default(),
gateway_id: "".to_string(),
gateway_listener: "".to_string(),
#[cfg(not(feature = "coconut"))]
backup_bandwidth_token_keys_dir: Default::default(),
#[cfg(not(feature = "coconut"))]
eth_private_key: "".to_string(),
#[cfg(not(feature = "coconut"))]
eth_endpoint: "".to_string(),
nym_root_directory: T::default_root_directory(),
super_struct: Default::default(),
}
@@ -326,6 +385,11 @@ impl<T: NymConfig> Client<T> {
fn default_reply_encryption_key_store_path(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("reply_key_store")
}
#[cfg(not(feature = "coconut"))]
fn default_backup_bandwidth_token_keys_dir(id: &str) -> PathBuf {
T::default_data_directory(Some(id)).join("backup_bandwidth_token_keys")
}
}
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
@@ -42,6 +42,17 @@ public_encryption_key_file = '{{ client.public_encryption_key_file }}'
# sent but not received back.
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
# Path to directory containing public/private keys used for bandwidth token purchase.
# Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
# The public key is the name of the file, while the private key is the content.
backup_bandwidth_token_keys_dir = '{{ client.backup_bandwidth_token_keys_dir }}'
# Ethereum private key.
eth_private_key = '{{ client.eth_private_key }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ client.eth_endpoint }}'
##### additional client config options #####
# ID of the gateway from which the client should be fetching messages.
+14 -34
View File
@@ -35,10 +35,7 @@ use nymsphinx::anonymous_replies::ReplySurb;
use nymsphinx::receiver::ReconstructedMessage;
use tokio::runtime::Runtime;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(feature = "coconut")]
use credentials::{bandwidth::prepare_for_spending, obtain_aggregate_verification_key};
use gateway_client::bandwidth::BandwidthController;
pub(crate) mod config;
@@ -168,31 +165,6 @@ impl NymClient {
.start(self.runtime.handle())
}
#[cfg(feature = "coconut")]
async fn prepare_coconut_credential(&self) -> Credential {
let verification_key = obtain_aggregate_verification_key(
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential = credentials::bandwidth::obtain_signature(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain bandwidth credential");
// the above would presumably be loaded from a file
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
prepare_for_spending(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&bandwidth_credential,
&verification_key,
)
.expect("could not prepare out bandwidth credential for spending")
}
fn start_gateway_client(
&mut self,
mixnet_message_sender: MixnetMessageSender,
@@ -212,7 +184,17 @@ impl NymClient {
self.runtime.block_on(async {
#[cfg(feature = "coconut")]
let coconut_credential = self.prepare_coconut_credential().await;
let bandwidth_controller = BandwidthController::new(
self.config.get_base().get_validator_api_endpoints(),
*self.key_manager.identity_keypair().public_key(),
);
#[cfg(not(feature = "coconut"))]
let bandwidth_controller = BandwidthController::new(
self.config.get_base().get_eth_endpoint(),
self.config.get_base().get_eth_private_key(),
self.config.get_base().get_backup_bandwidth_token_keys_dir(),
)
.expect("Could not create bandwidth controller");
let mut gateway_client = GatewayClient::new(
gateway_address,
@@ -222,13 +204,11 @@ impl NymClient {
mixnet_message_sender,
ack_sender,
self.config.get_base().get_gateway_response_timeout(),
Some(bandwidth_controller),
);
gateway_client
.authenticate_and_start(
#[cfg(feature = "coconut")]
Some(coconut_credential),
)
.authenticate_and_start()
.await
.expect("could not authenticate and start up the gateway connection");
+16 -2
View File
@@ -22,7 +22,7 @@ use topology::{filter::VersionFilterable, gateway};
use url::Url;
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
App::new("init")
let app = App::new("init")
.about("Initialise a Nym client. Do this first!")
.arg(Arg::with_name("id")
.long("id")
@@ -54,7 +54,21 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.long("fastmode")
.hidden(true) // this will prevent this flag from being displayed in `--help`
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
)
);
#[cfg(not(feature = "coconut"))]
let app = app
.arg(Arg::with_name("eth_endpoint")
.long("eth_endpoint")
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.takes_value(true)
.required(true))
.arg(Arg::with_name("eth_private_key")
.long("eth_private_key")
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true)
.required(true));
app
}
async fn register_with_gateway(
+9
View File
@@ -43,5 +43,14 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
config = config.with_port(port.unwrap());
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_private_key) = matches.value_of("eth_private_key") {
config.get_base_mut().with_eth_private_key(eth_private_key);
}
config
}
+14 -2
View File
@@ -10,7 +10,7 @@ use log::*;
use version_checker::is_minor_version_compatible;
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
App::new("run")
let app = App::new("run")
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
.arg(Arg::with_name("id")
.long("id")
@@ -38,7 +38,19 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.long("port")
.help("Port for the socket (if applicable) to listen on")
.takes_value(true)
)
);
#[cfg(not(feature = "coconut"))]
let app = app
.arg(Arg::with_name("eth_endpoint")
.long("eth_endpoint")
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.takes_value(true))
.arg(Arg::with_name("eth_private_key")
.long("eth_private_key")
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true));
app
}
// this only checks compatibility between config the binary. It does not take into consideration
@@ -42,6 +42,17 @@ public_encryption_key_file = '{{ client.public_encryption_key_file }}'
# sent but not received back.
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
# Path to directory containing public/private keys used for bandwidth token purchase.
# Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
# The public key is the name of the file, while the private key is the content.
backup_bandwidth_token_keys_dir = '{{ client.backup_bandwidth_token_keys_dir }}'
# Ethereum private key.
eth_private_key = '{{ client.eth_private_key }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ client.eth_endpoint }}'
##### additional client config options #####
# ID of the gateway from which the client should be fetching messages.
+14 -34
View File
@@ -34,10 +34,7 @@ use nymsphinx::addressing::clients::Recipient;
use nymsphinx::addressing::nodes::NodeIdentity;
use tokio::runtime::Runtime;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(feature = "coconut")]
use credentials::{bandwidth::prepare_for_spending, obtain_aggregate_verification_key};
use gateway_client::bandwidth::BandwidthController;
pub(crate) mod config;
@@ -156,31 +153,6 @@ impl NymClient {
.start(self.runtime.handle())
}
#[cfg(feature = "coconut")]
async fn prepare_coconut_credential(&self) -> Credential {
let verification_key = obtain_aggregate_verification_key(
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential = credentials::bandwidth::obtain_signature(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&self.config.get_base().get_validator_api_endpoints(),
)
.await
.expect("could not obtain bandwidth credential");
// the above would presumably be loaded from a file
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
prepare_for_spending(
&self.key_manager.identity_keypair().public_key().to_bytes(),
&bandwidth_credential,
&verification_key,
)
.expect("could not prepare out bandwidth credential for spending")
}
fn start_gateway_client(
&mut self,
mixnet_message_sender: MixnetMessageSender,
@@ -200,7 +172,17 @@ impl NymClient {
self.runtime.block_on(async {
#[cfg(feature = "coconut")]
let coconut_credential = self.prepare_coconut_credential().await;
let bandwidth_controller = BandwidthController::new(
self.config.get_base().get_validator_api_endpoints(),
*self.key_manager.identity_keypair().public_key(),
);
#[cfg(not(feature = "coconut"))]
let bandwidth_controller = BandwidthController::new(
self.config.get_base().get_eth_endpoint(),
self.config.get_base().get_eth_private_key(),
self.config.get_base().get_backup_bandwidth_token_keys_dir(),
)
.expect("Could not create bandwidth controller");
let mut gateway_client = GatewayClient::new(
gateway_address,
@@ -210,13 +192,11 @@ impl NymClient {
mixnet_message_sender,
ack_sender,
self.config.get_base().get_gateway_response_timeout(),
Some(bandwidth_controller),
);
gateway_client
.authenticate_and_start(
#[cfg(feature = "coconut")]
Some(coconut_credential),
)
.authenticate_and_start()
.await
.expect("could not authenticate and start up the gateway connection");
+16 -2
View File
@@ -20,7 +20,7 @@ use topology::{filter::VersionFilterable, gateway};
use url::Url;
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
App::new("init")
let app = App::new("init")
.about("Initialise a Nym client. Do this first!")
.arg(Arg::with_name("id")
.long("id")
@@ -54,7 +54,21 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.long("fastmode")
.hidden(true) // this will prevent this flag from being displayed in `--help`
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
)
);
#[cfg(not(feature = "coconut"))]
let app = app
.arg(Arg::with_name("eth_endpoint")
.long("eth_endpoint")
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.takes_value(true)
.required(true))
.arg(Arg::with_name("eth_private_key")
.long("eth_private_key")
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true)
.required(true));
app
}
async fn register_with_gateway(
+9
View File
@@ -39,5 +39,14 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
config = config.with_port(port.unwrap());
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
config.get_base_mut().with_eth_endpoint(eth_endpoint);
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_private_key) = matches.value_of("eth_private_key") {
config.get_base_mut().with_eth_private_key(eth_private_key);
}
config
}
+14 -2
View File
@@ -10,7 +10,7 @@ use log::*;
use version_checker::is_minor_version_compatible;
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
App::new("run")
let app = App::new("run")
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
.arg(Arg::with_name("id")
.long("id")
@@ -44,7 +44,19 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.long("port")
.help("Port for the socket to listen on")
.takes_value(true)
)
);
#[cfg(not(feature = "coconut"))]
let app = app
.arg(Arg::with_name("eth_endpoint")
.long("eth_endpoint")
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.takes_value(true))
.arg(Arg::with_name("eth_private_key")
.long("eth_private_key")
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
.takes_value(true));
app
}
// this only checks compatibility between config the binary. It does not take into consideration
+9 -34
View File
@@ -17,10 +17,7 @@ use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use wasm_utils::{console_log, console_warn};
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(feature = "coconut")]
use credentials::{bandwidth::prepare_for_spending, obtain_aggregate_verification_key};
use gateway_client::bandwidth::BandwidthController;
pub(crate) mod received_processor;
@@ -103,35 +100,15 @@ impl NymClient {
self.self_recipient().to_string()
}
#[cfg(feature = "coconut")]
async fn prepare_coconut_credential(validators: &[Url], identity_bytes: &[u8]) -> Credential {
let verification_key = obtain_aggregate_verification_key(validators)
.await
.expect("could not obtain aggregate verification key of validators");
let bandwidth_credential =
credentials::bandwidth::obtain_signature(identity_bytes, validators)
.await
.expect("could not obtain bandwidth credential");
// the above would presumably be loaded from a file
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
prepare_for_spending(identity_bytes, &bandwidth_credential, &verification_key)
.expect("could not prepare out bandwidth credential for spending")
}
// Right now it's impossible to have async exported functions to take `&self` rather than self
pub async fn initial_setup(self) -> Self {
#[cfg(feature = "coconut")]
let coconut_credential = {
let validator_server = self.validator_server.clone();
let identity_public_key = self.identity.public_key().clone();
Self::prepare_coconut_credential(
&vec![validator_server],
&identity_public_key.to_bytes(),
)
.await
};
let bandwidth_controller = Some(BandwidthController::new(
vec![self.validator_server.clone()],
*self.identity.public_key(),
));
#[cfg(not(feature = "coconut"))]
let bandwidth_controller = None;
let mut client = self.get_and_update_topology().await;
let gateway = client.choose_gateway();
@@ -147,13 +124,11 @@ impl NymClient {
mixnet_messages_sender,
ack_sender,
DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
bandwidth_controller,
);
gateway_client
.authenticate_and_start(
#[cfg(feature = "coconut")]
Some(coconut_credential),
)
.authenticate_and_start()
.await
.expect("could not authenticate and start up the gateway connection");
@@ -10,14 +10,19 @@ edition = "2018"
# TODO: (for this and other crates), similarly to 'tokio', import only required "futures" modules rather than
# the entire crate
futures = "0.3"
json = "0.12.4"
log = "0.4"
thiserror = "1.0"
url = "2.2"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
# internal
credentials = { path = "../../credentials" }
crypto = { path = "../../crypto" }
gateway-requests = { path = "../../../gateway/gateway-requests" }
nymsphinx = { path = "../../nymsphinx" }
coconut-interface = { path = "../../coconut-interface", optional = true }
network-defaults = { path = "../../network-defaults" }
[dependencies.tungstenite]
version = "0.13"
@@ -31,6 +36,12 @@ features = ["macros", "rt", "net", "sync", "time"]
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-tungstenite]
version = "0.14"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.secp256k1]
version = "0.20.3"
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.web3]
version = "0.17.0"
# wasm-only dependencies
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen]
version = "0.2"
@@ -0,0 +1,226 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::GatewayClientError;
#[cfg(feature = "coconut")]
use credentials::coconut::{
bandwidth::{obtain_signature, prepare_for_spending},
utils::obtain_aggregate_verification_key,
};
#[cfg(not(feature = "coconut"))]
use credentials::token::bandwidth::TokenCredential;
#[cfg(not(feature = "coconut"))]
use crypto::asymmetric::identity;
use crypto::asymmetric::identity::PublicKey;
#[cfg(not(feature = "coconut"))]
use network_defaults::{
eth_contract::ETH_JSON_ABI, BANDWIDTH_VALUE, ETH_BURN_FUNCTION_NAME, ETH_CONTRACT_ADDRESS,
ETH_MIN_BLOCK_DEPTH, TOKENS_TO_BURN,
};
#[cfg(not(feature = "coconut"))]
use rand::rngs::OsRng;
#[cfg(not(feature = "coconut"))]
use secp256k1::SecretKey;
#[cfg(not(feature = "coconut"))]
use std::io::Write;
#[cfg(not(feature = "coconut"))]
use std::str::FromStr;
#[cfg(not(feature = "coconut"))]
use web3::{
contract::{Contract, Options},
transports::Http,
types::{Address, Bytes, U256, U64},
Web3,
};
#[cfg(not(feature = "coconut"))]
pub fn eth_contract(web3: Web3<Http>) -> Contract<Http> {
Contract::from_json(
web3.eth(),
Address::from(ETH_CONTRACT_ADDRESS),
json::parse(ETH_JSON_ABI)
.expect("Invalid json abi")
.dump()
.as_bytes(),
)
.expect("Invalid json abi")
}
#[derive(Clone)]
pub struct BandwidthController {
#[cfg(feature = "coconut")]
validator_endpoints: Vec<url::Url>,
#[cfg(feature = "coconut")]
identity: PublicKey,
#[cfg(not(feature = "coconut"))]
contract: Contract<Http>,
#[cfg(not(feature = "coconut"))]
eth_private_key: SecretKey,
#[cfg(not(feature = "coconut"))]
backup_bandwidth_token_keys_dir: std::path::PathBuf,
}
impl BandwidthController {
#[cfg(feature = "coconut")]
pub fn new(validator_endpoints: Vec<url::Url>, identity: PublicKey) -> Self {
BandwidthController {
validator_endpoints,
identity,
}
}
#[cfg(not(feature = "coconut"))]
pub fn new(
eth_endpoint: String,
eth_private_key: String,
backup_bandwidth_token_keys_dir: std::path::PathBuf,
) -> Result<Self, GatewayClientError> {
// Fail early, on invalid url
let transport =
Http::new(&eth_endpoint).map_err(|_| GatewayClientError::InvalidURL(eth_endpoint))?;
let web3 = web3::Web3::new(transport);
// Fail early, on invalid abi
let contract = eth_contract(web3);
let eth_private_key = secp256k1::SecretKey::from_str(&eth_private_key)
.map_err(|_| GatewayClientError::InvalidEthereumPrivateKey)?;
Ok(BandwidthController {
contract,
eth_private_key,
backup_bandwidth_token_keys_dir,
})
}
#[cfg(not(feature = "coconut"))]
fn backup_keypair(&self, keypair: &identity::KeyPair) -> Result<(), GatewayClientError> {
std::fs::create_dir_all(&self.backup_bandwidth_token_keys_dir)?;
let file_path = self
.backup_bandwidth_token_keys_dir
.join(keypair.public_key().to_base58_string());
let mut file = std::fs::File::create(file_path)?;
file.write_all(&keypair.private_key().to_bytes())?;
Ok(())
}
#[cfg(feature = "coconut")]
pub async fn prepare_coconut_credential(
&self,
) -> Result<coconut_interface::Credential, GatewayClientError> {
let verification_key = obtain_aggregate_verification_key(&self.validator_endpoints).await?;
let bandwidth_credential =
obtain_signature(&self.identity.to_bytes(), &self.validator_endpoints).await?;
// the above would presumably be loaded from a file
// the below would only be executed once we know where we want to spend it (i.e. which gateway and stuff)
Ok(prepare_for_spending(
&self.identity.to_bytes(),
&bandwidth_credential,
&verification_key,
)?)
}
#[cfg(not(feature = "coconut"))]
pub async fn prepare_token_credential(
&self,
gateway_identity: PublicKey,
) -> Result<TokenCredential, GatewayClientError> {
let mut rng = OsRng;
let kp = identity::KeyPair::new(&mut rng);
self.backup_keypair(&kp)?;
let verification_key = *kp.public_key();
let signed_verification_key = kp.private_key().sign(&verification_key.to_bytes());
self.buy_token_credential(verification_key, signed_verification_key)
.await?;
let message: Vec<u8> = verification_key
.to_bytes()
.iter()
.chain(gateway_identity.to_bytes().iter())
.copied()
.collect();
let signature = kp.private_key().sign(&message);
Ok(TokenCredential::new(
verification_key,
gateway_identity,
BANDWIDTH_VALUE,
signature,
))
}
#[cfg(not(feature = "coconut"))]
pub async fn buy_token_credential(
&self,
verification_key: PublicKey,
signed_verification_key: identity::Signature,
) -> Result<(), GatewayClientError> {
// 0 means a transaction failure, 1 means success
let confirmations = if cfg!(debug_assertions) {
1
} else {
ETH_MIN_BLOCK_DEPTH
};
// 15 seconds per confirmation block + 10 seconds of network overhead
log::info!(
"Waiting for Ethereum transaction. This should take about {} seconds",
confirmations * 15 + 10
);
let recipt = self
.contract
.signed_call_with_confirmations(
ETH_BURN_FUNCTION_NAME,
(
U256::from(TOKENS_TO_BURN),
U256::from(&verification_key.to_bytes()),
Bytes(signed_verification_key.to_bytes().to_vec()),
),
Options::default(),
confirmations,
&self.eth_private_key,
)
.await?;
if Some(U64::from(0)) == recipt.status {
Err(GatewayClientError::BurnTokenError(
web3::Error::InvalidResponse(format!(
"Transaction status is 0 (failure): {:?}",
recipt.logs,
)),
))
} else {
log::info!(
"Bought bandwidth on Ethereum: {} MB",
BANDWIDTH_VALUE / 1024 / 1024
);
Ok(())
}
}
}
#[cfg(not(feature = "coconut"))]
#[cfg(test)]
mod tests {
use super::*;
use network_defaults::ETH_EVENT_NAME;
#[test]
fn parse_contract() {
let transport =
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
let web3 = web3::Web3::new(transport);
// test no panic occurs
eth_contract(web3);
}
#[test]
fn check_event_name_constant_against_abi() {
let transport =
Http::new("https://rinkeby.infura.io/v3/00000000000000000000000000000000").unwrap();
let web3 = web3::Web3::new(transport);
let contract = eth_contract(web3);
assert!(contract.abi().event(ETH_EVENT_NAME).is_ok());
}
}
+97 -58
View File
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::bandwidth::BandwidthController;
use crate::cleanup_socket_message;
use crate::error::GatewayClientError;
use crate::packet_router::PacketRouter;
@@ -8,6 +9,10 @@ pub use crate::packet_router::{
AcknowledgementReceiver, AcknowledgementSender, MixnetMessageReceiver, MixnetMessageSender,
};
use crate::socket_state::{PartiallyDelegated, SocketState};
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(not(feature = "coconut"))]
use credentials::token::bandwidth::TokenCredential;
use crypto::asymmetric::identity;
use futures::{FutureExt, SinkExt, StreamExt};
use gateway_requests::authentication::encrypted_address::EncryptedAddressBytes;
@@ -30,15 +35,11 @@ use fluvio_wasm_timer as wasm_timer;
#[cfg(target_arch = "wasm32")]
use wasm_utils::websocket::JSWebsocket;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
const DEFAULT_RECONNECTION_ATTEMPTS: usize = 10;
const DEFAULT_RECONNECTION_BACKOFF: Duration = Duration::from_secs(5);
pub struct GatewayClient {
authenticated: bool,
#[cfg(feature = "coconut")]
bandwidth_remaining: i64,
gateway_address: String,
gateway_identity: identity::PublicKey,
@@ -47,6 +48,7 @@ pub struct GatewayClient {
connection: SocketState,
packet_router: PacketRouter,
response_timeout_duration: Duration,
bandwidth_controller: Option<BandwidthController>,
// reconnection related variables
/// Specifies whether client should try to reconnect to gateway on connection failure.
@@ -69,20 +71,19 @@ impl GatewayClient {
mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender,
response_timeout_duration: Duration,
bandwidth_controller: Option<BandwidthController>,
) -> Self {
GatewayClient {
authenticated: false,
#[cfg(feature = "coconut")]
bandwidth_remaining: 0,
gateway_address,
gateway_identity,
local_identity,
shared_key,
connection: SocketState::NotConnected,
packet_router: PacketRouter::new(ack_sender, mixnet_message_sender),
response_timeout_duration,
bandwidth_controller,
should_reconnect_on_failure: true,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
@@ -118,10 +119,7 @@ impl GatewayClient {
GatewayClient {
authenticated: false,
#[cfg(feature = "coconut")]
bandwidth_remaining: 0,
gateway_address,
gateway_identity,
local_identity,
@@ -129,6 +127,7 @@ impl GatewayClient {
connection: SocketState::NotConnected,
packet_router,
response_timeout_duration,
bandwidth_controller: None,
should_reconnect_on_failure: false,
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
@@ -139,7 +138,6 @@ impl GatewayClient {
self.gateway_identity
}
#[cfg(feature = "coconut")]
pub fn remaining_bandwidth(&self) -> i64 {
self.bandwidth_remaining
}
@@ -208,14 +206,7 @@ impl GatewayClient {
for i in 1..self.reconnection_attempts {
info!("attempt {}...", i);
if self
.authenticate_and_start(
#[cfg(feature = "coconut")]
None,
)
.await
.is_ok()
{
if self.authenticate_and_start().await.is_ok() {
info!("managed to reconnect!");
return Ok(());
}
@@ -234,13 +225,7 @@ impl GatewayClient {
// final attempt (done separately to be able to return a proper error)
info!("attempt {}", self.reconnection_attempts);
match self
.authenticate_and_start(
#[cfg(feature = "coconut")]
None,
)
.await
{
match self.authenticate_and_start().await {
Ok(_) => {
info!("managed to reconnect!");
Ok(())
@@ -451,8 +436,12 @@ impl GatewayClient {
ClientControlRequest::new_authenticate(self_address, encrypted_address, iv).into();
match self.send_websocket_message(msg).await? {
ServerResponse::Authenticate { status } => {
ServerResponse::Authenticate {
status,
bandwidth_remaining,
} => {
self.authenticated = status;
self.bandwidth_remaining = bandwidth_remaining;
Ok(())
}
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
@@ -478,22 +467,15 @@ impl GatewayClient {
}
#[cfg(feature = "coconut")]
pub async fn claim_coconut_bandwidth(
async fn claim_coconut_bandwidth(
&mut self,
coconut_credential: Credential,
credential: Credential,
) -> Result<(), GatewayClientError> {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
if self.shared_key.is_none() {
return Err(GatewayClientError::NoSharedKeyAvailable);
}
let mut rng = OsRng;
let iv = IV::new_random(&mut rng);
let msg = ClientControlRequest::new_enc_coconut_bandwidth_credential(
&coconut_credential,
&credential,
self.shared_key.as_ref().unwrap(),
iv,
)
@@ -507,7 +489,64 @@ impl GatewayClient {
Ok(())
}
#[cfg(feature = "coconut")]
#[cfg(not(feature = "coconut"))]
async fn claim_token_bandwidth(
&mut self,
credential: TokenCredential,
) -> Result<(), GatewayClientError> {
let mut rng = OsRng;
let iv = IV::new_random(&mut rng);
let msg = ClientControlRequest::new_enc_token_bandwidth_credential(
&credential,
self.shared_key.as_ref().unwrap(),
iv,
)
.into();
self.bandwidth_remaining = match self.send_websocket_message(msg).await? {
ServerResponse::Bandwidth { available_total } => Ok(available_total),
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
_ => Err(GatewayClientError::UnexpectedResponse),
}?;
Ok(())
}
pub async fn claim_bandwidth(&mut self) -> Result<(), GatewayClientError> {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
if self.shared_key.is_none() {
return Err(GatewayClientError::NoSharedKeyAvailable);
}
if self.bandwidth_controller.is_none() {
return Err(GatewayClientError::NoBandwidthControllerAvailable);
}
warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while");
#[cfg(feature = "coconut")]
let credential = self
.bandwidth_controller
.as_ref()
.unwrap()
.prepare_coconut_credential()
.await?;
#[cfg(not(feature = "coconut"))]
let credential = self
.bandwidth_controller
.as_ref()
.unwrap()
.prepare_token_credential(self.gateway_identity)
.await?;
#[cfg(feature = "coconut")]
return self.claim_coconut_bandwidth(credential).await;
#[cfg(not(feature = "coconut"))]
return self.claim_token_bandwidth(credential).await;
}
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
packets
.iter()
@@ -522,9 +561,16 @@ impl GatewayClient {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
#[cfg(feature = "coconut")]
if self.estimate_required_bandwidth(&packets) < self.bandwidth_remaining {
return Err(GatewayClientError::NotEnoughBandwidth);
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
// Try to claim more bandwidth first, and return an error only if that is still not
// enough (the current granularity for bandwidth should be sufficient)
self.claim_bandwidth().await?;
if self.estimate_required_bandwidth(&packets) > self.bandwidth_remaining {
return Err(GatewayClientError::NotEnoughBandwidth(
self.estimate_required_bandwidth(&packets),
self.bandwidth_remaining,
));
}
}
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
@@ -590,9 +636,16 @@ impl GatewayClient {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
#[cfg(feature = "coconut")]
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
return Err(GatewayClientError::NotEnoughBandwidth);
// Try to claim more bandwidth first, and return an error only if that is still not
// enough
self.claim_bandwidth().await?;
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
return Err(GatewayClientError::NotEnoughBandwidth(
mix_packet.sphinx_packet().len() as i64,
self.bandwidth_remaining,
));
}
}
if !self.connection.is_established() {
return Err(GatewayClientError::ConnectionNotEstablished);
@@ -629,10 +682,6 @@ impl GatewayClient {
if !self.authenticated {
return Err(GatewayClientError::NotAuthenticated);
}
#[cfg(feature = "coconut")]
if self.bandwidth_remaining <= 0 {
return Err(GatewayClientError::NotEnoughBandwidth);
}
if self.connection.is_partially_delegated() {
return Ok(());
}
@@ -660,22 +709,12 @@ impl GatewayClient {
Ok(())
}
pub async fn authenticate_and_start(
&mut self,
#[cfg(feature = "coconut")] coconut_credential: Option<Credential>,
) -> Result<Arc<SharedKeys>, GatewayClientError> {
pub async fn authenticate_and_start(&mut self) -> Result<Arc<SharedKeys>, GatewayClientError> {
if !self.connection.is_established() {
self.establish_connection().await?;
}
let shared_key = self.perform_initial_authentication().await?;
#[cfg(feature = "coconut")]
{
if let Some(coconut_credential) = coconut_credential {
self.claim_coconut_bandwidth(coconut_credential).await?;
}
}
// this call is NON-blocking
self.start_listening_for_mixnet_messages()?;
+63 -76
View File
@@ -2,39 +2,83 @@
// SPDX-License-Identifier: Apache-2.0
use gateway_requests::registration::handshake::error::HandshakeError;
use std::fmt::{self, Error, Formatter};
use std::io;
use thiserror::Error;
use tungstenite::Error as WsError;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::JsValue;
#[cfg(not(feature = "coconut"))]
use web3::Error as Web3Error;
#[derive(Debug)]
#[derive(Debug, Error)]
pub enum GatewayClientError {
#[error("Connection to the gateway is not established")]
ConnectionNotEstablished,
#[error("Gateway returned an error response - {0}")]
GatewayError(String),
NetworkError(WsError),
#[error("There was a network error - {0}")]
NetworkError(#[from] WsError),
// TODO: see if `JsValue` is a reasonable type for this
#[cfg(target_arch = "wasm32")]
#[error("There was a network error")]
NetworkErrorWasm(JsValue),
NoSharedKeyAvailable,
ConnectionAbruptlyClosed,
MalformedResponse,
SerializeCredential,
NotAuthenticated,
NotEnoughBandwidth,
UnexpectedResponse,
ConnectionInInvalidState,
RegistrationFailure(HandshakeError),
AuthenticationFailure,
Timeout,
}
#[cfg(not(feature = "coconut"))]
#[error("Could not backup keypair - {0}")]
IOError(#[from] std::io::Error),
impl From<WsError> for GatewayClientError {
fn from(err: WsError) -> Self {
GatewayClientError::NetworkError(err)
}
#[cfg(not(feature = "coconut"))]
#[error("Could not burn ERC20 token in Ethereum smart contract - {0}")]
BurnTokenError(#[from] Web3Error),
#[cfg(not(feature = "coconut"))]
#[error("Invalid Ethereum private key")]
InvalidEthereumPrivateKey,
#[error("Invalid URL - {0}")]
InvalidURL(String),
#[error("No shared key was provided or obtained")]
NoSharedKeyAvailable,
#[error("No bandwidth controller provided")]
NoBandwidthControllerAvailable,
#[error("Credential error - {0}")]
CredentialError(#[from] credentials::error::Error),
#[error("Connection was abruptly closed")]
ConnectionAbruptlyClosed,
#[error("Received response was malformed")]
MalformedResponse,
#[error("Credential could not be serialized")]
SerializeCredential,
#[error("Client is not authenticated")]
NotAuthenticated,
#[error("Client does not have enough bandwidth: estimated {0}, remaining: {1}")]
NotEnoughBandwidth(i64, i64),
#[error("Received an unexpected response")]
UnexpectedResponse,
#[error("Connection is in an invalid state - please send a bug report")]
ConnectionInInvalidState,
#[error("Failed to finish registration handshake - {0}")]
RegistrationFailure(HandshakeError),
#[error("Authentication failure")]
AuthenticationFailure,
#[error("Timed out")]
Timeout,
}
impl GatewayClientError {
@@ -54,60 +98,3 @@ impl GatewayClientError {
}
}
}
#[cfg(target_arch = "wasm32")]
impl From<JsValue> for GatewayClientError {
fn from(err: JsValue) -> Self {
GatewayClientError::NetworkErrorWasm(err)
}
}
// better human readable representation of the error, mostly so that GatewayClientError
// would implement std::error::Error
impl fmt::Display for GatewayClientError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
match self {
GatewayClientError::ConnectionNotEstablished => {
write!(f, "connection to the gateway is not established")
}
GatewayClientError::NoSharedKeyAvailable => {
write!(f, "no shared key was provided or obtained")
}
GatewayClientError::NotAuthenticated => write!(f, "client is not authenticated"),
GatewayClientError::NetworkError(err) => {
write!(f, "there was a network error - {}", err)
}
#[cfg(target_arch = "wasm32")]
GatewayClientError::NetworkErrorWasm(err) => {
write!(f, "there was a network error - {:?}", err)
}
GatewayClientError::ConnectionAbruptlyClosed => {
write!(f, "connection was abruptly closed")
}
GatewayClientError::Timeout => write!(f, "timed out"),
GatewayClientError::MalformedResponse => write!(f, "received response was malformed"),
GatewayClientError::ConnectionInInvalidState => write!(
f,
"connection is in an invalid state - please send a bug report"
),
GatewayClientError::RegistrationFailure(handshake_err) => write!(
f,
"failed to finish registration handshake - {}",
handshake_err
),
GatewayClientError::AuthenticationFailure => write!(f, "authentication failure"),
GatewayClientError::GatewayError(err) => {
write!(f, "gateway returned an error response - {}", err)
}
GatewayClientError::UnexpectedResponse => write!(f, "received an unexpected response"),
GatewayClientError::NotEnoughBandwidth => {
write!(f, "client does not have enough bandwidth")
}
GatewayClientError::SerializeCredential => {
write!(f, "credential could not be serialized")
}
}
}
}
@@ -8,6 +8,7 @@ pub use packet_router::{
};
use tungstenite::{protocol::Message, Error as WsError};
pub mod bandwidth;
pub mod client;
pub mod error;
pub mod packet_router;
@@ -119,7 +119,7 @@ impl PartiallyDelegated {
}
.is_err()
{
panic!("failed to send back `mixnet_receiver_future` result on the oneshot channel")
warn!("failed to send back `mixnet_receiver_future` result on the oneshot channel")
}
};
@@ -10,9 +10,9 @@ use mixnet_contract::StateParams;
use crate::{validator_api, ValidatorClientError};
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
#[cfg(feature = "nymd-client")]
use mixnet_contract::RawDelegationData;
use mixnet_contract::{GatewayBond, MixNodeBond};
#[cfg(feature = "nymd-client")]
use mixnet_contract::{RawDelegationData, RewardingIntervalResponse};
use url::Url;
#[cfg(feature = "nymd-client")]
@@ -172,6 +172,43 @@ impl<C> Client<C> {
Ok(self.nymd.get_state_params().await?)
}
pub async fn get_current_rewarding_interval(
&self,
) -> Result<RewardingIntervalResponse, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_current_rewarding_interval().await?)
}
pub async fn get_reward_pool(&self) -> Result<u128, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_reward_pool().await?.u128())
}
pub async fn get_circulating_supply(&self) -> Result<u128, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_circulating_supply().await?.u128())
}
pub async fn get_sybil_resistance_percent(&self) -> Result<u8, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_sybil_resistance_percent().await?)
}
pub async fn get_epoch_reward_percent(&self) -> Result<u8, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
Ok(self.nymd.get_epoch_reward_percent().await?)
}
// basically handles paging for us
pub async fn get_all_nymd_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
where
@@ -23,10 +23,11 @@ pub enum Operation {
BondGateway,
UnbondGateway,
DelegateToGateway,
UndelegateFromGateway,
UpdateStateParams,
BeginMixnodeRewarding,
FinishMixnodeRewarding,
}
pub(crate) fn calculate_fee(gas_price: &GasPrice, gas_limit: Gas) -> Coin {
@@ -43,13 +44,13 @@ impl fmt::Display for Operation {
Operation::Send => f.write_str("Send"),
Operation::BondMixnode => f.write_str("BondMixnode"),
Operation::UnbondMixnode => f.write_str("UnbondMixnode"),
Operation::DelegateToMixnode => f.write_str("DelegateToMixnode"),
Operation::UndelegateFromMixnode => f.write_str("UndelegateFromMixnode"),
Operation::BondGateway => f.write_str("BondGateway"),
Operation::UnbondGateway => f.write_str("UnbondGateway"),
Operation::DelegateToGateway => f.write_str("DelegateToGateway"),
Operation::UndelegateFromGateway => f.write_str("UndelegateFromGateway"),
Operation::DelegateToMixnode => f.write_str("DelegateToMixnode"),
Operation::UndelegateFromMixnode => f.write_str("UndelegateFromMixnode"),
Operation::UpdateStateParams => f.write_str("UpdateStateParams"),
Operation::BeginMixnodeRewarding => f.write_str("BeginMixnodeRewarding"),
Operation::FinishMixnodeRewarding => f.write_str("FinishMixnodeRewarding"),
}
}
}
@@ -71,10 +72,10 @@ impl Operation {
Operation::BondGateway => 175_000u64.into(),
Operation::UnbondGateway => 175_000u64.into(),
Operation::DelegateToGateway => 175_000u64.into(),
Operation::UndelegateFromGateway => 175_000u64.into(),
Operation::UpdateStateParams => 175_000u64.into(),
Operation::BeginMixnodeRewarding => 175_000u64.into(),
Operation::FinishMixnodeRewarding => 175_000u64.into(),
}
}
@@ -11,12 +11,13 @@ use crate::nymd::fee_helpers::Operation;
use crate::nymd::wallet::DirectSecp256k1HdWallet;
use cosmrs::rpc::endpoint::broadcast;
use cosmrs::rpc::{Error as TendermintRpcError, HttpClientUrl};
use cosmwasm_std::Coin;
use cosmwasm_std::{Coin, Uint128};
use mixnet_contract::{
Addr, Delegation, ExecuteMsg, Gateway, GatewayOwnershipResponse, IdentityKey,
LayerDistribution, MixNode, MixOwnershipResponse, PagedAllDelegationsResponse,
PagedGatewayResponse, PagedMixDelegationsResponse, PagedMixnodeResponse,
PagedReverseMixDelegationsResponse, QueryMsg, RawDelegationData, StateParams,
PagedReverseMixDelegationsResponse, QueryMsg, RawDelegationData, RewardingIntervalResponse,
StateParams,
};
use serde::Serialize;
use std::collections::HashMap;
@@ -27,10 +28,11 @@ pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
pub use crate::nymd::gas_price::GasPrice;
pub use cosmrs::rpc::HttpClient as QueryNymdClient;
pub use cosmrs::tendermint::block::Height;
pub use cosmrs::tendermint::hash;
pub use cosmrs::tendermint::Time as TendermintTime;
pub use cosmrs::tx::{Fee, Gas};
pub use cosmrs::Coin as CosmosCoin;
pub use cosmrs::{AccountId, Denom};
pub use cosmrs::{AccountId, Decimal, Denom};
pub use signing_client::Client as SigningNymdClient;
pub mod cosmwasm_client;
@@ -184,6 +186,21 @@ impl<C> NymdClient<C> {
self.client.get_height().await
}
/// Obtains the hash of a block specified by the provided height.
///
/// # Arguments
///
/// * `height`: height of the block for which we want to obtain the hash.
pub async fn get_block_hash(&self, height: u32) -> Result<hash::Hash, NymdError>
where
C: CosmWasmClient + Sync,
{
self.client
.get_block(Some(height))
.await
.map(|block| block.block_id.hash)
}
pub async fn get_balance(&self, address: &AccountId) -> Result<Option<CosmosCoin>, NymdError>
where
C: CosmWasmClient + Sync,
@@ -201,6 +218,18 @@ impl<C> NymdClient<C> {
.await
}
pub async fn get_current_rewarding_interval(
&self,
) -> Result<RewardingIntervalResponse, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::CurrentRewardingInterval {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
pub async fn get_layer_distribution(&self) -> Result<LayerDistribution, NymdError>
where
C: CosmWasmClient + Sync,
@@ -211,6 +240,46 @@ impl<C> NymdClient<C> {
.await
}
pub async fn get_reward_pool(&self) -> Result<Uint128, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetRewardPool {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
pub async fn get_circulating_supply(&self) -> Result<Uint128, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetCirculatingSupply {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
pub async fn get_sybil_resistance_percent(&self) -> Result<u8, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetSybilResistancePercent {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
pub async fn get_epoch_reward_percent(&self) -> Result<u8, NymdError>
where
C: CosmWasmClient + Sync,
{
let request = QueryMsg::GetEpochRewardPercent {};
self.client
.query_contract_smart(self.contract_address()?, &request)
.await
}
/// Checks whether there is a bonded mixnode associated with the provided client's address
pub async fn owns_mixnode(&self, address: &AccountId) -> Result<bool, NymdError>
where
@@ -642,6 +711,54 @@ impl<C> NymdClient<C> {
)
.await
}
pub async fn begin_mixnode_rewarding(
&self,
rewarding_interval_nonce: u32,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::BeginMixnodeRewarding);
let req = ExecuteMsg::BeginMixnodeRewarding {
rewarding_interval_nonce,
};
self.client
.execute(
self.address(),
self.contract_address()?,
&req,
fee,
"Beginning mixnode rewarding procedure",
Vec::new(),
)
.await
}
pub async fn finish_mixnode_rewarding(
&self,
rewarding_interval_nonce: u32,
) -> Result<ExecuteResult, NymdError>
where
C: SigningCosmWasmClient + Sync,
{
let fee = self.get_fee(Operation::FinishMixnodeRewarding);
let req = ExecuteMsg::FinishMixnodeRewarding {
rewarding_interval_nonce,
};
self.client
.execute(
self.address(),
self.contract_address()?,
&req,
fee,
"Finishing mixnode rewarding procedure",
Vec::new(),
)
.await
}
}
fn cosmwasm_coin_to_cosmos_coin(coin: Coin) -> CosmosCoin {
+2
View File
@@ -11,4 +11,6 @@ url = "2.2"
# I guess temporarily until we get serde support in coconut up and running
coconut-interface = { path = "../coconut-interface" }
crypto = { path = "../crypto" }
network-defaults = { path = "../network-defaults" }
validator-client = { path = "../client-libs/validator-client" }
@@ -8,11 +8,10 @@
use url::Url;
use super::utils::{obtain_aggregate_signature, prepare_credential_for_spending};
use crate::error::Error;
use crate::utils::{obtain_aggregate_signature, prepare_credential_for_spending};
use coconut_interface::{hash_to_scalar, Credential, Parameters, Signature, VerificationKey};
const BANDWIDTH_VALUE: u64 = 10 * 1024 * 1024 * 1024; // 10 GB
use network_defaults::BANDWIDTH_VALUE;
pub const PUBLIC_ATTRIBUTES: u32 = 1;
pub const PRIVATE_ATTRIBUTES: u32 = 1;
+5
View File
@@ -0,0 +1,5 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod bandwidth;
pub mod utils;
+3 -3
View File
@@ -1,8 +1,8 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod bandwidth;
pub mod coconut;
pub mod error;
mod utils;
pub mod token;
pub use utils::{obtain_aggregate_signature, obtain_aggregate_verification_key};
pub use coconut::utils::{obtain_aggregate_signature, obtain_aggregate_verification_key};
+140
View File
@@ -0,0 +1,140 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crypto::asymmetric::identity::{PublicKey, Signature, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH};
use crate::error::Error;
use std::convert::TryInto;
#[cfg(not(feature = "coconut"))]
pub struct TokenCredential {
verification_key: PublicKey,
gateway_identity: PublicKey,
bandwidth: u64,
signature: Signature,
}
#[cfg(not(feature = "coconut"))]
impl TokenCredential {
pub fn new(
verification_key: PublicKey,
gateway_identity: PublicKey,
bandwidth: u64,
signature: Signature,
) -> Self {
TokenCredential {
verification_key,
gateway_identity,
bandwidth,
signature,
}
}
pub fn verification_key(&self) -> PublicKey {
self.verification_key
}
pub fn gateway_identity(&self) -> PublicKey {
self.gateway_identity
}
pub fn bandwidth(&self) -> u64 {
self.bandwidth
}
pub fn signature_bytes(&self) -> [u8; 64] {
self.signature.to_bytes()
}
pub fn verify_signature(&self) -> bool {
let message: Vec<u8> = self
.verification_key
.to_bytes()
.iter()
.chain(self.gateway_identity.to_bytes().iter())
.copied()
.collect();
self.verification_key
.verify(&message, &self.signature)
.is_ok()
}
pub fn to_bytes(&self) -> Vec<u8> {
self.verification_key
.to_bytes()
.iter()
.chain(self.gateway_identity.to_bytes().iter())
.chain(self.bandwidth.to_be_bytes().iter())
.chain(self.signature.to_bytes().iter())
.copied()
.collect()
}
pub fn from_bytes(b: &[u8]) -> Result<Self, Error> {
if b.len() != 2 * PUBLIC_KEY_LENGTH + 8 + SIGNATURE_LENGTH {
return Err(Error::BandwidthCredentialError);
}
let verification_key = PublicKey::from_bytes(&b[..PUBLIC_KEY_LENGTH])
.map_err(|_| Error::BandwidthCredentialError)?;
let gateway_identity = PublicKey::from_bytes(&b[PUBLIC_KEY_LENGTH..2 * PUBLIC_KEY_LENGTH])
.map_err(|_| Error::BandwidthCredentialError)?;
let bandwidth = u64::from_be_bytes(
b[2 * PUBLIC_KEY_LENGTH..2 * PUBLIC_KEY_LENGTH + 8]
.try_into()
// unwrapping is safe because we know we have 8 bytes
.unwrap(),
);
let signature = Signature::from_bytes(&b[2 * PUBLIC_KEY_LENGTH + 8..])
.map_err(|_| Error::BandwidthCredentialError)?;
Ok(TokenCredential {
verification_key,
gateway_identity,
bandwidth,
signature,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(not(feature = "coconut"))]
#[test]
fn token_serde() {
// pre-generated, valid values
let verification_key = PublicKey::from_bytes(&[
103, 105, 71, 177, 149, 245, 26, 32, 73, 121, 76, 50, 94, 88, 119, 231, 91, 229, 167,
56, 39, 62, 185, 39, 83, 246, 153, 27, 17, 155, 109, 73,
])
.unwrap();
let gateway_identity = PublicKey::from_bytes(&[
37, 113, 137, 189, 157, 82, 35, 2, 187, 136, 61, 119, 98, 5, 245, 82, 46, 124, 67, 45,
165, 255, 53, 222, 185, 252, 6, 148, 128, 15, 206, 19,
])
.unwrap();
let signature = Signature::from_bytes(&[
117, 251, 162, 217, 57, 2, 50, 210, 206, 81, 236, 90, 74, 201, 69, 237, 240, 247, 214,
158, 220, 89, 235, 222, 85, 134, 73, 73, 8, 60, 25, 39, 183, 28, 83, 193, 31, 174, 25,
24, 38, 215, 205, 228, 159, 135, 35, 4, 171, 59, 100, 157, 12, 249, 77, 52, 143, 4, 32,
28, 147, 70, 182, 14,
])
.unwrap();
let credential = TokenCredential::new(verification_key, gateway_identity, 1024, signature);
let serialized_credential = credential.to_bytes();
let deserialized_credential = TokenCredential::from_bytes(&serialized_credential).unwrap();
assert_eq!(
credential.verification_key,
deserialized_credential.verification_key
);
assert_eq!(
credential.gateway_identity,
deserialized_credential.gateway_identity
);
assert_eq!(credential.bandwidth, deserialized_credential.bandwidth);
assert_eq!(
credential.signature.to_bytes(),
deserialized_credential.signature.to_bytes()
);
}
}
+4
View File
@@ -0,0 +1,4 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod bandwidth;
+10
View File
@@ -0,0 +1,10 @@
[package]
name = "erc20-bridge-contract"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
+45
View File
@@ -0,0 +1,45 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
// Serializable structures for what we find in common/crypto
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, JsonSchema)]
pub struct PublicKey([u8; 32]);
impl PublicKey {
pub fn new(bytes: [u8; 32]) -> Self {
PublicKey(bytes)
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
}
impl AsRef<[u8]> for PublicKey {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Signature([u8; 32], [u8; 32]);
impl Signature {
pub fn new(bytes: [u8; 64]) -> Self {
let mut sig1 = [0u8; 32];
let mut sig2 = [0u8; 32];
sig1.copy_from_slice(&bytes[..32]);
sig2.copy_from_slice(&bytes[32..]);
Signature(sig1, sig2)
}
pub fn to_bytes(&self) -> [u8; 64] {
let mut res = [0u8; 64];
res[..32].copy_from_slice(&self.0);
res[32..].copy_from_slice(&self.1);
res
}
}
+3
View File
@@ -0,0 +1,3 @@
pub mod keys;
pub mod msg;
pub mod payment;
+30
View File
@@ -0,0 +1,30 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::keys::PublicKey;
use crate::payment::LinkPaymentData;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
LinkPayment { data: LinkPaymentData },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
GetPayments {
limit: Option<u32>,
start_after: Option<PublicKey>,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct MigrateMsg {}
@@ -0,0 +1,73 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::keys::{PublicKey, Signature};
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct Payment {
verification_key: PublicKey,
gateway_identity: PublicKey,
bandwidth: u64,
}
impl Payment {
pub fn new(verification_key: PublicKey, gateway_identity: PublicKey, bandwidth: u64) -> Self {
Payment {
verification_key,
gateway_identity,
bandwidth,
}
}
pub fn verification_key(&self) -> PublicKey {
self.verification_key
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct LinkPaymentData {
pub verification_key: PublicKey,
pub gateway_identity: PublicKey,
pub bandwidth: u64,
pub signature: Signature,
}
impl LinkPaymentData {
pub fn new(
verification_key: [u8; 32],
gateway_identity: [u8; 32],
bandwidth: u64,
signature: [u8; 64],
) -> Self {
LinkPaymentData {
verification_key: PublicKey::new(verification_key),
gateway_identity: PublicKey::new(gateway_identity),
bandwidth,
signature: Signature::new(signature),
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct PagedPaymentResponse {
pub payments: Vec<Payment>,
pub per_page: usize,
pub start_next_after: Option<PublicKey>,
}
impl PagedPaymentResponse {
pub fn new(
payments: Vec<Payment>,
per_page: usize,
start_next_after: Option<PublicKey>,
) -> Self {
PagedPaymentResponse {
payments,
per_page,
start_next_after,
}
}
}
+10 -2
View File
@@ -8,10 +8,18 @@ edition = "2018"
[dependencies]
# this branch is identical to 0.14.1 with addition of updated k256 dependency required to help poor cargo choose correct version
cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch="0.14.1-updatedk256" }
cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch = "0.14.1-updatedk256" }
#cosmwasm-std = { version = "0.14.1" }
serde = { version = "1.0", features = ["derive"] }
serde_repr = "0.1"
schemars = "0.8"
ts-rs = "3.0"
ts-rs = { version = "3.0", optional = true }
thiserror = "1.0"
network-defaults = { path = "../network-defaults" }
fixed = "1.1"
az = "1.1"
log = "0.4.14"
[features]
default = ["ts-rs"]
+9
View File
@@ -0,0 +1,9 @@
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum MixnetContractError {
#[error("Overflow Error")]
OverflowError(#[from] cosmwasm_std::OverflowError),
#[error("reward_blockstamp field not set, set_reward_blockstamp must be called before attempting to issue rewards")]
BlockstampNotSet,
}
+2 -2
View File
@@ -7,9 +7,9 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::fmt::Display;
use ts_rs::TS;
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema, TS)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
pub struct Gateway {
pub host: String,
pub mix_port: u16,
+6 -2
View File
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
mod delegation;
pub mod error;
mod gateway;
mod mixnode;
pub mod mixnode;
mod msg;
mod types;
@@ -15,4 +16,7 @@ pub use delegation::{
pub use gateway::{Gateway, GatewayBond, GatewayOwnershipResponse, PagedGatewayResponse};
pub use mixnode::{Layer, MixNode, MixNodeBond, MixOwnershipResponse, PagedMixnodeResponse};
pub use msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
pub use types::{IdentityKey, IdentityKeyRef, LayerDistribution, SphinxKey, StateParams};
pub use types::{
IdentityKey, IdentityKeyRef, LayerDistribution, RewardingIntervalResponse, SphinxKey,
StateParams,
};
+230 -3
View File
@@ -2,15 +2,20 @@
#![allow(clippy::field_reassign_with_default)]
use crate::{IdentityKey, SphinxKey};
use cosmwasm_std::{coin, Addr, Coin};
use az::CheckedCast;
use cosmwasm_std::{coin, Addr, Coin, Uint128};
use log::error;
use network_defaults::{DEFAULT_OPERATOR_EPOCH_COST, DEFAULT_PROFIT_MARGIN};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::cmp::Ordering;
use std::fmt::Display;
use ts_rs::TS;
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema, TS)]
type U128 = fixed::types::U75F53; // u128 with 18 significant digits
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
pub struct MixNode {
pub host: String,
pub mix_port: u16,
@@ -43,6 +48,97 @@ pub enum Layer {
Three = 3,
}
#[derive(Debug, Clone, JsonSchema, PartialEq, Serialize, Deserialize, Copy)]
pub struct NodeRewardParams {
period_reward_pool: Uint128,
k: Uint128,
reward_blockstamp: u64,
circulating_supply: Uint128,
uptime: Uint128,
sybil_resistance_percent: u8,
}
impl NodeRewardParams {
pub fn new(
period_reward_pool: u128,
k: u128,
reward_blockstamp: u64,
circulating_supply: u128,
uptime: u128,
sybil_resistance_percent: u8,
) -> NodeRewardParams {
NodeRewardParams {
period_reward_pool: Uint128(period_reward_pool),
k: Uint128(k),
reward_blockstamp,
circulating_supply: Uint128(circulating_supply),
uptime: Uint128(uptime),
sybil_resistance_percent,
}
}
pub fn performance(&self) -> U128 {
U128::from_num(self.uptime.u128()) / U128::from_num(100)
}
pub fn operator_cost(&self) -> U128 {
U128::from_num(self.uptime.u128() / 100u128 * DEFAULT_OPERATOR_EPOCH_COST as u128)
}
pub fn set_reward_blockstamp(&mut self, blockstamp: u64) {
self.reward_blockstamp = blockstamp;
}
pub fn period_reward_pool(&self) -> u128 {
self.period_reward_pool.u128()
}
pub fn k(&self) -> u128 {
self.k.u128()
}
pub fn circulating_supply(&self) -> u128 {
self.circulating_supply.u128()
}
pub fn reward_blockstamp(&self) -> u64 {
self.reward_blockstamp
}
pub fn uptime(&self) -> u128 {
self.uptime.u128()
}
pub fn one_over_k(&self) -> U128 {
U128::from_num(1) / U128::from_num(self.k.u128())
}
pub fn alpha(&self) -> U128 {
U128::from_num(self.sybil_resistance_percent) / U128::from_num(100)
}
}
#[derive(Debug)]
pub struct NodeRewardResult {
reward: U128,
lambda: U128,
sigma: U128,
}
impl NodeRewardResult {
pub fn reward(&self) -> U128 {
self.reward
}
pub fn lambda(&self) -> U128 {
self.lambda
}
pub fn sigma(&self) -> U128 {
self.sigma
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub struct MixNodeBond {
pub bond_amount: Coin,
@@ -51,6 +147,7 @@ pub struct MixNodeBond {
pub layer: Layer,
pub block_height: u64,
pub mix_node: MixNode,
pub profit_margin_percent: Option<u8>,
}
impl MixNodeBond {
@@ -60,6 +157,7 @@ impl MixNodeBond {
layer: Layer,
block_height: u64,
mix_node: MixNode,
profit_margin_percent: Option<u8>,
) -> Self {
MixNodeBond {
total_delegation: coin(0, &bond_amount.denom),
@@ -68,9 +166,15 @@ impl MixNodeBond {
layer,
block_height,
mix_node,
profit_margin_percent,
}
}
pub fn profit_margin(&self) -> U128 {
U128::from_num(self.profit_margin_percent.unwrap_or(DEFAULT_PROFIT_MARGIN))
/ U128::from_num(100)
}
pub fn identity(&self) -> &String {
&self.mix_node.identity_key
}
@@ -86,6 +190,124 @@ impl MixNodeBond {
pub fn mix_node(&self) -> &MixNode {
&self.mix_node
}
pub fn total_stake(&self) -> Option<u128> {
if self.bond_amount.denom != self.total_delegation.denom {
None
} else {
Some(self.bond_amount.amount.u128() + self.total_delegation.amount.u128())
}
}
pub fn total_delegation(&self) -> Coin {
self.total_delegation.clone()
}
pub fn bond_to_circulating_supply(&self, circulating_supply: u128) -> U128 {
U128::from_num(self.bond_amount().amount.u128()) / U128::from_num(circulating_supply)
}
pub fn total_stake_to_circulating_supply(&self, circulating_supply: u128) -> U128 {
U128::from_num(self.bond_amount().amount.u128() + self.total_delegation().amount.u128())
/ U128::from_num(circulating_supply)
}
pub fn lambda(&self, params: &NodeRewardParams) -> U128 {
// Ratio of a bond to the token circulating supply
let bond_to_circulating_supply_ratio =
self.bond_to_circulating_supply(params.circulating_supply());
bond_to_circulating_supply_ratio.min(params.one_over_k())
}
pub fn sigma(&self, params: &NodeRewardParams) -> U128 {
// Ratio of a delegation to the the token circulating supply
let total_stake_to_circulating_supply_ratio =
self.total_stake_to_circulating_supply(params.circulating_supply());
total_stake_to_circulating_supply_ratio.min(params.one_over_k())
}
pub fn reward(&self, params: &NodeRewardParams) -> NodeRewardResult {
// Assuming uniform work distribution across the network this is one_over_k * k
let omega_k = U128::from_num(1u128);
let lambda = self.lambda(params);
let sigma = self.sigma(params);
let reward = params.performance()
* params.period_reward_pool()
* (sigma * omega_k + params.alpha() * lambda * sigma * params.k())
/ (U128::from_num(1) + params.alpha());
NodeRewardResult {
reward,
lambda,
sigma,
}
}
pub fn node_profit(&self, params: &NodeRewardParams) -> U128 {
if self.reward(params).reward() < params.operator_cost() {
U128::from_num(0)
} else {
self.reward(params).reward() - params.operator_cost()
}
}
pub fn operator_reward(&self, params: &NodeRewardParams) -> u128 {
let reward = self.reward(params);
let profit = if reward.reward < params.operator_cost() {
U128::from_num(0)
} else {
reward.reward - params.operator_cost()
};
let operator_base_reward = reward.reward.min(params.operator_cost());
let operator_reward = (self.profit_margin()
+ (U128::from_num(1) - self.profit_margin()) * reward.lambda / reward.sigma)
* profit;
let reward = (operator_reward + operator_base_reward).max(U128::from_num(0));
if let Some(int_reward) = reward.checked_cast() {
int_reward
} else {
error!(
"Could not cast reward ({}) to u128, returning 0 - mixnode {}",
reward,
self.identity()
);
0u128
}
}
pub fn sigma_ratio(&self, params: &NodeRewardParams) -> U128 {
if self.total_stake_to_circulating_supply(params.circulating_supply()) < params.one_over_k()
{
self.total_stake_to_circulating_supply(params.circulating_supply())
} else {
params.one_over_k()
}
}
pub fn reward_delegation(&self, delegation_amount: Uint128, params: &NodeRewardParams) -> u128 {
let scaled_delegation_amount =
U128::from_num(delegation_amount.u128()) / U128::from_num(params.circulating_supply());
let delegator_reward = (U128::from_num(1) - self.profit_margin())
* scaled_delegation_amount
/ self.sigma(params)
* self.node_profit(params);
let reward = delegator_reward.max(U128::from_num(0));
if let Some(int_reward) = reward.checked_cast() {
int_reward
} else {
error!(
"Could not cast delegator reward ({}) to u128, returning 0 - mixnode {}",
reward,
self.identity()
);
0u128
}
}
}
impl PartialOrd for MixNodeBond {
@@ -217,6 +439,7 @@ mod tests {
layer: Layer::One,
block_height: 100,
mix_node: mixnode_fixture(),
profit_margin_percent: Some(10),
};
let mix2 = MixNodeBond {
@@ -226,6 +449,7 @@ mod tests {
layer: Layer::One,
block_height: 120,
mix_node: mixnode_fixture(),
profit_margin_percent: Some(10),
};
let mix3 = MixNodeBond {
@@ -235,6 +459,7 @@ mod tests {
layer: Layer::One,
block_height: 120,
mix_node: mixnode_fixture(),
profit_margin_percent: Some(10),
};
let mix4 = MixNodeBond {
@@ -244,6 +469,7 @@ mod tests {
layer: Layer::One,
block_height: 120,
mix_node: mixnode_fixture(),
profit_margin_percent: Some(10),
};
let mix5 = MixNodeBond {
@@ -253,6 +479,7 @@ mod tests {
layer: Layer::One,
block_height: 120,
mix_node: mixnode_fixture(),
profit_margin_percent: Some(10),
};
// summary:
+28
View File
@@ -1,6 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::mixnode::NodeRewardParams;
use crate::StateParams;
use crate::{Gateway, IdentityKey, MixNode};
use cosmwasm_std::Addr;
@@ -31,10 +32,32 @@ pub enum ExecuteMsg {
mix_identity: IdentityKey,
},
BeginMixnodeRewarding {
// nonce of the current rewarding interval
rewarding_interval_nonce: u32,
},
RewardMixnode {
identity: IdentityKey,
// percentage value in range 0-100
uptime: u32,
// nonce of the current rewarding interval
rewarding_interval_nonce: u32,
},
FinishMixnodeRewarding {
// nonce of the current rewarding interval
rewarding_interval_nonce: u32,
},
RewardMixnodeV2 {
identity: IdentityKey,
// percentage value in range 0-100
params: NodeRewardParams,
// nonce of the current rewarding interval
rewarding_interval_nonce: u32,
},
}
@@ -56,6 +79,7 @@ pub enum QueryMsg {
address: Addr,
},
StateParams {},
CurrentRewardingInterval {},
GetMixDelegations {
mix_identity: IdentityKey,
start_after: Option<Addr>,
@@ -75,6 +99,10 @@ pub enum QueryMsg {
address: Addr,
},
LayerDistribution {},
GetRewardPool {},
GetCirculatingSupply {},
GetEpochRewardPercent {},
GetSybilResistancePercent {},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
+20 -1
View File
@@ -26,15 +26,29 @@ impl LayerDistribution {
}
}
#[derive(Debug, Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq)]
pub struct RewardingIntervalResponse {
pub current_rewarding_interval_starting_block: u64,
pub current_rewarding_interval_nonce: u32,
pub rewarding_in_progress: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct StateParams {
pub epoch_length: u32, // length of an epoch, expressed in hours
pub epoch_length: u32, // length of a rewarding epoch/interval, expressed in hours
pub minimum_mixnode_bond: Uint128, // minimum amount a mixnode must bond to get into the system
pub minimum_gateway_bond: Uint128, // minimum amount a gateway must bond to get into the system
pub mixnode_bond_reward_rate: Decimal, // annual reward rate, expressed as a decimal like 1.25
pub mixnode_delegation_reward_rate: Decimal, // annual reward rate, expressed as a decimal like 1.25
// number of mixnode that are going to get rewarded during current rewarding interval (k_m)
// based on overall demand for private bandwidth-
pub mixnode_rewarded_set_size: u32,
// subset of rewarded mixnodes that are actively receiving mix traffic
// used to handle shorter-term (e.g. hourly) fluctuations of demand
pub mixnode_active_set_size: u32,
}
@@ -54,6 +68,11 @@ impl Display for StateParams {
"mixnode delegation reward rate: {}; ",
self.mixnode_delegation_reward_rate
)?;
write!(
f,
"mixnode rewarded set size: {}",
self.mixnode_rewarded_set_size
)?;
write!(
f,
"mixnode active set size: {}",
+1
View File
@@ -7,6 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hex-literal = "0.3.3"
serde = {version = "1.0", features = ["derive"]}
url = "2.2"
time = { version = "0.3", features = ["macros"] }
+132
View File
@@ -0,0 +1,132 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// This should be modified whenever an updated Ethereum contract is uploaded
pub const ETH_JSON_ABI: &str = r#"
[
{
"inputs": [
{
"internalType": "contract ERC20Burnable",
"name": "_erc20",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "Bandwidth",
"type": "uint256"
},
{
"indexed": true,
"internalType": "uint256",
"name": "VerificationKey",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bytes",
"name": "SignedVerificationKey",
"type": "bytes"
}
],
"name": "Burned",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "verificationKey",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "signedVerificationKey",
"type": "bytes"
}
],
"name": "burnTokenForAccessCode",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "erc20",
"outputs": [
{
"internalType": "contract ERC20Burnable",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
"#;
+28 -2
View File
@@ -5,6 +5,8 @@ use std::time::Duration;
use time::OffsetDateTime;
use url::Url;
pub mod eth_contract;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ValidatorDetails {
// it is assumed those values are always valid since they're being provided in our defaults file
@@ -61,7 +63,24 @@ pub fn default_api_endpoints() -> Vec<Url> {
}
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen";
pub const NETWORK_MONITOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
/// How much bandwidth (in bytes) one token can buy
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
/// How many ERC20 tokens should be burned to buy bandwidth
pub const TOKENS_TO_BURN: u64 = 10;
/// Default bandwidth (in bytes) that we try to buy
pub const BANDWIDTH_VALUE: u64 = TOKENS_TO_BURN * BYTES_PER_TOKEN;
// Ethereum constants used for token bridge
pub const ETH_CONTRACT_ADDRESS: [u8; 20] =
hex_literal::hex!("9fEE3e28c17dbB87310A51F13C4fbf4331A6f102");
pub const ETH_MIN_BLOCK_DEPTH: usize = 7;
pub const COSMOS_CONTRACT_ADDRESS: &str = "punk1jld76tqw4wnpfenmay2xkv86nr3j0w426eka82";
// Name of the event triggered by the eth contract. If the event name is changed,
// this would also need to be changed; It is currently tested against the json abi
pub const ETH_EVENT_NAME: &str = "Burned";
pub const ETH_BURN_FUNCTION_NAME: &str = "burnTokenForAccessCode";
/// Defaults Cosmos Hub/ATOM path
pub const COSMOS_DERIVATION_PATH: &str = "m/44'/118'/0'/0/0";
@@ -93,4 +112,11 @@ pub const VALIDATOR_API_VERSION: &str = "v1";
// REWARDING
pub const DEFAULT_FIRST_EPOCH_START: OffsetDateTime = time::macros::datetime!(2021-08-23 12:00 UTC);
pub const DEFAULT_EPOCH_LENGTH: Duration = Duration::from_secs(24 * 60 * 60); // 24h
pub const DEFAULT_EPOCH_LENGTH: Duration = Duration::from_secs(24 * 60 * 60 * 30); // 30 days
/// We'll be assuming a few more things, profit margin and cost function. Since we don't have relialable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate epoch costs to Nyms. We'll also assume a cost of 40$ per epoch(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
pub const DEFAULT_OPERATOR_EPOCH_COST: u64 = 40_000_000; // 40$/(30 days) at 1 Nym == 1$
// TODO: is there a way to get this from the chain
pub const TOTAL_SUPPLY: u128 = 1_000_000_000_000_000;
pub const DEFAULT_PROFIT_MARGIN: u8 = 10;
+863
View File
@@ -0,0 +1,863 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array 0.12.4",
]
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "config"
version = "0.1.0"
dependencies = [
"handlebars",
"humantime-serde",
"network-defaults",
"serde",
"toml",
"url",
]
[[package]]
name = "const-oid"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdab415d6744056100f40250a66bc430c1a46f7a02e20bc11c94c79a0f0464df"
[[package]]
name = "cosmos_contract"
version = "0.1.0"
dependencies = [
"config",
"cosmwasm-std",
"cosmwasm-storage",
"erc20-bridge-contract",
"schemars",
"serde",
"thiserror",
]
[[package]]
name = "cosmwasm-crypto"
version = "0.14.1"
source = "git+https://github.com/jstuczyn/cosmwasm?branch=0.14.1-updatedk256#308781cd5f33b0e996176c6b500793d3648c0f7b"
dependencies = [
"digest 0.9.0",
"ed25519-zebra",
"k256",
"rand_core 0.5.1",
"thiserror",
]
[[package]]
name = "cosmwasm-derive"
version = "0.14.1"
source = "git+https://github.com/jstuczyn/cosmwasm?branch=0.14.1-updatedk256#308781cd5f33b0e996176c6b500793d3648c0f7b"
dependencies = [
"syn",
]
[[package]]
name = "cosmwasm-std"
version = "0.14.1"
source = "git+https://github.com/jstuczyn/cosmwasm?branch=0.14.1-updatedk256#308781cd5f33b0e996176c6b500793d3648c0f7b"
dependencies = [
"base64",
"cosmwasm-crypto",
"cosmwasm-derive",
"schemars",
"serde",
"serde-json-wasm",
"thiserror",
"uint",
]
[[package]]
name = "cosmwasm-storage"
version = "0.14.1"
source = "git+https://github.com/jstuczyn/cosmwasm?branch=0.14.1-updatedk256#308781cd5f33b0e996176c6b500793d3648c0f7b"
dependencies = [
"cosmwasm-std",
"serde",
]
[[package]]
name = "cpufeatures"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
"libc",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-bigint"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d12477e115c0d570c12a2dfd859f80b55b60ddb5075df210d3af06d133a69f45"
dependencies = [
"generic-array 0.14.4",
"rand_core 0.6.3",
"subtle",
"zeroize",
]
[[package]]
name = "crypto-mac"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
"generic-array 0.14.4",
"subtle",
]
[[package]]
name = "curve25519-dalek"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
dependencies = [
"byteorder",
"digest 0.9.0",
"rand_core 0.5.1",
"subtle",
"zeroize",
]
[[package]]
name = "der"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2"
dependencies = [
"const-oid",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array 0.12.4",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "dyn-clone"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf"
[[package]]
name = "ecdsa"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
dependencies = [
"der",
"elliptic-curve",
"hmac",
"signature",
]
[[package]]
name = "ed25519-zebra"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409"
dependencies = [
"curve25519-dalek",
"hex",
"rand_core 0.5.1",
"serde",
"sha2",
"thiserror",
]
[[package]]
name = "elliptic-curve"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b"
dependencies = [
"crypto-bigint",
"ff",
"generic-array 0.14.4",
"group",
"pkcs8",
"rand_core 0.6.3",
"subtle",
"zeroize",
]
[[package]]
name = "erc20-bridge-contract"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "ff"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
dependencies = [
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
"cfg-if",
"libc",
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
name = "group"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
dependencies = [
"ff",
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "handlebars"
version = "3.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3"
dependencies = [
"log",
"pest",
"pest_derive",
"quick-error",
"serde",
"serde_json",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hex-literal"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b"
[[package]]
name = "hmac"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [
"crypto-mac",
"digest 0.9.0",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "humantime-serde"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058"
dependencies = [
"humantime",
"serde",
]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "k256"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea"
dependencies = [
"cfg-if",
"ecdsa",
"elliptic-curve",
"sha2",
]
[[package]]
name = "libc"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "network-defaults"
version = "0.1.0"
dependencies = [
"hex-literal",
"serde",
"time",
"url",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
dependencies = [
"maplit",
"pest",
"sha-1",
]
[[package]]
name = "pkcs8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447"
dependencies = [
"der",
"spki",
]
[[package]]
name = "proc-macro2"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quick-error"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quote"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom 0.2.3",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "schemars"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409"
dependencies = [
"dyn-clone",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn",
]
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde-json-wasm"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50eef3672ec8fa45f3457fd423ba131117786784a895548021976117c1ded449"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_derive_internals"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha-1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
"block-buffer 0.7.3",
"digest 0.8.1",
"fake-simd",
"opaque-debug 0.2.3",
]
[[package]]
name = "sha2"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpufeatures",
"digest 0.9.0",
"opaque-debug 0.3.0",
]
[[package]]
name = "signature"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335"
dependencies = [
"digest 0.9.0",
"rand_core 0.6.3",
]
[[package]]
name = "spki"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32"
dependencies = [
"der",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "thiserror"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99beeb0daeac2bd1e86ac2c21caddecb244b39a093594da1a661ec2060c7aedd"
dependencies = [
"libc",
"time-macros",
]
[[package]]
name = "time-macros"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6"
[[package]]
name = "tinyvec"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "typenum"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "uint"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f"
dependencies = [
"byteorder",
"crunchy",
"hex",
"static_assertions",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "zeroize"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
+40
View File
@@ -0,0 +1,40 @@
[package]
name = "cosmos_contract"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace] # adding a blank workspace to keep it out of the global workspace.
[lib]
crate-type = ["cdylib", "rlib"]
[profile.release]
opt-level = 3
debug = false
rpath = false
lto = true
debug-assertions = false
codegen-units = 1
panic = 'abort'
incremental = false
overflow-checks = true
[features]
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
[dev-dependencies]
config = { path = "../../common/config"}
[dependencies]
erc20-bridge-contract = { path = "../../common/erc20-bridge-contract" }
# this branch is identical to 0.14.1 with addition of updated k256 dependency required to help poor cargo choose correct version
cosmwasm-std = { git = "https://github.com/jstuczyn/cosmwasm", branch="0.14.1-updatedk256", features = ["iterator"] }
cosmwasm-storage = { git = "https://github.com/jstuczyn/cosmwasm", branch="0.14.1-updatedk256", features = ["iterator"] }
schemars = "0.8"
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
thiserror = "1.0.23"
+27
View File
@@ -0,0 +1,27 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{StdError, VerificationError};
use thiserror::Error;
/// Custom errors for contract failure conditions.
///
/// Add any other custom errors you like here.
/// Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details.
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),
#[error("Invalid size for signature items")]
InvalidSignatureSize,
#[error("This payment has already been claimed by someone")]
PaymentAlreadyClaimed,
#[error("Error while verifying ed25519 signature - {0}")]
VerificationError(#[from] VerificationError),
#[error("The payment is not properly signed")]
BadSignature,
}
+102
View File
@@ -0,0 +1,102 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
mod error;
mod queries;
mod storage;
mod support;
mod transactions;
use cosmwasm_std::{
entry_point, to_binary, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response,
};
use crate::error::ContractError;
use erc20_bridge_contract::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
/// Instantiate the contract.
///
/// `deps` contains Storage, API and Querier
/// `env` contains block, message and contract info
/// `msg` is the contract initialization message, sort of like a constructor call.
#[entry_point]
pub fn instantiate(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: InstantiateMsg,
) -> Result<Response, ContractError> {
Ok(Response::default())
}
/// Handle an incoming message
#[entry_point]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::LinkPayment { data } => transactions::link_payment(deps, env, info, data),
}
}
#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, ContractError> {
let query_res = match msg {
QueryMsg::GetPayments { start_after, limit } => {
to_binary(&queries::query_payments_paged(deps, start_after, limit)?)
}
};
Ok(query_res?)
}
#[entry_point]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Default::default())
}
#[cfg(test)]
pub mod tests {
use super::*;
use config::defaults::DENOM;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::{coins, from_binary};
use erc20_bridge_contract::payment::PagedPaymentResponse;
#[test]
fn initialize_contract() {
let mut deps = mock_dependencies(&[]);
let env = mock_env();
let msg = InstantiateMsg {};
let info = mock_info("creator", &[]);
let res = instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
assert_eq!(0, res.messages.len());
// payments should be empty after initialization
let res = query(
deps.as_ref(),
env.clone(),
QueryMsg::GetPayments {
start_after: None,
limit: Option::from(2),
},
)
.unwrap();
let page: PagedPaymentResponse = from_binary(&res).unwrap();
assert_eq!(0, page.payments.len()); // there are no payments in the list when it's just been initialized
// Contract balance should match what we initialized it as
assert_eq!(
coins(0, DENOM),
vec![deps
.as_ref()
.querier
.query_balance(env.contract.address, DENOM)
.unwrap()]
);
}
}
+191
View File
@@ -0,0 +1,191 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{Deps, Order, StdResult};
use crate::storage::payments_read;
use erc20_bridge_contract::keys::PublicKey;
use erc20_bridge_contract::payment::{PagedPaymentResponse, Payment};
const PAYMENT_PAGE_MAX_LIMIT: u32 = 100;
const PAYMENT_PAGE_DEFAULT_LIMIT: u32 = 50;
/// Adds a 0 byte to terminate the `start_after` value given. This allows CosmWasm
/// to get the succeeding key as the start of the next page.
fn calculate_start_value<B: AsRef<[u8]>>(start_after: Option<B>) -> Option<Vec<u8>> {
start_after.as_ref().map(|identity| {
identity
.as_ref()
.iter()
.cloned()
.chain(std::iter::once(0))
.collect()
})
}
pub fn query_payments_paged(
deps: Deps,
start_after: Option<PublicKey>,
limit: Option<u32>,
) -> StdResult<PagedPaymentResponse> {
let limit = limit
.unwrap_or(PAYMENT_PAGE_DEFAULT_LIMIT)
.min(PAYMENT_PAGE_MAX_LIMIT) as usize;
let start = calculate_start_value(start_after);
let payments = payments_read(deps.storage)
.range(start.as_deref(), None, Order::Ascending)
.take(limit)
.map(|res| res.map(|item| item.1))
.collect::<StdResult<Vec<Payment>>>()?;
let start_next_after = payments.last().map(|payment| payment.verification_key());
Ok(PagedPaymentResponse::new(payments, limit, start_next_after))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::storage::payments;
use crate::support::tests::helpers;
use std::convert::TryInto;
#[test]
fn payments_empty_on_init() {
let deps = helpers::init_contract();
let response = query_payments_paged(deps.as_ref(), None, Option::from(2)).unwrap();
assert_eq!(0, response.payments.len());
}
#[test]
fn payments_paged_retrieval_obeys_limits() {
let mut deps = helpers::init_contract();
let storage = deps.as_mut().storage;
let limit = 2;
for n in 0u32..10000 {
let bytes: Vec<u8> = std::iter::repeat(n.to_be_bytes())
.take(8)
.flatten()
.collect();
let verification_key = PublicKey::new(bytes.try_into().unwrap());
let payment = helpers::payment_fixture();
payments(storage)
.save(&verification_key.to_bytes(), &payment)
.unwrap();
}
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(limit)).unwrap();
assert_eq!(limit, page1.payments.len() as u32);
}
#[test]
fn payments_paged_retrieval_has_default_limit() {
let mut deps = helpers::init_contract();
let storage = deps.as_mut().storage;
for n in 0u32..100 {
let bytes: Vec<u8> = std::iter::repeat(n.to_be_bytes())
.take(8)
.flatten()
.collect();
let verification_key = PublicKey::new(bytes.try_into().unwrap());
let payment = helpers::payment_fixture();
payments(storage)
.save(&verification_key.to_bytes(), &payment)
.unwrap();
}
// query without explicitly setting a limit
let page1 = query_payments_paged(deps.as_ref(), None, None).unwrap();
assert_eq!(PAYMENT_PAGE_DEFAULT_LIMIT, page1.payments.len() as u32);
}
#[test]
fn payments_paged_retrieval_has_max_limit() {
let mut deps = helpers::init_contract();
let storage = deps.as_mut().storage;
for n in 0u32..10000 {
let bytes: Vec<u8> = std::iter::repeat(n.to_be_bytes())
.take(8)
.flatten()
.collect();
let verification_key = PublicKey::new(bytes.try_into().unwrap());
let payment = helpers::payment_fixture();
payments(storage)
.save(&verification_key.to_bytes(), &payment)
.unwrap();
}
// query with a crazily high limit in an attempt to use too many resources
let crazy_limit = 1000;
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(crazy_limit)).unwrap();
// we default to a decent sized upper bound instead
assert_eq!(PAYMENT_PAGE_MAX_LIMIT, page1.payments.len() as u32);
}
#[test]
fn payments_pagination_works() {
let key1 = PublicKey::new([1; 32]);
let key2 = PublicKey::new([2; 32]);
let key3 = PublicKey::new([3; 32]);
let key4 = PublicKey::new([4; 32]);
let mut deps = helpers::init_contract();
let payment = helpers::payment_fixture();
payments(&mut deps.storage)
.save(&key1.to_bytes(), &payment)
.unwrap();
let per_page = 2;
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
// page should have 1 result on it
assert_eq!(1, page1.payments.len());
// save another
payments(&mut deps.storage)
.save(&key2.to_bytes(), &payment)
.unwrap();
// page1 should have 2 results on it
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
assert_eq!(2, page1.payments.len());
payments(&mut deps.storage)
.save(&key3.to_bytes(), &payment)
.unwrap();
// page1 still has 2 results
let page1 = query_payments_paged(deps.as_ref(), None, Option::from(per_page)).unwrap();
assert_eq!(2, page1.payments.len());
// retrieving the next page should start after the last key on this page
let start_after = key2;
let page2 = query_payments_paged(
deps.as_ref(),
Option::from(start_after),
Option::from(per_page),
)
.unwrap();
assert_eq!(1, page2.payments.len());
// save another one
payments(&mut deps.storage)
.save(&key4.to_bytes(), &payment)
.unwrap();
let start_after = key2;
let page2 = query_payments_paged(
deps.as_ref(),
Option::from(start_after),
Option::from(per_page),
)
.unwrap();
// now we have 2 pages, with 2 results on the second page
assert_eq!(2, page2.payments.len());
}
}
+79
View File
@@ -0,0 +1,79 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::Storage;
use cosmwasm_storage::{bucket, bucket_read, Bucket, ReadonlyBucket};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use erc20_bridge_contract::payment::Payment;
// buckets
const PREFIX_PAYMENTS: &[u8] = b"payments";
const PREFIX_STATUS: &[u8] = b"status";
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
pub enum Status {
Unchecked,
Checked,
Spent,
}
pub fn payments(storage: &mut dyn Storage) -> Bucket<Payment> {
bucket(storage, PREFIX_PAYMENTS)
}
pub fn payments_read(storage: &dyn Storage) -> ReadonlyBucket<Payment> {
bucket_read(storage, PREFIX_PAYMENTS)
}
pub fn status(storage: &mut dyn Storage) -> Bucket<Status> {
bucket(storage, PREFIX_STATUS)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::support::tests::helpers;
use cosmwasm_std::testing::MockStorage;
use erc20_bridge_contract::keys::PublicKey;
#[test]
fn payments_single_read_retrieval() {
let mut storage = MockStorage::new();
let key1 = PublicKey::new([1; 32]);
let key2 = PublicKey::new([2; 32]);
let payment1 = helpers::payment_fixture();
let payment2 = helpers::payment_fixture();
payments(&mut storage)
.save(key1.as_ref(), &payment1)
.unwrap();
payments(&mut storage)
.save(key2.as_ref(), &payment2)
.unwrap();
let res1 = payments_read(&storage).load(key1.as_ref()).unwrap();
let res2 = payments_read(&storage).load(key2.as_ref()).unwrap();
assert_eq!(payment1, res1);
assert_eq!(payment2, res2);
}
#[test]
fn status_single_read_retrieval() {
let mut storage = MockStorage::new();
let key1 = PublicKey::new([1; 32]);
let key2 = PublicKey::new([2; 32]);
let status_value = Status::Unchecked;
status(&mut storage)
.save(key1.as_ref(), &status_value)
.unwrap();
status(&mut storage)
.save(key2.as_ref(), &status_value)
.unwrap();
let res1 = status(&mut storage).load(key1.as_ref()).unwrap();
assert_eq!(status_value, res1);
let res2 = status(&mut storage).load(key2.as_ref()).unwrap();
assert_eq!(status_value, res2);
}
}
@@ -0,0 +1,3 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod tests;
@@ -0,0 +1,28 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(test)]
pub mod helpers {
use crate::instantiate;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier};
use cosmwasm_std::{Empty, MemoryStorage, OwnedDeps};
use erc20_bridge_contract::keys::PublicKey;
use erc20_bridge_contract::msg::InstantiateMsg;
use erc20_bridge_contract::payment::Payment;
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
let mut deps = mock_dependencies(&[]);
let msg = InstantiateMsg {};
let env = mock_env();
let info = mock_info("creator", &[]);
instantiate(deps.as_mut(), env.clone(), info, msg).unwrap();
return deps;
}
pub fn payment_fixture() -> Payment {
let public_key = PublicKey::new([1; 32]);
let gateway_identity = PublicKey::new([2; 32]);
let bandwidth = 42;
Payment::new(public_key, gateway_identity, bandwidth)
}
}
+146
View File
@@ -0,0 +1,146 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
use crate::error::ContractError;
use crate::storage::{payments, status, Status};
use erc20_bridge_contract::payment::{LinkPaymentData, Payment};
pub(crate) fn link_payment(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
data: LinkPaymentData,
) -> Result<Response, ContractError> {
let mut status_bucket = status(deps.storage);
let verification_key = data.verification_key.to_bytes();
let gateway_identity = data.gateway_identity.to_bytes();
let message: Vec<u8> = verification_key
.iter()
.chain(gateway_identity.iter())
.copied()
.collect();
let signature = data.signature.to_bytes();
if let Ok(Some(_)) = status_bucket.may_load(&verification_key) {
return Err(ContractError::PaymentAlreadyClaimed);
}
if !deps
.api
.ed25519_verify(&message, &signature, &verification_key)?
{
return Err(ContractError::BadSignature);
}
status_bucket.save(&verification_key, &Status::Unchecked)?;
payments(deps.storage).save(
&verification_key,
&Payment::new(data.verification_key, data.gateway_identity, data.bandwidth),
)?;
Ok(Response::default())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::storage::payments_read;
use crate::support::tests::helpers;
use cosmwasm_std::testing::{mock_env, mock_info};
use erc20_bridge_contract::keys::PublicKey;
#[test]
fn bad_signature_payment() {
let mut deps = helpers::init_contract();
let env = mock_env();
let info = mock_info("owner", &[]);
let payment_data = LinkPaymentData::new([1; 32], [2; 32], 42, [3; 64]);
assert_eq!(
link_payment(deps.as_mut(), env, info, payment_data),
Err(ContractError::BadSignature)
);
}
#[test]
fn good_payment() {
let mut deps = helpers::init_contract();
let env = mock_env();
let info = mock_info("owner", &[]);
let verification_key = [
78, 142, 213, 13, 39, 169, 76, 205, 242, 206, 129, 208, 190, 51, 139, 206, 245, 199,
120, 151, 181, 250, 192, 153, 123, 104, 129, 139, 60, 254, 243, 98,
];
let gateway_identity = [
106, 76, 76, 238, 214, 177, 233, 112, 56, 33, 21, 201, 89, 42, 69, 196, 175, 56, 6,
110, 184, 167, 203, 63, 1, 167, 134, 102, 165, 215, 3, 212,
];
let bandwidth = 42;
let signature = [
200, 134, 156, 198, 113, 180, 129, 90, 70, 28, 176, 201, 35, 208, 145, 28, 15, 16, 9,
110, 148, 188, 193, 75, 157, 201, 206, 211, 128, 215, 66, 207, 175, 155, 48, 24, 171,
254, 9, 37, 108, 205, 143, 37, 77, 189, 162, 52, 44, 130, 173, 60, 220, 22, 193, 3,
111, 90, 123, 147, 206, 8, 137, 1,
];
let payment_data =
LinkPaymentData::new(verification_key, gateway_identity, bandwidth, signature);
assert!(link_payment(deps.as_mut(), env, info, payment_data).is_ok());
assert_eq!(
payments_read(&deps.storage)
.load(&verification_key)
.unwrap(),
Payment::new(
PublicKey::new(verification_key),
PublicKey::new(gateway_identity),
bandwidth
)
);
assert_eq!(
status(&mut deps.storage).load(&verification_key).unwrap(),
Status::Unchecked
)
}
#[test]
fn double_spend_protection() {
let mut deps = helpers::init_contract();
let env = mock_env();
let info = mock_info("owner", &[]);
let verification_key = [
78, 142, 213, 13, 39, 169, 76, 205, 242, 206, 129, 208, 190, 51, 139, 206, 245, 199,
120, 151, 181, 250, 192, 153, 123, 104, 129, 139, 60, 254, 243, 98,
];
let gateway_identity = [
106, 76, 76, 238, 214, 177, 233, 112, 56, 33, 21, 201, 89, 42, 69, 196, 175, 56, 6,
110, 184, 167, 203, 63, 1, 167, 134, 102, 165, 215, 3, 212,
];
let bandwidth = 42;
let signature = [
200, 134, 156, 198, 113, 180, 129, 90, 70, 28, 176, 201, 35, 208, 145, 28, 15, 16, 9,
110, 148, 188, 193, 75, 157, 201, 206, 211, 128, 215, 66, 207, 175, 155, 48, 24, 171,
254, 9, 37, 108, 205, 143, 37, 77, 189, 162, 52, 44, 130, 173, 60, 220, 22, 193, 3,
111, 90, 123, 147, 206, 8, 137, 1,
];
let payment_data =
LinkPaymentData::new(verification_key, gateway_identity, bandwidth, signature);
link_payment(deps.as_mut(), env.clone(), info.clone(), payment_data).unwrap();
// Only the verification key is used for double spending protection, the other data is irrelevant
let second_payment_data = LinkPaymentData::new(verification_key, [1; 32], 10, [2; 64]);
assert_eq!(
link_payment(deps.as_mut(), env, info, second_payment_data),
Err(ContractError::PaymentAlreadyClaimed)
)
}
}
+1
View File
@@ -0,0 +1 @@
.envrc
+220 -93
View File
@@ -23,9 +23,9 @@ dependencies = [
[[package]]
name = "ast_node"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93f52ce8fac3d0e6720a92b0576d737c01b1b5db4dd786e962e5925f00bf755"
checksum = "e96d5444b02f3080edac8a144f6baf29b2fb6ff589ad4311559731a7c7529381"
dependencies = [
"darling",
"pmutil",
@@ -41,12 +41,24 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
version = "0.7.3"
@@ -79,9 +91,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.7.1"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byte-tools"
@@ -89,6 +101,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -121,9 +139,9 @@ dependencies = [
[[package]]
name = "const-oid"
version = "0.6.0"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c32f031ea41b4291d695026c023b95d59db2d8a2c7640800ed56bc8f510f22"
checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
[[package]]
name = "cosmwasm-crypto"
@@ -147,9 +165,9 @@ dependencies = [
[[package]]
name = "cosmwasm-schema"
version = "0.14.0"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6a9a6a4ca3b4d7b56f943312a65857cdfc84424f9c2773889f4cd17f36fba61"
checksum = "04159eec9b583671db7923ff2b979736dfb8f0152347cab9fd02373c22e1a870"
dependencies = [
"schemars",
"serde_json",
@@ -181,9 +199,9 @@ dependencies = [
[[package]]
name = "cpufeatures"
version = "0.1.4"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
"libc",
]
@@ -196,9 +214,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-bigint"
version = "0.2.2"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b32a398eb1ccfbe7e4f452bc749c44d38dd732e9a253f19da224c416f00ee7f4"
checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
dependencies = [
"generic-array 0.14.4",
"rand_core 0.6.3",
@@ -218,9 +236,9 @@ dependencies = [
[[package]]
name = "curve25519-dalek"
version = "3.1.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3"
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
dependencies = [
"byteorder",
"digest 0.9.0",
@@ -266,9 +284,9 @@ dependencies = [
[[package]]
name = "der"
version = "0.4.0"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f215f706081a44cb702c71c39a52c05da637822e9c1645a50b7202689e982d"
checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2"
dependencies = [
"const-oid",
]
@@ -338,9 +356,9 @@ checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf"
[[package]]
name = "ecdsa"
version = "0.12.3"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713c32426287891008edb98f8b5c6abb2130aa043c93a818728fcda78606f274"
checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
dependencies = [
"der",
"elliptic-curve",
@@ -370,9 +388,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "elliptic-curve"
version = "0.10.4"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8"
checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b"
dependencies = [
"crypto-bigint",
"ff",
@@ -404,14 +422,26 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "ff"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63eec06c61e487eecf0f7e6e6372e596a81922c28d33e645d6983ca6493a1af0"
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
dependencies = [
"rand_core 0.6.3",
"subtle",
]
[[package]]
name = "fixed"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d333a26ec13a023c6dff4b7584de4d323cfee2e508f5dd2bbee6669e4f7efdf"
dependencies = [
"az",
"bytemuck",
"half",
"typenum",
]
[[package]]
name = "fnv"
version = "1.0.7"
@@ -501,6 +531,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "handlebars"
version = "3.5.5"
@@ -521,6 +557,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hex-literal"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b"
[[package]]
name = "hmac"
version = "0.11.0"
@@ -564,6 +606,15 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "is-macro"
version = "0.1.9"
@@ -579,15 +630,15 @@ dependencies = [
[[package]]
name = "itoa"
version = "0.4.7"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "k256"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "008b0281ca8032567c9711cd48631781c15228301860a39b32deb28d63125e46"
checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea"
dependencies = [
"cfg-if 1.0.0",
"ecdsa",
@@ -603,9 +654,18 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.100"
version = "0.2.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
[[package]]
name = "lock_api"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
@@ -624,9 +684,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "matches"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "memchr"
@@ -638,10 +698,15 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
name = "mixnet-contract"
version = "0.1.0"
dependencies = [
"az",
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
"thiserror",
"ts-rs",
]
@@ -653,6 +718,7 @@ dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
"cosmwasm-storage",
"fixed",
"mixnet-contract",
"schemars",
"serde",
@@ -663,6 +729,7 @@ dependencies = [
name = "network-defaults"
version = "0.1.0"
dependencies = [
"hex-literal",
"serde",
"time",
"url",
@@ -732,6 +799,31 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if 1.0.0",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
@@ -802,9 +894,9 @@ dependencies = [
[[package]]
name = "pkcs8"
version = "0.7.5"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbee84ed13e44dd82689fa18348a49934fa79cc774a344c42fc9b301c71b140a"
checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447"
dependencies = [
"der",
"spki",
@@ -823,9 +915,9 @@ dependencies = [
[[package]]
name = "ppv-lite86"
version = "0.2.10"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]]
name = "precomputed-hash"
@@ -835,9 +927,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro2"
version = "1.0.24"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
dependencies = [
"unicode-xid",
]
@@ -850,9 +942,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quote"
version = "1.0.8"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
@@ -917,6 +1009,15 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "redox_syscall"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.5.4"
@@ -942,9 +1043,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "schemars"
version = "0.8.3"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc6ab463ae35acccb5cba66c0084c985257b797d288b6050cc2f6ac1b266cb78"
checksum = "d7a48d098c2a7fdf5740b19deb1181b4fb8a9e68e03ae517c14cde04b5725409"
dependencies = [
"dyn-clone",
"schemars_derive",
@@ -954,9 +1055,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.3"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "902fdfbcf871ae8f653bddf4b2c05905ddaabc08f69d32a915787e3be0d31356"
checksum = "4a9ea2a613fe4cd7118b2bb101a25d8ae6192e1975179b67b2f17afd11e70ac8"
dependencies = [
"proc-macro2",
"quote",
@@ -971,10 +1072,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "serde"
version = "1.0.122"
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "974ef1bd2ad8a507599b336595454081ff68a9599b4890af7643c0c0ed73a62c"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
dependencies = [
"serde_derive",
]
@@ -990,9 +1097,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.122"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dee1f300f838c8ac340ecb0112b3ac472464fa67e87292bdb3dfc9c49128e17"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
@@ -1012,9 +1119,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.61"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"itoa",
"ryu",
@@ -1046,9 +1153,9 @@ dependencies = [
[[package]]
name = "sha2"
version = "0.9.5"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa"
dependencies = [
"block-buffer 0.9.0",
"cfg-if 1.0.0",
@@ -1059,9 +1166,9 @@ dependencies = [
[[package]]
name = "signature"
version = "1.3.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335"
checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4"
dependencies = [
"digest 0.9.0",
"rand_core 0.6.3",
@@ -1075,15 +1182,15 @@ checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
[[package]]
name = "smallvec"
version = "1.6.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "spki"
version = "0.4.0"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "987637c5ae6b3121aba9d513f869bd2bff11c4cc086c22473befd6649c0bd521"
checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32"
dependencies = [
"der",
]
@@ -1102,12 +1209,13 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "string_cache"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a"
checksum = "923f0f39b6267d37d23ce71ae7235602134b250ace715dd2c90421998ddac0c6"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"parking_lot",
"phf_shared",
"precomputed-hash",
"serde",
@@ -1146,15 +1254,15 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "subtle"
version = "2.4.0"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "swc_atoms"
version = "0.2.7"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "837a3ef86c2817228e733b6f173c821fd76f9eb21a0bc9001a826be48b00b4e7"
checksum = "9f5229fe227ff0060e13baa386d6e368797700eab909523f730008d191ee53ae"
dependencies = [
"string_cache",
"string_cache_codegen",
@@ -1254,9 +1362,9 @@ dependencies = [
[[package]]
name = "swc_macros_common"
version = "0.3.3"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ed2e930f5a1a4071fe62c90fd3a296f6030e5d94bfe13993244423caf59a78"
checksum = "bf7c68e78ffbcba3d38abe6d0b76a0e1a37888b5c9301db3426537207090ada3"
dependencies = [
"pmutil",
"proc-macro2",
@@ -1266,9 +1374,9 @@ dependencies = [
[[package]]
name = "swc_visit"
version = "0.2.6"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a423caa0b4585118164dbad8f1ad52b592a9a9370b25decc4d84c6b4309132c0"
checksum = "f8511a4788ab29daf00bee23e425aac92c9be4eec74c98fec4a45d0e710be695"
dependencies = [
"either",
"swc_visit_macros",
@@ -1290,9 +1398,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.65"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
dependencies = [
"proc-macro2",
"quote",
@@ -1301,18 +1409,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.23"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.23"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
@@ -1321,9 +1429,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.1"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a776787d9c5d455bec3db044586ccdd8a9c74d5da5dc319fb80f3db08808fe6"
checksum = "99beeb0daeac2bd1e86ac2c21caddecb244b39a093594da1a661ec2060c7aedd"
dependencies = [
"libc",
"time-macros",
@@ -1331,15 +1439,15 @@ dependencies = [
[[package]]
name = "time-macros"
version = "0.2.1"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04a153416002296880a3b51329a0e3df31c779c53ec827993e865ce427982843"
checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6"
[[package]]
name = "tinyvec"
version = "1.3.1"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338"
checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
dependencies = [
"tinyvec_macros",
]
@@ -1383,9 +1491,9 @@ dependencies = [
[[package]]
name = "typenum"
version = "1.13.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "ucd-trie"
@@ -1395,9 +1503,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "uint"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e"
checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f"
dependencies = [
"byteorder",
"crunchy",
@@ -1407,12 +1515,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
version = "0.3.5"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
dependencies = [
"matches",
]
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
@@ -1431,9 +1536,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "url"
@@ -1466,7 +1571,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "zeroize"
version = "1.3.0"
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zeroize"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970"
+1
View File
@@ -49,3 +49,4 @@ thiserror = { version = "1.0.23" }
[dev-dependencies]
cosmwasm-schema = { version = "0.14.0" }
fixed = "1.1"
+56 -9
View File
@@ -1,11 +1,13 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::u128;
use crate::helpers::calculate_epoch_reward_rate;
use crate::state::State;
use crate::storage::{config, layer_distribution};
use crate::{error::ContractError, queries, transactions};
use config::defaults::NETWORK_MONITOR_ADDRESS;
use config::defaults::REWARDING_VALIDATOR_ADDRESS;
use cosmwasm_std::{
entry_point, to_binary, Addr, Decimal, Deps, DepsMut, Env, MessageInfo, QueryResponse,
Response, Uint128,
@@ -24,23 +26,35 @@ pub const INITIAL_MIXNODE_BOND: Uint128 = Uint128(100_000000);
pub const INITIAL_MIXNODE_BOND_REWARD_RATE: u64 = 110;
pub const INITIAL_MIXNODE_DELEGATION_REWARD_RATE: u64 = 110;
pub const INITIAL_MIXNODE_REWARDED_SET_SIZE: u32 = 200;
pub const INITIAL_MIXNODE_ACTIVE_SET_SIZE: u32 = 100;
fn default_initial_state(owner: Addr) -> State {
pub const INITIAL_REWARD_POOL: u128 = 250_000_000_000_000;
pub const EPOCH_REWARD_PERCENT: u8 = 2; // Used to calculate epoch reward pool
pub const DEFAULT_SYBIL_RESISTANCE_PERCENT: u8 = 30;
// We'll be assuming a few more things, profit margin and cost function. Since we don't have relialable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate epoch costs to Nyms. We'll also assume a cost of 40$ per epoch(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
pub const DEFAULT_COST_PER_EPOCH: u32 = 40_000_000;
fn default_initial_state(owner: Addr, env: Env) -> State {
let mixnode_bond_reward_rate = Decimal::percent(INITIAL_MIXNODE_BOND_REWARD_RATE);
let mixnode_delegation_reward_rate = Decimal::percent(INITIAL_MIXNODE_DELEGATION_REWARD_RATE);
State {
owner,
network_monitor_address: Addr::unchecked(NETWORK_MONITOR_ADDRESS), // we trust our hardcoded value
rewarding_validator_address: Addr::unchecked(REWARDING_VALIDATOR_ADDRESS), // we trust our hardcoded value
params: StateParams {
epoch_length: INITIAL_DEFAULT_EPOCH_LENGTH,
minimum_mixnode_bond: INITIAL_MIXNODE_BOND,
minimum_gateway_bond: INITIAL_GATEWAY_BOND,
mixnode_bond_reward_rate,
mixnode_delegation_reward_rate,
mixnode_rewarded_set_size: INITIAL_MIXNODE_REWARDED_SET_SIZE,
mixnode_active_set_size: INITIAL_MIXNODE_ACTIVE_SET_SIZE,
},
rewarding_interval_starting_block: env.block.height,
latest_rewarding_interval_nonce: 0,
rewarding_in_progress: false,
mixnode_epoch_bond_reward: calculate_epoch_reward_rate(
INITIAL_DEFAULT_EPOCH_LENGTH,
mixnode_bond_reward_rate,
@@ -60,11 +74,11 @@ fn default_initial_state(owner: Addr) -> State {
#[entry_point]
pub fn instantiate(
deps: DepsMut,
_env: Env,
env: Env,
info: MessageInfo,
_msg: InstantiateMsg,
) -> Result<Response, ContractError> {
let state = default_initial_state(info.sender);
let state = default_initial_state(info.sender, env);
config(deps.storage).save(&state)?;
layer_distribution(deps.storage).save(&Default::default())?;
@@ -91,15 +105,42 @@ pub fn execute(
ExecuteMsg::UpdateStateParams(params) => {
transactions::try_update_state_params(deps, info, params)
}
ExecuteMsg::RewardMixnode { identity, uptime } => {
transactions::try_reward_mixnode(deps, env, info, identity, uptime)
}
ExecuteMsg::RewardMixnode {
identity,
uptime,
rewarding_interval_nonce,
} => transactions::try_reward_mixnode(
deps,
env,
info,
identity,
uptime,
rewarding_interval_nonce,
),
ExecuteMsg::RewardMixnodeV2 {
identity,
params,
rewarding_interval_nonce,
} => transactions::try_reward_mixnode_v2(
deps,
env,
info,
identity,
params,
rewarding_interval_nonce,
),
ExecuteMsg::DelegateToMixnode { mix_identity } => {
transactions::try_delegate_to_mixnode(deps, env, info, mix_identity)
}
ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
transactions::try_remove_delegation_from_mixnode(deps, info, mix_identity)
}
ExecuteMsg::BeginMixnodeRewarding {
rewarding_interval_nonce,
} => transactions::try_begin_mixnode_rewarding(deps, env, info, rewarding_interval_nonce),
ExecuteMsg::FinishMixnodeRewarding {
rewarding_interval_nonce,
} => transactions::try_finish_mixnode_rewarding(deps, info, rewarding_interval_nonce),
}
}
@@ -119,6 +160,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
to_binary(&queries::query_owns_gateway(deps, address)?)
}
QueryMsg::StateParams {} => to_binary(&queries::query_state_params(deps)),
QueryMsg::CurrentRewardingInterval {} => {
to_binary(&queries::query_rewarding_interval(deps))
}
QueryMsg::LayerDistribution {} => to_binary(&queries::query_layer_distribution(deps)),
QueryMsg::GetMixDelegations {
mix_identity,
@@ -151,11 +195,14 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
mix_identity,
address,
)?),
QueryMsg::GetRewardPool {} => to_binary(&queries::query_reward_pool(deps)),
QueryMsg::GetCirculatingSupply {} => to_binary(&queries::query_circulating_supply(deps)),
QueryMsg::GetEpochRewardPercent {} => to_binary(&EPOCH_REWARD_PERCENT),
QueryMsg::GetSybilResistancePercent {} => to_binary(&DEFAULT_SYBIL_RESISTANCE_PERCENT),
};
Ok(query_res?)
}
#[entry_point]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Default::default())
+23
View File
@@ -51,6 +51,9 @@ pub enum ContractError {
#[error("The delegation reward rate for mixnode was set to be lower than 1")]
DecreasingMixnodeDelegationReward,
#[error("Provided active set size is bigger than the demanded set")]
InvalidActiveSetSize,
#[error("The node had uptime larger than 100%")]
UnexpectedUptime,
@@ -77,4 +80,24 @@ pub enum ContractError {
identity: IdentityKey,
address: Addr,
},
#[error("Overflow error!")]
Overflow(#[from] cosmwasm_std::OverflowError),
#[error("We tried to remove more funds then are available in the Reward pool. Wanted to remove {to_remove}, but have only {reward_pool}")]
OutOfFunds { to_remove: u128, reward_pool: u128 },
#[error("Invalid ratio")]
Ratio(#[from] mixnet_contract::error::MixnetContractError),
#[error("Received invalid rewarding interval nonce. Expected {expected}, received {received}")]
InvalidRewardingIntervalNonce { received: u32, expected: u32 },
#[error("Rewarding distribution is currently in progress")]
RewardingInProgress,
#[error("Rewarding distribution is currently not in progress")]
RewardingNotInProgress,
#[error("Mixnode {identity} has already been rewarded during the current rewarding interval")]
MixnodeAlreadyRewarded { identity: IdentityKey },
}
+2 -2
View File
@@ -19,11 +19,11 @@ const DECIMAL_FRACTIONAL: Uint128 = Uint128(1_000_000_000_000_000_000u128);
// cosmwasm bucket internal value
const NAMESPACE_LENGTH: usize = 2;
fn decimal_to_uint128(value: Decimal) -> Uint128 {
pub fn decimal_to_uint128(value: Decimal) -> Uint128 {
value * DECIMAL_FRACTIONAL
}
fn uint128_to_decimal(value: Uint128) -> Decimal {
pub fn uint128_to_decimal(value: Uint128) -> Decimal {
Decimal::from_ratio(value, DECIMAL_FRACTIONAL)
}
+28 -7
View File
@@ -4,17 +4,17 @@
use crate::error::ContractError;
use crate::helpers::get_all_delegations_paged;
use crate::storage::{
all_mix_delegations_read, gateways_owners_read, gateways_read, mix_delegations_read,
mixnodes_owners_read, mixnodes_read, read_layer_distribution, read_state_params,
reverse_mix_delegations_read,
all_mix_delegations_read, circulating_supply, config_read, gateways_owners_read, gateways_read,
mix_delegations_read, mixnodes_owners_read, mixnodes_read, read_layer_distribution,
read_state_params, reverse_mix_delegations_read, reward_pool_value,
};
use config::defaults::DENOM;
use cosmwasm_std::{coin, Addr, Deps, Order, StdResult};
use cosmwasm_std::{coin, Addr, Deps, Order, StdResult, Uint128};
use mixnet_contract::{
Delegation, GatewayBond, GatewayOwnershipResponse, IdentityKey, LayerDistribution, MixNodeBond,
MixOwnershipResponse, PagedAllDelegationsResponse, PagedGatewayResponse,
PagedMixDelegationsResponse, PagedMixnodeResponse, PagedReverseMixDelegationsResponse,
RawDelegationData, StateParams,
RawDelegationData, RewardingIntervalResponse, StateParams,
};
const BOND_PAGE_MAX_LIMIT: u32 = 100;
@@ -87,10 +87,27 @@ pub(crate) fn query_state_params(deps: Deps) -> StateParams {
read_state_params(deps.storage)
}
pub(crate) fn query_rewarding_interval(deps: Deps) -> RewardingIntervalResponse {
let state = config_read(deps.storage).load().unwrap();
RewardingIntervalResponse {
current_rewarding_interval_starting_block: state.rewarding_interval_starting_block,
current_rewarding_interval_nonce: state.latest_rewarding_interval_nonce,
rewarding_in_progress: state.rewarding_in_progress,
}
}
pub(crate) fn query_layer_distribution(deps: Deps) -> LayerDistribution {
read_layer_distribution(deps.storage)
}
pub(crate) fn query_reward_pool(deps: Deps) -> Uint128 {
reward_pool_value(deps.storage)
}
pub(crate) fn query_circulating_supply(deps: Deps) -> Uint128 {
circulating_supply(deps.storage)
}
/// Adds a 0 byte to terminate the `start_after` value given. This allows CosmWasm
/// to get the succeeding key as the start of the next page.
// S works for both `String` and `Addr` and that's what we wanted
@@ -562,15 +579,19 @@ pub(crate) mod tests {
let dummy_state = State {
owner: Addr::unchecked("someowner"),
network_monitor_address: Addr::unchecked("monitor"),
rewarding_validator_address: Addr::unchecked("monitor"),
params: StateParams {
epoch_length: 1,
minimum_mixnode_bond: 123u128.into(),
minimum_gateway_bond: 456u128.into(),
mixnode_bond_reward_rate: "1.23".parse().unwrap(),
mixnode_delegation_reward_rate: "7.89".parse().unwrap(),
mixnode_active_set_size: 1000,
mixnode_rewarded_set_size: 1000,
mixnode_active_set_size: 500,
},
rewarding_interval_starting_block: 123,
latest_rewarding_interval_nonce: 0,
rewarding_in_progress: false,
mixnode_epoch_bond_reward: "1.23".parse().unwrap(),
mixnode_epoch_delegation_reward: "7.89".parse().unwrap(),
};
+8 -1
View File
@@ -9,9 +9,16 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
pub owner: Addr, // only the owner account can update state
pub network_monitor_address: Addr,
pub rewarding_validator_address: Addr,
pub params: StateParams,
// keep track of the changes to the current rewarding interval,
// i.e. at which block has the latest rewarding occurred
// and whether another run is already in progress
pub rewarding_interval_starting_block: u64,
pub latest_rewarding_interval_nonce: u32,
pub rewarding_in_progress: bool,
// helper values to avoid having to recalculate them on every single payment operation
pub mixnode_epoch_bond_reward: Decimal, // reward per epoch expressed as a decimal like 0.05
pub mixnode_epoch_delegation_reward: Decimal, // reward per epoch expressed as a decimal like 0.05
+134 -19
View File
@@ -1,14 +1,16 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::queries;
use crate::contract::INITIAL_REWARD_POOL;
use crate::state::State;
use crate::transactions::MINIMUM_BLOCK_AGE_FOR_REWARDING;
use crate::{error::ContractError, queries};
use config::defaults::TOTAL_SUPPLY;
use cosmwasm_std::{Decimal, Order, StdResult, Storage, Uint128};
use cosmwasm_storage::{
bucket, bucket_read, singleton, singleton_read, Bucket, ReadonlyBucket, ReadonlySingleton,
Singleton,
};
use mixnet_contract::mixnode::NodeRewardParams;
use mixnet_contract::{
Addr, GatewayBond, IdentityKey, IdentityKeyRef, Layer, LayerDistribution, MixNodeBond,
RawDelegationData, StateParams,
@@ -24,9 +26,10 @@ use serde::Serialize;
// singletons
const CONFIG_KEY: &[u8] = b"config";
const LAYER_DISTRIBUTION_KEY: &[u8] = b"layers";
const REWARD_POOL_PREFIX: &[u8] = b"pool";
// buckets
const PREFIX_MIXNODES: &[u8] = b"mn";
pub const PREFIX_MIXNODES: &[u8] = b"mn";
const PREFIX_MIXNODES_OWNERS: &[u8] = b"mo";
const PREFIX_GATEWAYS: &[u8] = b"gt";
const PREFIX_GATEWAYS_OWNERS: &[u8] = b"go";
@@ -34,6 +37,8 @@ const PREFIX_GATEWAYS_OWNERS: &[u8] = b"go";
const PREFIX_MIX_DELEGATION: &[u8] = b"md";
const PREFIX_REVERSE_MIX_DELEGATION: &[u8] = b"dm";
const PREFIX_REWARDED_MIXNODES: &[u8] = b"rm";
// Contract-level stuff
// TODO Unify bucket and mixnode storage functions
@@ -46,6 +51,53 @@ pub fn config_read(storage: &dyn Storage) -> ReadonlySingleton<State> {
singleton_read(storage, CONFIG_KEY)
}
fn reward_pool(storage: &dyn Storage) -> ReadonlySingleton<Uint128> {
singleton_read(storage, REWARD_POOL_PREFIX)
}
pub fn mut_reward_pool(storage: &mut dyn Storage) -> Singleton<Uint128> {
singleton(storage, REWARD_POOL_PREFIX)
}
pub fn reward_pool_value(storage: &dyn Storage) -> Uint128 {
match reward_pool(storage).load() {
Ok(value) => value,
Err(_e) => Uint128(INITIAL_REWARD_POOL),
}
}
#[allow(dead_code)]
pub fn incr_reward_pool(
amount: Uint128,
storage: &mut dyn Storage,
) -> Result<Uint128, ContractError> {
let stake = reward_pool_value(storage).saturating_add(amount);
mut_reward_pool(storage).save(&stake)?;
Ok(stake)
}
pub fn decr_reward_pool(
amount: Uint128,
storage: &mut dyn Storage,
) -> Result<Uint128, ContractError> {
let stake = match reward_pool_value(storage).checked_sub(amount) {
Ok(stake) => stake,
Err(_e) => {
return Err(ContractError::OutOfFunds {
to_remove: amount.u128(),
reward_pool: reward_pool_value(storage).u128(),
})
}
};
mut_reward_pool(storage).save(&stake)?;
Ok(stake)
}
pub fn circulating_supply(storage: &dyn Storage) -> Uint128 {
let reward_pool = reward_pool_value(storage).u128();
Uint128(TOTAL_SUPPLY - reward_pool)
}
pub(crate) fn read_state_params(storage: &dyn Storage) -> StateParams {
// note: In any other case, I wouldn't have attempted to unwrap this result, but in here
// if we fail to load the stored state we would already be in the undefined behaviour land,
@@ -53,22 +105,6 @@ pub(crate) fn read_state_params(storage: &dyn Storage) -> StateParams {
config_read(storage).load().unwrap().params
}
pub(crate) fn read_mixnode_epoch_bond_reward_rate(storage: &dyn Storage) -> Decimal {
// same justification as in `read_state_params` for the unwrap
config_read(storage)
.load()
.unwrap()
.mixnode_epoch_bond_reward
}
pub(crate) fn read_mixnode_epoch_delegation_reward_rate(storage: &dyn Storage) -> Decimal {
// same justification as in `read_state_params` for the unwrap
config_read(storage)
.load()
.unwrap()
.mixnode_epoch_delegation_reward
}
pub fn layer_distribution(storage: &mut dyn Storage) -> Singleton<LayerDistribution> {
singleton(storage, LAYER_DISTRIBUTION_KEY)
}
@@ -146,6 +182,35 @@ pub fn mixnodes_owners_read(storage: &dyn Storage) -> ReadonlyBucket<IdentityKey
bucket_read(storage, PREFIX_MIXNODES_OWNERS)
}
// we want to treat this bucket as a set so we don't really care about what type of data is being stored.
// I went with u8 as after serialization it takes only a single byte of space, while if a `()` was used,
// it would have taken 4 bytes (representation of 'null')
pub fn rewarded_mixnodes(storage: &mut dyn Storage, rewarding_interval_nonce: u32) -> Bucket<u8> {
Bucket::multilevel(
storage,
&[
rewarding_interval_nonce.to_be_bytes().as_ref(),
PREFIX_REWARDED_MIXNODES,
],
)
}
// we want to treat this bucket as a set so we don't really care about what type of data is being stored.
// I went with u8 as after serialization it takes only a single byte of space, while if a `()` was used,
// it would have taken 4 bytes (representation of 'null')
pub fn rewarded_mixnodes_read(
storage: &dyn Storage,
rewarding_interval_nonce: u32,
) -> ReadonlyBucket<u8> {
ReadonlyBucket::multilevel(
storage,
&[
rewarding_interval_nonce.to_be_bytes().as_ref(),
PREFIX_REWARDED_MIXNODES,
],
)
}
// helpers
pub(crate) fn increase_mix_delegated_stakes(
storage: &mut dyn Storage,
@@ -196,6 +261,55 @@ pub(crate) fn increase_mix_delegated_stakes(
Ok(total_rewarded)
}
pub(crate) fn increase_mix_delegated_stakes_v2(
storage: &mut dyn Storage,
bond: &MixNodeBond,
params: &NodeRewardParams,
) -> Result<Uint128, ContractError> {
let chunk_size = queries::DELEGATION_PAGE_MAX_LIMIT as usize;
let mut total_rewarded = Uint128::zero();
let mut chunk_start: Option<Vec<_>> = None;
loop {
// get `chunk_size` of delegations
let delegations_chunk = mix_delegations_read(storage, bond.identity())
.range(chunk_start.as_deref(), None, Order::Ascending)
.take(chunk_size)
.collect::<StdResult<Vec<_>>>()?;
if delegations_chunk.is_empty() {
break;
}
// append 0 byte to the last value to start with whatever is the next succeeding key
chunk_start = Some(
delegations_chunk
.last()
.unwrap()
.0
.iter()
.cloned()
.chain(std::iter::once(0u8))
.collect(),
);
// and for each of them increase the stake proportionally to the reward
// if at least `MINIMUM_BLOCK_AGE_FOR_REWARDING` blocks have been created
// since they delegated
for (delegator_address, mut delegation) in delegations_chunk.into_iter() {
if delegation.block_height + MINIMUM_BLOCK_AGE_FOR_REWARDING
<= params.reward_blockstamp()
{
let reward = bond.reward_delegation(delegation.amount, params);
delegation.amount += Uint128(reward);
total_rewarded += Uint128(reward);
mix_delegations(storage, bond.identity()).save(&delegator_address, &delegation)?;
}
}
}
Ok(total_rewarded)
}
// currently not used outside tests
#[cfg(test)]
pub(crate) fn read_mixnode_bond(
@@ -345,6 +459,7 @@ mod tests {
identity_key: node_identity.clone(),
..mix_node_fixture()
},
profit_margin_percent: Some(10),
};
mixnodes(&mut storage)
+1
View File
@@ -133,6 +133,7 @@ pub mod helpers {
Layer::One,
12_345,
mix_node,
None,
)
}
File diff suppressed because it is too large Load Diff
+8 -3
View File
@@ -11,6 +11,7 @@ rust-version = "1.56"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bip39 = "1.0.1"
clap = "2.33.0"
dirs = "3.0"
dashmap = "4.0"
@@ -28,22 +29,26 @@ tokio-stream = { version = "0.1", features = [ "fs" ] }
tokio-tungstenite = "0.14"
url = { version = "2.2", features = [ "serde" ] }
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
web3 = "0.17.0"
# internal
coconut-interface = { path = "../common/coconut-interface" , optional = true}
credentials = { path = "../common/credentials" , optional = true}
credentials = { path = "../common/credentials" }
config = { path = "../common/config" }
crypto = { path = "../common/crypto" }
erc20-bridge-contract = { path = "../common/erc20-bridge-contract" }
gateway-requests = { path = "gateway-requests" }
gateway-client = { path = "../common/client-libs/gateway-client" }
mixnet-client = { path = "../common/client-libs/mixnet-client" }
mixnode-common = { path = "../common/mixnode-common" }
network-defaults = { path = "../common/network-defaults" }
nymsphinx = { path = "../common/nymsphinx" }
pemstore = { path = "../common/pemstore" }
validator-client = { path = "../common/client-libs/validator-client" }
validator-client = { path = "../common/client-libs/validator-client", features = ["nymd-client"] }
version-checker = { path = "../common/version-checker" }
[features]
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut"]
coconut = ["coconut-interface", "gateway-requests/coconut", "gateway-client/coconut"]
[build-dependencies]
tokio = { version = "1.4", features = ["rt-multi-thread", "macros"] }
+2 -2
View File
@@ -24,10 +24,10 @@ crypto = { path = "../../common/crypto" }
pemstore = { path = "../../common/pemstore" }
coconut-interface = { path = "../../common/coconut-interface", optional = true }
credentials = { path = "../../common/credentials", optional = true }
credentials = { path = "../../common/credentials" }
[features]
coconut = ["coconut-interface", "credentials"]
coconut = ["coconut-interface"]
[dependencies.tungstenite]
version = "0.13.0"
@@ -49,14 +49,11 @@ impl<'a> GatewayHandshake<'a> {
}
// init: <- pub_key || g^x
let init_message = check_processing_error(
let (remote_identity, remote_ephemeral_key) = check_processing_error(
State::<S>::parse_init_message(received_init_payload),
&mut state,
)
.await?;
let remote_identity = init_message.local_id_pubkey();
let remote_ephemeral_key = init_message.ephemeral_key();
state.update_remote_identity(remote_identity);
// hkdf::<blake3>::(g^xy)
@@ -15,46 +15,9 @@ use futures::{Sink, SinkExt, Stream, StreamExt};
use log::*;
use nymsphinx::params::{GatewayEncryptionAlgorithm, GatewaySharedKeyHkdfAlgorithm};
use rand::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
use tungstenite::Message as WsMessage;
#[derive(Serialize, Deserialize)]
pub struct InitMessage {
local_id_pubkey: [u8; identity::PUBLIC_KEY_LENGTH],
ephemeral_key: [u8; identity::PUBLIC_KEY_LENGTH],
}
impl InitMessage {
fn new(local_id_pubkey: &identity::PublicKey, ephemeral_key: &encryption::PublicKey) -> Self {
InitMessage {
local_id_pubkey: local_id_pubkey.to_bytes(),
ephemeral_key: ephemeral_key.to_bytes(),
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn local_id_pubkey(&self) -> identity::PublicKey {
identity::PublicKey::from_bytes(&self.local_id_pubkey).unwrap()
}
#[cfg(not(target_arch = "wasm32"))]
pub fn ephemeral_key(&self) -> encryption::PublicKey {
encryption::PublicKey::from_bytes(&self.ephemeral_key).unwrap()
}
fn to_bytes(&self) -> Vec<u8> {
bincode::serialize(self).unwrap()
}
}
impl TryFrom<&[u8]> for InitMessage {
type Error = HandshakeError;
fn try_from(value: &[u8]) -> Result<InitMessage, Self::Error> {
bincode::deserialize(value).map_err(|e| e.into())
}
}
/// Handshake state.
pub(crate) struct State<'a, S> {
/// The underlying WebSocket stream.
@@ -101,17 +64,41 @@ impl<'a, S> State<'a, S> {
// Eventually the ID_PUBKEY prefix will get removed and recipient will know
// initializer's identity from another source.
pub(crate) fn init_message(&self) -> Vec<u8> {
InitMessage::new(
self.identity.public_key(),
self.ephemeral_keypair.public_key(),
)
.to_bytes()
self.identity
.public_key()
.to_bytes()
.iter()
.cloned()
.chain(
self.ephemeral_keypair
.public_key()
.to_bytes()
.iter()
.cloned(),
)
.collect()
}
// this will need to be adjusted when REMOTE_ID_PUBKEY is removed
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn parse_init_message(init_message: Vec<u8>) -> Result<InitMessage, HandshakeError> {
InitMessage::try_from(init_message.as_slice()).map_err(|_| HandshakeError::MalformedRequest)
pub(crate) fn parse_init_message(
mut init_message: Vec<u8>,
) -> Result<(identity::PublicKey, encryption::PublicKey), HandshakeError> {
if init_message.len() != identity::PUBLIC_KEY_LENGTH + encryption::PUBLIC_KEY_SIZE {
return Err(HandshakeError::MalformedRequest);
}
let remote_ephemeral_key_bytes = init_message.split_off(identity::PUBLIC_KEY_LENGTH);
// this can only fail if the provided bytes have len different from encryption::PUBLIC_KEY_SIZE
// which is impossible
let remote_ephemeral_key =
encryption::PublicKey::from_bytes(&remote_ephemeral_key_bytes).unwrap();
// this could actually fail if the curve point fails to get decompressed
let remote_identity = identity::PublicKey::from_bytes(&init_message)
.map_err(|_| HandshakeError::MalformedRequest)?;
Ok((remote_identity, remote_ephemeral_key))
}
pub(crate) fn derive_shared_key(&mut self, remote_ephemeral_key: &encryption::PublicKey) {
+44 -8
View File
@@ -22,6 +22,8 @@ use tungstenite::protocol::Message;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(not(feature = "coconut"))]
use credentials::token::bandwidth::TokenCredential;
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type", rename_all = "camelCase")]
@@ -117,8 +119,7 @@ pub enum ClientControlRequest {
},
#[serde(alias = "handshakePayload")]
RegisterHandshakeInitRequest { data: Vec<u8> },
#[cfg(feature = "coconut")]
CoconutBandwidthCredential {
BandwidthCredential {
enc_credential: Vec<u8>,
iv: Vec<u8>,
},
@@ -148,7 +149,7 @@ impl ClientControlRequest {
let enc_credential =
shared_key.encrypt_and_tag(&serialized_credential, Some(iv.inner()));
Some(ClientControlRequest::CoconutBandwidthCredential {
Some(ClientControlRequest::BandwidthCredential {
enc_credential,
iv: iv.to_bytes(),
})
@@ -166,6 +167,30 @@ impl ClientControlRequest {
let credential = shared_key.decrypt_tagged(&enc_credential, Some(iv.inner()))?;
bincode::deserialize(&credential).map_err(|_| GatewayRequestsError::MalformedEncryption)
}
#[cfg(not(feature = "coconut"))]
pub fn new_enc_token_bandwidth_credential(
credential: &TokenCredential,
shared_key: &SharedKeys,
iv: IV,
) -> Self {
let enc_credential = shared_key.encrypt_and_tag(&credential.to_bytes(), Some(iv.inner()));
ClientControlRequest::BandwidthCredential {
enc_credential,
iv: iv.to_bytes(),
}
}
#[cfg(not(feature = "coconut"))]
pub fn try_from_enc_token_bandwidth_credential(
enc_credential: Vec<u8>,
shared_key: &SharedKeys,
iv: IV,
) -> Result<TokenCredential, GatewayRequestsError> {
let credential = shared_key.decrypt_tagged(&enc_credential, Some(iv.inner()))?;
TokenCredential::from_bytes(&credential)
.map_err(|_| GatewayRequestsError::MalformedEncryption)
}
}
impl From<ClientControlRequest> for Message {
@@ -196,11 +221,22 @@ impl TryInto<String> for ClientControlRequest {
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum ServerResponse {
Authenticate { status: bool },
Register { status: bool },
Bandwidth { available_total: i64 },
Send { remaining_bandwidth: i64 },
Error { message: String },
Authenticate {
status: bool,
bandwidth_remaining: i64,
},
Register {
status: bool,
},
Bandwidth {
available_total: i64,
},
Send {
remaining_bandwidth: i64,
},
Error {
message: String,
},
}
impl ServerResponse {
+24 -5
View File
@@ -9,7 +9,7 @@ use config::NymConfig;
use crypto::asymmetric::{encryption, identity};
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
App::new("init")
let app = App::new("init")
.about("Initialise the gateway")
.arg(
Arg::with_name(ID_ARG_NAME)
@@ -50,11 +50,30 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.takes_value(true)
)
.arg(
Arg::with_name(VALIDATORS_ARG_NAME)
.long(VALIDATORS_ARG_NAME)
.help("Comma separated list of rest endpoints of the validators")
Arg::with_name(VALIDATOR_APIS_ARG_NAME)
.long(VALIDATOR_APIS_ARG_NAME)
.help("Comma separated list of endpoints of the validators APIs")
.takes_value(true),
)
);
#[cfg(not(feature = "coconut"))]
let app = app
.arg(Arg::with_name(ETH_ENDPOINT)
.long(ETH_ENDPOINT)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.takes_value(true)
.required(true))
.arg(Arg::with_name(VALIDATORS_ARG_NAME)
.long(VALIDATORS_ARG_NAME)
.help("Comma separated list of endpoints of the validator")
.takes_value(true))
.arg(Arg::with_name(COSMOS_MNEMONIC)
.long(COSMOS_MNEMONIC)
.help("Cosmos wallet mnemonic")
.takes_value(true)
.required(true));
app
}
fn show_bonding_info(config: &Config) {
+22 -1
View File
@@ -13,7 +13,13 @@ pub(crate) const ID_ARG_NAME: &str = "id";
pub(crate) const HOST_ARG_NAME: &str = "host";
pub(crate) const MIX_PORT_ARG_NAME: &str = "mix-port";
pub(crate) const CLIENTS_PORT_ARG_NAME: &str = "clients-port";
pub(crate) const VALIDATOR_APIS_ARG_NAME: &str = "validator-apis";
#[cfg(not(feature = "coconut"))]
pub(crate) const VALIDATORS_ARG_NAME: &str = "validators";
#[cfg(not(feature = "coconut"))]
pub(crate) const COSMOS_MNEMONIC: &str = "mnemonic";
#[cfg(not(feature = "coconut"))]
pub(crate) const ETH_ENDPOINT: &str = "eth_endpoint";
pub(crate) const ANNOUNCE_HOST_ARG_NAME: &str = "announce-host";
pub(crate) const DATASTORE_PATH: &str = "datastore";
@@ -64,13 +70,28 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
config = config.announce_host_from_listening_host()
}
if let Some(raw_validators) = matches.value_of(VALIDATORS_ARG_NAME) {
if let Some(raw_validators) = matches.value_of(VALIDATOR_APIS_ARG_NAME) {
config = config.with_custom_validator_apis(parse_validators(raw_validators));
}
#[cfg(not(feature = "coconut"))]
if let Some(raw_validators) = matches.value_of(VALIDATORS_ARG_NAME) {
config = config.with_custom_validator_nymd(parse_validators(raw_validators));
}
#[cfg(not(feature = "coconut"))]
if let Some(cosmos_mnemonic) = matches.value_of(COSMOS_MNEMONIC) {
config = config.with_cosmos_mnemonic(String::from(cosmos_mnemonic));
}
if let Some(datastore_path) = matches.value_of(DATASTORE_PATH) {
config = config.with_custom_persistent_store(datastore_path);
}
#[cfg(not(feature = "coconut"))]
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT) {
config = config.with_eth_endpoint(String::from(eth_endpoint));
}
config
}
+23 -6
View File
@@ -12,7 +12,7 @@ use log::*;
use version_checker::is_minor_version_compatible;
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
App::new("run")
let app = App::new("run")
.about("Starts the gateway")
.arg(
Arg::with_name(ID_ARG_NAME)
@@ -53,11 +53,28 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
.takes_value(true)
)
.arg(
Arg::with_name(VALIDATORS_ARG_NAME)
.long(VALIDATORS_ARG_NAME)
.help("Comma separated list of rest endpoints of the validators")
Arg::with_name(VALIDATOR_APIS_ARG_NAME)
.long(VALIDATOR_APIS_ARG_NAME)
.help("Comma separated list of endpoints of the validators APIs")
.takes_value(true),
)
);
#[cfg(not(feature = "coconut"))]
let app = app
.arg(Arg::with_name(ETH_ENDPOINT)
.long(ETH_ENDPOINT)
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
.takes_value(true))
.arg(Arg::with_name(VALIDATORS_ARG_NAME)
.long(VALIDATORS_ARG_NAME)
.help("Comma separated list of endpoints of the validator")
.takes_value(true))
.arg(Arg::with_name(COSMOS_MNEMONIC)
.long(COSMOS_MNEMONIC)
.help("Cosmos wallet mnemonic")
.takes_value(true));
app
}
fn show_binding_warning(address: String) {
@@ -149,7 +166,7 @@ pub async fn execute(matches: ArgMatches<'static>) {
}
println!(
"Validator servers: {:?}",
"Validator API servers: {:?}",
config.get_validator_api_endpoints()
);
+51
View File
@@ -127,6 +127,24 @@ impl Config {
self
}
#[cfg(not(feature = "coconut"))]
pub fn with_custom_validator_nymd(mut self, validator_nymd_urls: Vec<Url>) -> Self {
self.gateway.validator_nymd_urls = validator_nymd_urls;
self
}
#[cfg(not(feature = "coconut"))]
pub fn with_cosmos_mnemonic(mut self, cosmos_mnemonic: String) -> Self {
self.gateway.cosmos_mnemonic = cosmos_mnemonic;
self
}
#[cfg(not(feature = "coconut"))]
pub fn with_eth_endpoint(mut self, eth_endpoint: String) -> Self {
self.gateway.eth_endpoint = eth_endpoint;
self
}
pub fn with_listening_address<S: Into<String>>(mut self, listening_address: S) -> Self {
let listening_address_string = listening_address.into();
if let Ok(ip_addr) = listening_address_string.parse() {
@@ -191,10 +209,25 @@ impl Config {
self.gateway.public_sphinx_key_file.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_eth_endpoint(&self) -> String {
self.gateway.eth_endpoint.clone()
}
pub fn get_validator_api_endpoints(&self) -> Vec<Url> {
self.gateway.validator_api_urls.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_validator_nymd_endpoints(&self) -> Vec<Url> {
self.gateway.validator_nymd_urls.clone()
}
#[cfg(not(feature = "coconut"))]
pub fn get_cosmos_mnemonic(&self) -> String {
self.gateway.cosmos_mnemonic.clone()
}
pub fn get_listening_address(&self) -> IpAddr {
self.gateway.listening_address
}
@@ -281,9 +314,21 @@ pub struct Gateway {
/// Path to file containing public sphinx key.
public_sphinx_key_file: PathBuf,
/// Address to an Ethereum full node.
#[cfg(not(feature = "coconut"))]
eth_endpoint: String,
/// Addresses to APIs running on validator from which the node gets the view of the network.
validator_api_urls: Vec<Url>,
/// Addresses to validators which the node uses to check for double spending of ERC20 tokens.
#[cfg(not(feature = "coconut"))]
validator_nymd_urls: Vec<Url>,
/// Mnemonic of a cosmos wallet used for checking for double spending.
#[cfg(not(feature = "coconut"))]
cosmos_mnemonic: String,
/// nym_home_directory specifies absolute path to the home nym gateways directory.
/// It is expected to use default value and hence .toml file should not redefine this field.
nym_root_directory: PathBuf,
@@ -328,7 +373,13 @@ impl Default for Gateway {
public_identity_key_file: Default::default(),
private_sphinx_key_file: Default::default(),
public_sphinx_key_file: Default::default(),
#[cfg(not(feature = "coconut"))]
eth_endpoint: "".to_string(),
validator_api_urls: default_api_endpoints(),
#[cfg(not(feature = "coconut"))]
validator_nymd_urls: default_nymd_endpoints(),
#[cfg(not(feature = "coconut"))]
cosmos_mnemonic: "".to_string(),
nym_root_directory: Config::default_root_directory(),
persistent_storage: Default::default(),
}
+12
View File
@@ -34,6 +34,9 @@ private_sphinx_key_file = '{{ gateway.private_sphinx_key_file }}'
# Path to file containing public sphinx key.
public_sphinx_key_file = '{{ gateway.public_sphinx_key_file }}'
# Addess to an Ethereum full node.
eth_endpoint = '{{ gateway.eth_endpoint }}'
##### additional gateway config options #####
# Optional address announced to the directory server for the clients to connect to.
@@ -56,6 +59,15 @@ validator_api_urls = [
{{/each}}
]
# Addresses to validators which the node uses to check for double spending of ERC20 tokens.
validator_nymd_urls = [
{{#each gateway.validator_nymd_urls }}
'{{this}}',
{{/each}}
]
cosmos_mnemonic = "{{ gateway.cosmos_mnemonic }}"
##### advanced configuration options #####
# nym_home_directory specifies absolute path to the home nym gateway directory.
@@ -1,11 +1,17 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "coconut")]
use std::convert::TryFrom;
#[cfg(feature = "coconut")]
use coconut_interface::Credential;
#[cfg(feature = "coconut")]
use credentials::error::Error;
#[cfg(not(feature = "coconut"))]
use credentials::token::bandwidth::TokenCredential;
#[cfg(feature = "coconut")]
const BANDWIDTH_INDEX: usize = 0;
pub struct Bandwidth {
@@ -18,6 +24,7 @@ impl Bandwidth {
}
}
#[cfg(feature = "coconut")]
impl TryFrom<Credential> for Bandwidth {
type Error = Error;
@@ -34,3 +41,12 @@ impl TryFrom<Credential> for Bandwidth {
}
}
}
#[cfg(not(feature = "coconut"))]
impl From<TokenCredential> for Bandwidth {
fn from(credential: TokenCredential) -> Self {
Bandwidth {
value: credential.bandwidth(),
}
}
}
+1 -3
View File
@@ -2,7 +2,5 @@
// SPDX-License-Identifier: Apache-2.0
pub(crate) mod active_clients;
pub(crate) mod websocket;
#[cfg(feature = "coconut")]
mod bandwidth;
pub(crate) mod websocket;
@@ -17,13 +17,11 @@ use thiserror::Error;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_tungstenite::tungstenite::protocol::Message;
#[cfg(feature = "coconut")]
use crate::node::client_handling::bandwidth::Bandwidth;
#[cfg(feature = "coconut")]
use gateway_requests::iv::IV;
#[derive(Debug, Error)]
enum RequestHandlingError {
pub(crate) enum RequestHandlingError {
#[error("Internal gateway storage error")]
StorageError(#[from] StorageError),
@@ -39,13 +37,27 @@ enum RequestHandlingError {
#[error("The received request is not valid in the current context")]
IllegalRequest,
#[cfg(feature = "coconut")]
#[error("Provided bandwidth credential asks for more bandwidth than it is supported to add at once (credential value: {0}, supported: {}). Try to split it before attempting again", i64::MAX)]
UnsupportedBandwidthValue(u64),
#[cfg(feature = "coconut")]
#[error("Provided bandwidth credential did not verify correctly")]
InvalidCoconutBandwidthCredential,
InvalidBandwidthCredential,
#[cfg(not(feature = "coconut"))]
#[error("Ethereum web3 error")]
Web3Error(#[from] web3::Error),
#[cfg(not(feature = "coconut"))]
#[error("Ethereum ABI error")]
EthAbiError(#[from] web3::ethabi::Error),
#[cfg(not(feature = "coconut"))]
#[error("Ethereum contract error")]
EthContractError(#[from] web3::contract::Error),
#[cfg(not(feature = "coconut"))]
#[error("Nymd Error - {0}")]
NymdError(#[from] validator_client::nymd::error::NymdError),
#[cfg(feature = "coconut")]
#[error("Provided coconut bandwidth credential did not have expected structure - {0}")]
@@ -117,10 +129,6 @@ where
Ok(bandwidth)
}
// note: this is not technically a "coconut" thing, but currently we have no non-coconut
// bandwidth handling and hence clippy complains about dead and unreachable code
// so whenever we introduce another form of bandwidth claim, this feature flag should get removed
#[cfg(feature = "coconut")]
/// Increases the amount of available bandwidth of the connected client by the specified value.
///
/// # Arguments
@@ -180,7 +188,7 @@ where
)?;
if !credential.verify(&self.inner.aggregated_verification_key) {
return Err(RequestHandlingError::InvalidCoconutBandwidthCredential);
return Err(RequestHandlingError::InvalidBandwidthCredential);
}
let bandwidth = Bandwidth::try_from(credential)?;
@@ -202,6 +210,69 @@ where
Ok(ServerResponse::Bandwidth { available_total })
}
#[cfg(not(feature = "coconut"))]
/// Tries to handle the received bandwidth request by checking correctness of the received data
/// and if successful, increases client's bandwidth by an appropriate amount.
///
/// # Arguments
///
/// * `enc_credential`: raw encrypted bandwidth credential to verify.
/// * `iv`: fresh iv used for the credential.
async fn handle_token_bandwidth(
&mut self,
enc_credential: Vec<u8>,
iv: Vec<u8>,
) -> Result<ServerResponse, RequestHandlingError> {
let iv = IV::try_from_bytes(&iv)?;
let credential = ClientControlRequest::try_from_enc_token_bandwidth_credential(
enc_credential,
&self.client.shared_keys,
iv,
)?;
debug!("Received bandwidth increase request. Verifying signature");
if !credential.verify_signature() {
return Err(RequestHandlingError::InvalidBandwidthCredential);
}
debug!("Verifying Ethereum for token burn...");
self.inner
.erc20_bridge
.verify_eth_events(credential.verification_key())
.await?;
debug!("Claim the token on Cosmos, to make sure it's not spent twice...");
self.inner.erc20_bridge.claim_token(&credential).await?;
let bandwidth = Bandwidth::from(credential);
let bandwidth_value = bandwidth.value();
if bandwidth_value > i64::MAX as u64 {
// note that this would have represented more than 1 exabyte,
// which is like 125,000 worth of hard drives so I don't think we have
// to worry about it for now...
warn!("Somehow we received bandwidth value higher than 9223372036854775807. We don't really want to deal with this now");
return Err(RequestHandlingError::UnsupportedBandwidthValue(
bandwidth_value,
));
}
self.increase_bandwidth(bandwidth_value as i64).await?;
let available_total = self.get_available_bandwidth().await?;
debug!("Increased bandwidth for client: {:?}", self.client.address);
Ok(ServerResponse::Bandwidth { available_total })
}
async fn handle_bandwidth(
&mut self,
enc_credential: Vec<u8>,
iv: Vec<u8>,
) -> Result<ServerResponse, RequestHandlingError> {
#[cfg(feature = "coconut")]
return self.handle_coconut_bandwidth(enc_credential, iv).await;
#[cfg(not(feature = "coconut"))]
return self.handle_token_bandwidth(enc_credential, iv).await;
}
/// Tries to handle request to forward sphinx packet into the network. The request can only succeed
/// if the client has enough available bandwidth.
///
@@ -214,17 +285,8 @@ where
&self,
mix_packet: MixPacket,
) -> Result<ServerResponse, RequestHandlingError> {
// currently we have no way for increasing bandwidth hence we shouldn't be performing
// any meaningful metering. Once we have another way of claiming bandwidth, this
// feature lock should go away
#[cfg(feature = "coconut")]
// for now let's just use actual size of the sphinx packet. there's a tiny bit of overhead
// we're not including (but it's literally like 2 bytes) when the packet is framed
let consumed_bandwidth = mix_packet.sphinx_packet().len() as i64;
#[cfg(not(feature = "coconut"))]
let consumed_bandwidth = 0;
let available_bandwidth = self.get_available_bandwidth().await?;
if available_bandwidth < consumed_bandwidth {
@@ -273,9 +335,8 @@ where
match ClientControlRequest::try_from(raw_request) {
Err(e) => RequestHandlingError::InvalidTextRequest(e).into_error_message(),
Ok(request) => match request {
#[cfg(feature = "coconut")]
ClientControlRequest::CoconutBandwidthCredential { enc_credential, iv } => {
match self.handle_coconut_bandwidth(enc_credential, iv).await {
ClientControlRequest::BandwidthCredential { enc_credential, iv } => {
match self.handle_bandwidth(enc_credential, iv).await {
Ok(response) => response.into(),
Err(err) => err.into_error_message(),
}
@@ -0,0 +1,204 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use bip39::core::str::FromStr;
use bip39::Mnemonic;
use rand::seq::SliceRandom;
use rand::thread_rng;
use url::Url;
use web3::contract::tokens::Detokenize;
use web3::contract::{Contract, Error};
use web3::ethabi::Token;
use web3::transports::Http;
use web3::types::{BlockNumber, FilterBuilder, H256};
use web3::Web3;
use crate::node::client_handling::websocket::connection_handler::authenticated::RequestHandlingError;
use credentials::token::bandwidth::TokenCredential;
use crypto::asymmetric::identity::{PublicKey, Signature};
use erc20_bridge_contract::msg::ExecuteMsg;
use erc20_bridge_contract::payment::LinkPaymentData;
use gateway_client::bandwidth::eth_contract;
use network_defaults::{COSMOS_CONTRACT_ADDRESS, DENOM, ETH_EVENT_NAME, ETH_MIN_BLOCK_DEPTH};
use validator_client::nymd::{
AccountId, CosmosCoin, Decimal, Denom, Fee, Gas, NymdClient, SigningNymdClient,
};
pub(crate) struct ERC20Bridge {
// This is needed because web3's Contract doesn't sufficiently expose it's eth interface
web3: Web3<Http>,
contract: Contract<Http>,
nymd_client: NymdClient<SigningNymdClient>,
}
impl ERC20Bridge {
pub fn new(eth_endpoint: String, nymd_urls: Vec<Url>, cosmos_mnemonic: String) -> Self {
let transport = Http::new(&eth_endpoint).expect("Invalid Ethereum endpoint");
let web3 = Web3::new(transport);
let nymd_url = nymd_urls
.choose(&mut thread_rng())
.expect("The list of validators is empty");
let mnemonic =
Mnemonic::from_str(&cosmos_mnemonic).expect("Invalid Cosmos mnemonic provided");
let nymd_client = NymdClient::connect_with_mnemonic(
nymd_url.as_ref(),
AccountId::from_str(COSMOS_CONTRACT_ADDRESS).ok(),
mnemonic,
)
.expect("Could not create nymd client");
ERC20Bridge {
contract: eth_contract(web3.clone()),
web3,
nymd_client,
}
}
pub(crate) async fn verify_eth_events(
&self,
verification_key: PublicKey,
) -> Result<(), RequestHandlingError> {
// It's safe to unwrap here, as we are guarded by a unit test that checks the event
// name constant against the contract abi
let event = self.contract.abi().event(ETH_EVENT_NAME).unwrap();
let latest_block = self.web3.eth().block_number().await?;
let check_until = if cfg!(debug_assertions) {
latest_block
} else {
latest_block - ETH_MIN_BLOCK_DEPTH
};
let filter = FilterBuilder::default()
.address(vec![self.contract.address()])
.topics(
Some(vec![event.signature()]),
Some(vec![H256::from(verification_key.to_bytes())]),
None,
None,
)
.from_block(BlockNumber::Earliest)
.to_block(BlockNumber::Number(check_until))
.build();
// Get only the first event that checks out. If the client burns more tokens with the
// same verification key, those token would be lost
for l in self.web3.eth().logs(filter).await? {
let log = event.parse_log(web3::ethabi::RawLog {
topics: l.topics,
data: l.data.0,
})?;
let burned_event =
Burned::from_tokens(log.params.into_iter().map(|x| x.value).collect::<Vec<_>>())?;
if burned_event.verify(verification_key) {
return Ok(());
}
}
Err(RequestHandlingError::InvalidBandwidthCredential)
}
pub(crate) async fn claim_token(
&self,
credential: &TokenCredential,
) -> Result<(), RequestHandlingError> {
// It's ok to unwrap here, as the cosmos contract and denom are set correctly
let contract_address = self.nymd_client.contract_address().unwrap();
let coin = CosmosCoin {
denom: Denom::from_str(DENOM).unwrap(),
amount: Decimal::from(100000u64),
};
let fee = Fee::from_amount_and_gas(coin.clone(), Gas::from(500000));
let req = ExecuteMsg::LinkPayment {
data: LinkPaymentData::new(
credential.verification_key().to_bytes(),
credential.gateway_identity().to_bytes(),
credential.bandwidth(),
credential.signature_bytes(),
),
};
self.nymd_client
.execute(
// it's ok to unwrap here, as the address is
contract_address,
&req,
fee,
"Linking payment",
vec![coin],
)
.await?;
Ok(())
}
}
#[derive(Debug)]
pub struct Burned {
/// The bandwidth bought by the client
pub bandwidth: u64,
/// Client public verification key
pub verification_key: PublicKey,
/// Signed verification key
pub signed_verification_key: Signature,
}
impl Burned {
pub fn verify(&self, verification_key: PublicKey) -> bool {
self.verification_key == verification_key
&& verification_key
.verify(
&self.verification_key.to_bytes(),
&self.signed_verification_key,
)
.is_ok()
}
}
impl Detokenize for Burned {
fn from_tokens(tokens: Vec<Token>) -> Result<Self, Error>
where
Self: Sized,
{
if tokens.len() != 3 {
return Err(Error::InvalidOutputType(format!(
"Expected three elements, got: {:?}",
tokens
)));
}
let bandwidth = tokens
.get(0)
.unwrap()
.clone()
.into_uint()
.ok_or_else(|| Error::InvalidOutputType(String::from("Expected Uint for bandwidth")))?
.as_u64();
let verification_key: [u8; 32] = tokens
.get(1)
.unwrap()
.clone()
.into_uint()
.ok_or_else(|| {
Error::InvalidOutputType(String::from("Expected Uint for verification key"))
})?
.into();
let verification_key = PublicKey::from_bytes(&verification_key).map_err(|_| {
Error::InvalidOutputType(format!(
"Expected verification key of 32 bytes, got: {}",
verification_key.len()
))
})?;
let signed_verification_key =
tokens.get(2).unwrap().clone().into_bytes().ok_or_else(|| {
Error::InvalidOutputType(String::from("Expected Bytes for signed_verification_key"))
})?;
let signed_verification_key =
Signature::from_bytes(&signed_verification_key).map_err(|_| {
Error::InvalidOutputType(format!(
"Expected signature of 64 bytes, got: {}",
signed_verification_key.len()
))
})?;
Ok(Burned {
bandwidth,
verification_key,
signed_verification_key,
})
}
}
@@ -30,6 +30,9 @@ use tokio_tungstenite::tungstenite::{protocol::Message, Error as WsError};
#[cfg(feature = "coconut")]
use coconut_interface::VerificationKey;
#[cfg(not(feature = "coconut"))]
use crate::node::client_handling::websocket::connection_handler::eth_events::ERC20Bridge;
#[derive(Debug, Error)]
enum InitialAuthenticationError {
#[error("Internal gateway storage error")]
@@ -75,6 +78,9 @@ pub(crate) struct FreshHandler<R, S> {
#[cfg(feature = "coconut")]
pub(crate) aggregated_verification_key: VerificationKey,
#[cfg(not(feature = "coconut"))]
pub(crate) erc20_bridge: Arc<ERC20Bridge>,
}
impl<R, S> FreshHandler<R, S>
@@ -91,6 +97,7 @@ where
storage: PersistentStorage,
active_clients_store: ActiveClientsStore,
#[cfg(feature = "coconut")] aggregated_verification_key: VerificationKey,
#[cfg(not(feature = "coconut"))] erc20_bridge: Arc<ERC20Bridge>,
) -> Self {
FreshHandler {
rng,
@@ -101,6 +108,8 @@ where
storage,
#[cfg(feature = "coconut")]
aggregated_verification_key,
#[cfg(not(feature = "coconut"))]
erc20_bridge,
}
}
@@ -394,12 +403,20 @@ where
.authenticate_client(address, encrypted_address, iv)
.await?;
let status = shared_keys.is_some();
let bandwidth_remaining = self
.storage
.get_available_bandwidth(address)
.await?
.unwrap_or(0);
let client_details =
shared_keys.map(|shared_keys| ClientDetails::new(address, shared_keys));
Ok(InitialAuthResult::new(
client_details,
ServerResponse::Authenticate { status },
ServerResponse::Authenticate {
status,
bandwidth_remaining,
},
))
}
@@ -497,11 +514,6 @@ where
ClientControlRequest::RegisterHandshakeInitRequest { data } => {
self.handle_register(data).await
}
// note: this is not technically a "coconut" thing, but currently we have no non-coconut
// bandwidth handling and hence clippy complains about dead and unreachable code
// so whenever we introduce another form of bandwidth claim, this feature flag should get removed
#[cfg(feature = "coconut")]
// won't accept anything else (like bandwidth) without prior authentication
_ => Err(InitialAuthenticationError::InvalidRequest),
}
@@ -13,6 +13,8 @@ pub(crate) use self::authenticated::AuthenticatedHandler;
pub(crate) use self::fresh::FreshHandler;
mod authenticated;
#[cfg(not(feature = "coconut"))]
pub(crate) mod eth_events;
mod fresh;
//// TODO: note for my future self to consider the following idea:
@@ -16,12 +16,18 @@ use tokio::task::JoinHandle;
#[cfg(feature = "coconut")]
use coconut_interface::VerificationKey;
#[cfg(not(feature = "coconut"))]
use crate::node::client_handling::websocket::connection_handler::eth_events::ERC20Bridge;
pub(crate) struct Listener {
address: SocketAddr,
local_identity: Arc<identity::KeyPair>,
#[cfg(feature = "coconut")]
aggregated_verification_key: VerificationKey,
#[cfg(not(feature = "coconut"))]
erc20_bridge: Arc<ERC20Bridge>,
}
impl Listener {
@@ -29,12 +35,15 @@ impl Listener {
address: SocketAddr,
local_identity: Arc<identity::KeyPair>,
#[cfg(feature = "coconut")] aggregated_verification_key: VerificationKey,
#[cfg(not(feature = "coconut"))] erc20_bridge: ERC20Bridge,
) -> Self {
Listener {
address,
local_identity,
#[cfg(feature = "coconut")]
aggregated_verification_key,
#[cfg(not(feature = "coconut"))]
erc20_bridge: Arc::new(erc20_bridge),
}
}
@@ -70,6 +79,8 @@ impl Listener {
active_clients_store.clone(),
#[cfg(feature = "coconut")]
self.aggregated_verification_key.clone(),
#[cfg(not(feature = "coconut"))]
Arc::clone(&self.erc20_bridge),
);
tokio::spawn(async move { handle.start_handling().await });
}
+14
View File
@@ -15,6 +15,8 @@ use std::net::SocketAddr;
use std::process;
use std::sync::Arc;
#[cfg(not(feature = "coconut"))]
use crate::node::client_handling::websocket::connection_handler::eth_events::ERC20Bridge;
#[cfg(feature = "coconut")]
use coconut_interface::VerificationKey;
#[cfg(feature = "coconut")]
@@ -88,6 +90,7 @@ impl Gateway {
forwarding_channel: MixForwardingSender,
active_clients_store: ActiveClientsStore,
#[cfg(feature = "coconut")] verification_key: VerificationKey,
#[cfg(not(feature = "coconut"))] erc20_bridge: ERC20Bridge,
) {
info!("Starting client [web]socket listener...");
@@ -101,6 +104,8 @@ impl Gateway {
Arc::clone(&self.identity),
#[cfg(feature = "coconut")]
verification_key,
#[cfg(not(feature = "coconut"))]
erc20_bridge,
)
.start(
forwarding_channel,
@@ -180,6 +185,13 @@ impl Gateway {
.await
.expect("failed to contact validators to obtain their verification keys");
#[cfg(not(feature = "coconut"))]
let erc20_bridge = ERC20Bridge::new(
self.config.get_eth_endpoint(),
self.config.get_validator_nymd_endpoints(),
self.config.get_cosmos_mnemonic(),
);
let mix_forwarding_channel = self.start_packet_forwarder();
let active_clients_store = ActiveClientsStore::new();
@@ -193,6 +205,8 @@ impl Gateway {
active_clients_store,
#[cfg(feature = "coconut")]
validators_verification_key,
#[cfg(not(feature = "coconut"))]
erc20_bridge,
);
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
-4
View File
@@ -54,10 +54,6 @@ impl BandwidthManager {
.await
}
// note: this is not technically a "coconut" thing, but currently we have no non-coconut
// bandwidth handling and hence clippy complains about dead and unreachable code
// so whenever we introduce another form of bandwidth claim, this feature flag should get removed
#[cfg(feature = "coconut")]
/// Increases available bandwidth of the particular client by the specified amount.
///
/// # Arguments
-4
View File
@@ -211,10 +211,6 @@ impl PersistentStorage {
Ok(res)
}
// note: this is not technically a "coconut" thing, but currently we have no non-coconut
// bandwidth handling and hence clippy complains about dead and unreachable code
// so whenever we introduce another form of bandwidth claim, this feature flag should get removed
#[cfg(feature = "coconut")]
/// Increases available bandwidth of the particular client by the specified amount.
///
/// # Arguments
+255 -13
View File
@@ -24,6 +24,19 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "aes"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if 1.0.0",
"cipher",
"cpufeatures",
"ctr",
"opaque-debug 0.3.0",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@@ -130,6 +143,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "az"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325"
[[package]]
name = "base64"
version = "0.13.0"
@@ -157,7 +176,7 @@ dependencies = [
"k256",
"ripemd160",
"sha2",
"subtle",
"subtle 2.4.1",
"zeroize",
]
@@ -186,6 +205,18 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blake2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330"
dependencies = [
"byte-tools",
"crypto-mac 0.7.0",
"digest 0.8.1",
"opaque-debug 0.2.3",
]
[[package]]
name = "blake3"
version = "1.0.0"
@@ -197,6 +228,7 @@ dependencies = [
"cc",
"cfg-if 1.0.0",
"constant_time_eq",
"crypto-mac 0.11.1",
"digest 0.9.0",
"rayon",
]
@@ -255,7 +287,7 @@ dependencies = [
"group",
"pairing",
"rand_core 0.6.3",
"subtle",
"subtle 2.4.1",
]
[[package]]
@@ -288,6 +320,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -391,6 +429,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chacha"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddf3c081b5fba1e5615640aae998e0fbd10c24cbd897ee39ed754a77601a4862"
dependencies = [
"byteorder",
"keystream",
]
[[package]]
name = "chrono"
version = "0.4.19"
@@ -402,6 +450,15 @@ dependencies = [
"serde",
]
[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
@@ -705,6 +762,8 @@ name = "credentials"
version = "0.1.0"
dependencies = [
"coconut-interface",
"crypto",
"network-defaults",
"thiserror",
"url",
"validator-client",
@@ -760,6 +819,26 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto"
version = "0.1.0"
dependencies = [
"aes",
"blake3",
"bs58",
"cipher",
"digest 0.9.0",
"ed25519-dalek",
"generic-array 0.14.4",
"hkdf",
"hmac",
"log",
"nymsphinx-types",
"pemstore",
"rand 0.7.3",
"x25519-dalek",
]
[[package]]
name = "crypto-bigint"
version = "0.2.6"
@@ -768,10 +847,20 @@ checksum = "e49339137316df1914fdb54a5eae75a73f45068fd0d2178fe235b11d93238a6e"
dependencies = [
"generic-array 0.14.4",
"rand_core 0.6.3",
"subtle",
"subtle 2.4.1",
"zeroize",
]
[[package]]
name = "crypto-mac"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
dependencies = [
"generic-array 0.12.4",
"subtle 1.0.0",
]
[[package]]
name = "crypto-mac"
version = "0.11.1"
@@ -779,7 +868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
"generic-array 0.14.4",
"subtle",
"subtle 2.4.1",
]
[[package]]
@@ -818,6 +907,15 @@ dependencies = [
"sct",
]
[[package]]
name = "ctr"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
dependencies = [
"cipher",
]
[[package]]
name = "curve25519-dalek"
version = "3.2.0"
@@ -827,7 +925,7 @@ dependencies = [
"byteorder",
"digest 0.9.0",
"rand_core 0.5.1",
"subtle",
"subtle 2.4.1",
"zeroize",
]
@@ -1073,6 +1171,8 @@ checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
dependencies = [
"curve25519-dalek",
"ed25519",
"rand 0.7.3",
"serde",
"sha2",
"zeroize",
]
@@ -1109,7 +1209,7 @@ dependencies = [
"group",
"pkcs8",
"rand_core 0.6.3",
"subtle",
"subtle 2.4.1",
"zeroize",
]
@@ -1172,7 +1272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
dependencies = [
"rand_core 0.6.3",
"subtle",
"subtle 2.4.1",
]
[[package]]
@@ -1197,6 +1297,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "fixed"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d333a26ec13a023c6dff4b7584de4d323cfee2e508f5dd2bbee6669e4f7efdf"
dependencies = [
"az",
"bytemuck",
"half",
"typenum",
]
[[package]]
name = "flate2"
version = "1.0.21"
@@ -1493,8 +1605,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
"wasm-bindgen",
]
[[package]]
@@ -1663,7 +1777,7 @@ dependencies = [
"byteorder",
"ff",
"rand_core 0.6.3",
"subtle",
"subtle 2.4.1",
]
[[package]]
@@ -1741,6 +1855,12 @@ dependencies = [
"tracing",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "handlebars"
version = "3.5.5"
@@ -1810,6 +1930,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hex-literal"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b"
[[package]]
name = "hkd32"
version = "0.6.0"
@@ -1824,13 +1950,23 @@ dependencies = [
"zeroize",
]
[[package]]
name = "hkdf"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b"
dependencies = [
"digest 0.9.0",
"hmac",
]
[[package]]
name = "hmac"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [
"crypto-mac",
"crypto-mac 0.11.1",
"digest 0.9.0",
]
@@ -2161,6 +2297,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
[[package]]
name = "keystream"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28"
[[package]]
name = "kuchiki"
version = "0.8.1"
@@ -2185,6 +2327,24 @@ version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
[[package]]
name = "libm"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
[[package]]
name = "lioness"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9"
dependencies = [
"arrayref",
"blake2",
"chacha",
"keystream",
]
[[package]]
name = "lock_api"
version = "0.4.5"
@@ -2329,10 +2489,15 @@ dependencies = [
name = "mixnet-contract"
version = "0.1.0"
dependencies = [
"az",
"cosmwasm-std",
"fixed",
"log",
"network-defaults",
"schemars",
"serde",
"serde_repr",
"thiserror",
"ts-rs",
]
@@ -2404,6 +2569,7 @@ checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d"
name = "network-defaults"
version = "0.1.0"
dependencies = [
"hex-literal",
"serde",
"time 0.3.3",
"url",
@@ -2481,6 +2647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg 1.0.1",
"libm",
]
[[package]]
@@ -2540,6 +2707,13 @@ dependencies = [
"validator-client",
]
[[package]]
name = "nymsphinx-types"
version = "0.1.0"
dependencies = [
"sphinx",
]
[[package]]
name = "objc"
version = "0.2.7"
@@ -2706,7 +2880,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa"
dependencies = [
"crypto-mac",
"crypto-mac 0.11.1",
]
[[package]]
@@ -2736,6 +2910,24 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088"
[[package]]
name = "pem"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
dependencies = [
"base64",
"once_cell",
"regex",
]
[[package]]
name = "pemstore"
version = "0.1.0"
dependencies = [
"pem",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
@@ -3198,6 +3390,16 @@ dependencies = [
"getrandom 0.2.3",
]
[[package]]
name = "rand_distr"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e9532ada3929fb8b2e9dbe28d1e06c9b2cc65813f074fcb6bd5fbefeff9d56"
dependencies = [
"num-traits",
"rand 0.7.3",
]
[[package]]
name = "rand_hc"
version = "0.1.0"
@@ -3854,6 +4056,29 @@ dependencies = [
"system-deps 1.3.2",
]
[[package]]
name = "sphinx"
version = "0.1.0"
source = "git+https://github.com/nymtech/sphinx?rev=c494250f2a78bed33a618d470792418eee932859#c494250f2a78bed33a618d470792418eee932859"
dependencies = [
"aes",
"arrayref",
"blake2",
"bs58",
"byteorder",
"chacha",
"curve25519-dalek",
"digest 0.9.0",
"hkdf",
"hmac",
"lioness",
"log",
"rand 0.7.3",
"rand_distr",
"sha2",
"subtle 2.4.1",
]
[[package]]
name = "spin"
version = "0.5.2"
@@ -3970,6 +4195,12 @@ dependencies = [
"syn",
]
[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
[[package]]
name = "subtle"
version = "2.4.1"
@@ -4408,7 +4639,7 @@ dependencies = [
"serde_repr",
"sha2",
"signature",
"subtle",
"subtle 2.4.1",
"subtle-encoding",
"tendermint-proto",
"zeroize",
@@ -5136,6 +5367,17 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "x25519-dalek"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077"
dependencies = [
"curve25519-dalek",
"rand_core 0.5.1",
"zeroize",
]
[[package]]
name = "xattr"
version = "0.2.2"
@@ -5147,9 +5389,9 @@ dependencies = [
[[package]]
name = "zeroize"
version = "1.4.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "377db0846015f7ae377174787dd452e1c5f5a9050bc6f954911d01f116daa0cd"
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
dependencies = [
"zeroize_derive",
]
@@ -17,6 +17,7 @@ pub struct TauriStateParams {
minimum_gateway_bond: String,
mixnode_bond_reward_rate: String,
mixnode_delegation_reward_rate: String,
mixnode_rewarded_set_size: u32,
mixnode_active_set_size: u32,
}
@@ -28,6 +29,7 @@ impl From<StateParams> for TauriStateParams {
minimum_gateway_bond: p.minimum_gateway_bond.to_string(),
mixnode_bond_reward_rate: p.mixnode_bond_reward_rate.to_string(),
mixnode_delegation_reward_rate: p.mixnode_delegation_reward_rate.to_string(),
mixnode_rewarded_set_size: p.mixnode_rewarded_set_size,
mixnode_active_set_size: p.mixnode_active_set_size,
}
}
@@ -43,6 +45,7 @@ impl TryFrom<TauriStateParams> for StateParams {
minimum_gateway_bond: Uint128::try_from(p.minimum_gateway_bond.as_str())?,
mixnode_bond_reward_rate: Decimal::from_str(p.mixnode_bond_reward_rate.as_str())?,
mixnode_delegation_reward_rate: Decimal::from_str(p.mixnode_delegation_reward_rate.as_str())?,
mixnode_rewarded_set_size: p.mixnode_rewarded_set_size,
mixnode_active_set_size: p.mixnode_active_set_size,
})
}

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