├── .env ├── .github └── workflows │ └── compile.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── scripts └── end_to_end.sh ├── src ├── bin │ └── main.rs ├── lib.rs └── params.rs └── uml ├── decision.png └── decision.uml /.env: -------------------------------------------------------------------------------- 1 | RUST_BACKTRACE=1 2 | RUST_LOG=debug 3 | -------------------------------------------------------------------------------- /.github/workflows/compile.yml: -------------------------------------------------------------------------------- 1 | name: Compile 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | env: 8 | RUST_BACKTRACE: 1 9 | 10 | jobs: 11 | style: 12 | name: Check Style 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v1 17 | 18 | - name: Cache cargo registry 19 | uses: actions/cache@v2 20 | with: 21 | path: ~/.cargo/registry 22 | key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} 23 | 24 | - name: Cache cargo index 25 | uses: actions/cache@v2 26 | with: 27 | path: ~/.cargo/git 28 | key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} 29 | 30 | - name: Cache cargo target 31 | uses: actions/cache@v2 32 | with: 33 | path: target 34 | key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} 35 | 36 | - name: Install Rust 37 | uses: actions-rs/toolchain@v1 38 | with: 39 | profile: minimal 40 | toolchain: stable 41 | override: true 42 | components: rustfmt 43 | 44 | - name: cargo fmt --check 45 | uses: actions-rs/cargo@v1 46 | env: 47 | CARGO_NET_GIT_FETCH_WITH_CLI: true 48 | with: 49 | command: fmt 50 | args: --all -- --check 51 | 52 | test: 53 | name: Test 54 | runs-on: ubuntu-latest 55 | env: 56 | RUSTFLAGS: -Dwarnings 57 | strategy: 58 | matrix: 59 | rust: 60 | - stable 61 | steps: 62 | - name: Checkout 63 | uses: actions/checkout@v2 64 | 65 | - name: Cache cargo registry 66 | uses: actions/cache@v2 67 | with: 68 | path: ~/.cargo/registry 69 | key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} 70 | 71 | - name: Cache cargo index 72 | uses: actions/cache@v2 73 | with: 74 | path: ~/.cargo/git 75 | key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} 76 | 77 | - name: Cache cargo target 78 | uses: actions/cache@v2 79 | with: 80 | path: target 81 | key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} 82 | 83 | - name: Install Rust (${{ matrix.rust }}) 84 | uses: actions-rs/toolchain@v1 85 | with: 86 | profile: minimal 87 | toolchain: ${{ matrix.rust }} 88 | override: true 89 | 90 | - name: Test 91 | uses: actions-rs/cargo@v1 92 | with: 93 | command: test 94 | args: --release --all --no-fail-fast 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | # Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | 13 | # Added by cargo 14 | 15 | /target 16 | 17 | sftp-config.json 18 | 19 | .idea -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.16.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "0.7.18" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "ansi_term" 31 | version = "0.12.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 34 | dependencies = [ 35 | "winapi", 36 | ] 37 | 38 | [[package]] 39 | name = "anyhow" 40 | version = "1.0.42" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" 43 | 44 | [[package]] 45 | name = "arrayref" 46 | version = "0.3.6" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 49 | 50 | [[package]] 51 | name = "arrayvec" 52 | version = "0.5.2" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 55 | 56 | [[package]] 57 | name = "ascii" 58 | version = "0.9.3" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" 61 | 62 | [[package]] 63 | name = "atty" 64 | version = "0.2.14" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 67 | dependencies = [ 68 | "hermit-abi", 69 | "libc", 70 | "winapi", 71 | ] 72 | 73 | [[package]] 74 | name = "autocfg" 75 | version = "1.0.1" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 78 | 79 | [[package]] 80 | name = "backtrace" 81 | version = "0.3.61" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" 84 | dependencies = [ 85 | "addr2line", 86 | "cc", 87 | "cfg-if", 88 | "libc", 89 | "miniz_oxide", 90 | "object", 91 | "rustc-demangle", 92 | ] 93 | 94 | [[package]] 95 | name = "base64" 96 | version = "0.13.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 99 | 100 | [[package]] 101 | name = "bigdecimal" 102 | version = "0.2.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "cc403c26e6b03005522e6e8053384c4e881dfe5b2bf041c0c2c49be33d64a539" 105 | dependencies = [ 106 | "num-bigint", 107 | "num-integer", 108 | "num-traits", 109 | ] 110 | 111 | [[package]] 112 | name = "bitflags" 113 | version = "1.2.1" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 116 | 117 | [[package]] 118 | name = "blake2b_simd" 119 | version = "0.5.11" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" 122 | dependencies = [ 123 | "arrayref", 124 | "arrayvec", 125 | "constant_time_eq", 126 | ] 127 | 128 | [[package]] 129 | name = "block-buffer" 130 | version = "0.9.0" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 133 | dependencies = [ 134 | "generic-array", 135 | ] 136 | 137 | [[package]] 138 | name = "bs58" 139 | version = "0.4.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" 142 | dependencies = [ 143 | "sha2", 144 | ] 145 | 146 | [[package]] 147 | name = "bumpalo" 148 | version = "3.7.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" 151 | 152 | [[package]] 153 | name = "byteorder" 154 | version = "1.4.3" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 157 | 158 | [[package]] 159 | name = "bytes" 160 | version = "1.0.1" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" 163 | 164 | [[package]] 165 | name = "cc" 166 | version = "1.0.69" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" 169 | 170 | [[package]] 171 | name = "cfg-if" 172 | version = "1.0.0" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 175 | 176 | [[package]] 177 | name = "chrono" 178 | version = "0.4.19" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 181 | dependencies = [ 182 | "libc", 183 | "num-integer", 184 | "num-traits", 185 | "serde", 186 | "time", 187 | "winapi", 188 | ] 189 | 190 | [[package]] 191 | name = "clap-v3" 192 | version = "3.0.0-beta.1" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "bfac055d61c39ace5061621530f7f55651a261a4fba296ce1bad06d41a8de65e" 195 | dependencies = [ 196 | "ansi_term", 197 | "atty", 198 | "bitflags", 199 | "clap_derive-v3", 200 | "indexmap", 201 | "lazy_static", 202 | "strsim", 203 | "textwrap", 204 | "unicode-width", 205 | "vec_map", 206 | ] 207 | 208 | [[package]] 209 | name = "clap_derive-v3" 210 | version = "3.0.0-beta.1" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "c6dd675567eb3e35787bd2583d129e85fabc7503b0a093d08c51198a307e2091" 213 | dependencies = [ 214 | "heck", 215 | "proc-macro-error", 216 | "proc-macro2", 217 | "quote", 218 | "syn", 219 | ] 220 | 221 | [[package]] 222 | name = "combine" 223 | version = "3.8.1" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" 226 | dependencies = [ 227 | "ascii", 228 | "byteorder", 229 | "either", 230 | "memchr", 231 | "unreachable", 232 | ] 233 | 234 | [[package]] 235 | name = "constant_time_eq" 236 | version = "0.1.5" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 239 | 240 | [[package]] 241 | name = "core-foundation" 242 | version = "0.9.1" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" 245 | dependencies = [ 246 | "core-foundation-sys", 247 | "libc", 248 | ] 249 | 250 | [[package]] 251 | name = "core-foundation-sys" 252 | version = "0.8.2" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" 255 | 256 | [[package]] 257 | name = "cpufeatures" 258 | version = "0.1.5" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" 261 | dependencies = [ 262 | "libc", 263 | ] 264 | 265 | [[package]] 266 | name = "digest" 267 | version = "0.9.0" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 270 | dependencies = [ 271 | "generic-array", 272 | ] 273 | 274 | [[package]] 275 | name = "doc-comment" 276 | version = "0.3.3" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 279 | 280 | [[package]] 281 | name = "dotenv" 282 | version = "0.15.0" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" 285 | 286 | [[package]] 287 | name = "either" 288 | version = "1.6.1" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 291 | 292 | [[package]] 293 | name = "encoding_rs" 294 | version = "0.8.28" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" 297 | dependencies = [ 298 | "cfg-if", 299 | ] 300 | 301 | [[package]] 302 | name = "env_logger" 303 | version = "0.5.13" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" 306 | dependencies = [ 307 | "atty", 308 | "humantime", 309 | "log", 310 | "regex", 311 | "termcolor", 312 | ] 313 | 314 | [[package]] 315 | name = "failure" 316 | version = "0.1.8" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 319 | dependencies = [ 320 | "backtrace", 321 | "failure_derive", 322 | ] 323 | 324 | [[package]] 325 | name = "failure_derive" 326 | version = "0.1.8" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 329 | dependencies = [ 330 | "proc-macro2", 331 | "quote", 332 | "syn", 333 | "synstructure", 334 | ] 335 | 336 | [[package]] 337 | name = "fnv" 338 | version = "1.0.7" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 341 | 342 | [[package]] 343 | name = "foreign-types" 344 | version = "0.3.2" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 347 | dependencies = [ 348 | "foreign-types-shared", 349 | ] 350 | 351 | [[package]] 352 | name = "foreign-types-shared" 353 | version = "0.1.1" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 356 | 357 | [[package]] 358 | name = "form_urlencoded" 359 | version = "1.0.1" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 362 | dependencies = [ 363 | "matches", 364 | "percent-encoding", 365 | ] 366 | 367 | [[package]] 368 | name = "futures" 369 | version = "0.3.16" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" 372 | dependencies = [ 373 | "futures-channel", 374 | "futures-core", 375 | "futures-executor", 376 | "futures-io", 377 | "futures-sink", 378 | "futures-task", 379 | "futures-util", 380 | ] 381 | 382 | [[package]] 383 | name = "futures-channel" 384 | version = "0.3.16" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" 387 | dependencies = [ 388 | "futures-core", 389 | "futures-sink", 390 | ] 391 | 392 | [[package]] 393 | name = "futures-core" 394 | version = "0.3.16" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" 397 | 398 | [[package]] 399 | name = "futures-executor" 400 | version = "0.3.16" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" 403 | dependencies = [ 404 | "futures-core", 405 | "futures-task", 406 | "futures-util", 407 | ] 408 | 409 | [[package]] 410 | name = "futures-io" 411 | version = "0.3.16" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" 414 | 415 | [[package]] 416 | name = "futures-macro" 417 | version = "0.3.16" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" 420 | dependencies = [ 421 | "autocfg", 422 | "proc-macro-hack", 423 | "proc-macro2", 424 | "quote", 425 | "syn", 426 | ] 427 | 428 | [[package]] 429 | name = "futures-sink" 430 | version = "0.3.16" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" 433 | 434 | [[package]] 435 | name = "futures-task" 436 | version = "0.3.16" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" 439 | 440 | [[package]] 441 | name = "futures-util" 442 | version = "0.3.16" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" 445 | dependencies = [ 446 | "autocfg", 447 | "futures-channel", 448 | "futures-core", 449 | "futures-io", 450 | "futures-macro", 451 | "futures-sink", 452 | "futures-task", 453 | "memchr", 454 | "pin-project-lite", 455 | "pin-utils", 456 | "proc-macro-hack", 457 | "proc-macro-nested", 458 | "slab", 459 | ] 460 | 461 | [[package]] 462 | name = "generic-array" 463 | version = "0.14.4" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 466 | dependencies = [ 467 | "typenum", 468 | "version_check", 469 | ] 470 | 471 | [[package]] 472 | name = "getrandom" 473 | version = "0.2.3" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" 476 | dependencies = [ 477 | "cfg-if", 478 | "libc", 479 | "wasi", 480 | ] 481 | 482 | [[package]] 483 | name = "gimli" 484 | version = "0.25.0" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" 487 | 488 | [[package]] 489 | name = "graphql-introspection-query" 490 | version = "0.1.0" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "610aac641dbd2a457ad4cef34aa2827dae3f035fd214cb38c2d62d8543f3973f" 493 | dependencies = [ 494 | "serde", 495 | ] 496 | 497 | [[package]] 498 | name = "graphql-parser" 499 | version = "0.2.3" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "a5613c31f18676f164112732202124f373bb2103ff017b3b85ca954ea6a66ada" 502 | dependencies = [ 503 | "combine", 504 | "failure", 505 | ] 506 | 507 | [[package]] 508 | name = "graphql_client" 509 | version = "0.9.0" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "a0bb4f09181e4f80018d01c612125b07e0156f3753bfac37055fe2a25e031ca8" 512 | dependencies = [ 513 | "doc-comment", 514 | "graphql_query_derive", 515 | "serde", 516 | "serde_json", 517 | ] 518 | 519 | [[package]] 520 | name = "graphql_client_codegen" 521 | version = "0.9.0" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "8e304c223c809b3bff4614018f8e6d9edb176b31d64ed9ea48b6ae8b1a03abb9" 524 | dependencies = [ 525 | "failure", 526 | "graphql-introspection-query", 527 | "graphql-parser", 528 | "heck", 529 | "lazy_static", 530 | "proc-macro2", 531 | "quote", 532 | "serde", 533 | "serde_json", 534 | "syn", 535 | ] 536 | 537 | [[package]] 538 | name = "graphql_query_derive" 539 | version = "0.9.0" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "e1f6b14d5ce549227aa9e649cd9d36d008b91021275a8e0a67d71cef815adc2f" 542 | dependencies = [ 543 | "failure", 544 | "graphql_client_codegen", 545 | "proc-macro2", 546 | "syn", 547 | ] 548 | 549 | [[package]] 550 | name = "h2" 551 | version = "0.3.3" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726" 554 | dependencies = [ 555 | "bytes", 556 | "fnv", 557 | "futures-core", 558 | "futures-sink", 559 | "futures-util", 560 | "http", 561 | "indexmap", 562 | "slab", 563 | "tokio", 564 | "tokio-util", 565 | "tracing", 566 | ] 567 | 568 | [[package]] 569 | name = "hashbrown" 570 | version = "0.11.2" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 573 | 574 | [[package]] 575 | name = "heck" 576 | version = "0.3.3" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 579 | dependencies = [ 580 | "unicode-segmentation", 581 | ] 582 | 583 | [[package]] 584 | name = "hermit-abi" 585 | version = "0.1.19" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 588 | dependencies = [ 589 | "libc", 590 | ] 591 | 592 | [[package]] 593 | name = "http" 594 | version = "0.2.4" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" 597 | dependencies = [ 598 | "bytes", 599 | "fnv", 600 | "itoa", 601 | ] 602 | 603 | [[package]] 604 | name = "http-body" 605 | version = "0.4.2" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" 608 | dependencies = [ 609 | "bytes", 610 | "http", 611 | "pin-project-lite", 612 | ] 613 | 614 | [[package]] 615 | name = "httparse" 616 | version = "1.4.1" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" 619 | 620 | [[package]] 621 | name = "httpdate" 622 | version = "1.0.1" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" 625 | 626 | [[package]] 627 | name = "humantime" 628 | version = "1.3.0" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 631 | dependencies = [ 632 | "quick-error", 633 | ] 634 | 635 | [[package]] 636 | name = "hyper" 637 | version = "0.14.11" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11" 640 | dependencies = [ 641 | "bytes", 642 | "futures-channel", 643 | "futures-core", 644 | "futures-util", 645 | "h2", 646 | "http", 647 | "http-body", 648 | "httparse", 649 | "httpdate", 650 | "itoa", 651 | "pin-project-lite", 652 | "socket2", 653 | "tokio", 654 | "tower-service", 655 | "tracing", 656 | "want", 657 | ] 658 | 659 | [[package]] 660 | name = "hyper-tls" 661 | version = "0.5.0" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 664 | dependencies = [ 665 | "bytes", 666 | "hyper", 667 | "native-tls", 668 | "tokio", 669 | "tokio-native-tls", 670 | ] 671 | 672 | [[package]] 673 | name = "idna" 674 | version = "0.2.3" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 677 | dependencies = [ 678 | "matches", 679 | "unicode-bidi", 680 | "unicode-normalization", 681 | ] 682 | 683 | [[package]] 684 | name = "indexmap" 685 | version = "1.7.0" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 688 | dependencies = [ 689 | "autocfg", 690 | "hashbrown", 691 | ] 692 | 693 | [[package]] 694 | name = "instant" 695 | version = "0.1.10" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" 698 | dependencies = [ 699 | "cfg-if", 700 | ] 701 | 702 | [[package]] 703 | name = "ipnet" 704 | version = "2.3.1" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" 707 | 708 | [[package]] 709 | name = "itoa" 710 | version = "0.4.7" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 713 | 714 | [[package]] 715 | name = "js-sys" 716 | version = "0.3.51" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" 719 | dependencies = [ 720 | "wasm-bindgen", 721 | ] 722 | 723 | [[package]] 724 | name = "lazy_static" 725 | version = "1.4.0" 726 | source = "registry+https://github.com/rust-lang/crates.io-index" 727 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 728 | 729 | [[package]] 730 | name = "libc" 731 | version = "0.2.98" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" 734 | 735 | [[package]] 736 | name = "lock_api" 737 | version = "0.4.4" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" 740 | dependencies = [ 741 | "scopeguard", 742 | ] 743 | 744 | [[package]] 745 | name = "log" 746 | version = "0.4.14" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 749 | dependencies = [ 750 | "cfg-if", 751 | ] 752 | 753 | [[package]] 754 | name = "matches" 755 | version = "0.1.8" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 758 | 759 | [[package]] 760 | name = "memchr" 761 | version = "2.4.0" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" 764 | 765 | [[package]] 766 | name = "mime" 767 | version = "0.3.16" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 770 | 771 | [[package]] 772 | name = "mina-graphql-rs" 773 | version = "0.1.0" 774 | source = "git+https://github.com/zkvalidator/mina-graphql-rs?branch=main#f1474f03c44b9c1b94fadadf41d67f6fb71d4d69" 775 | dependencies = [ 776 | "anyhow", 777 | "chrono", 778 | "graphql_client", 779 | "log", 780 | "reqwest", 781 | "rust_decimal", 782 | "rust_decimal_macros", 783 | "serde", 784 | "serde_derive", 785 | "serde_json", 786 | "wasm-bindgen", 787 | ] 788 | 789 | [[package]] 790 | name = "mina-vrf-rs" 791 | version = "0.1.0" 792 | dependencies = [ 793 | "anyhow", 794 | "bigdecimal", 795 | "blake2b_simd", 796 | "bs58", 797 | "chrono", 798 | "clap-v3", 799 | "dotenv", 800 | "env_logger", 801 | "futures", 802 | "graphql_client", 803 | "log", 804 | "mina-graphql-rs", 805 | "num-bigint", 806 | "reqwest", 807 | "rust_decimal", 808 | "rust_decimal_macros", 809 | "serde", 810 | "serde_derive", 811 | "serde_json", 812 | "tokio", 813 | ] 814 | 815 | [[package]] 816 | name = "miniz_oxide" 817 | version = "0.4.4" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 820 | dependencies = [ 821 | "adler", 822 | "autocfg", 823 | ] 824 | 825 | [[package]] 826 | name = "mio" 827 | version = "0.7.13" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" 830 | dependencies = [ 831 | "libc", 832 | "log", 833 | "miow", 834 | "ntapi", 835 | "winapi", 836 | ] 837 | 838 | [[package]] 839 | name = "miow" 840 | version = "0.3.7" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 843 | dependencies = [ 844 | "winapi", 845 | ] 846 | 847 | [[package]] 848 | name = "native-tls" 849 | version = "0.2.7" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" 852 | dependencies = [ 853 | "lazy_static", 854 | "libc", 855 | "log", 856 | "openssl", 857 | "openssl-probe", 858 | "openssl-sys", 859 | "schannel", 860 | "security-framework", 861 | "security-framework-sys", 862 | "tempfile", 863 | ] 864 | 865 | [[package]] 866 | name = "ntapi" 867 | version = "0.3.6" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 870 | dependencies = [ 871 | "winapi", 872 | ] 873 | 874 | [[package]] 875 | name = "num-bigint" 876 | version = "0.3.2" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba" 879 | dependencies = [ 880 | "autocfg", 881 | "num-integer", 882 | "num-traits", 883 | ] 884 | 885 | [[package]] 886 | name = "num-integer" 887 | version = "0.1.44" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 890 | dependencies = [ 891 | "autocfg", 892 | "num-traits", 893 | ] 894 | 895 | [[package]] 896 | name = "num-traits" 897 | version = "0.2.14" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 900 | dependencies = [ 901 | "autocfg", 902 | ] 903 | 904 | [[package]] 905 | name = "num_cpus" 906 | version = "1.13.0" 907 | source = "registry+https://github.com/rust-lang/crates.io-index" 908 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 909 | dependencies = [ 910 | "hermit-abi", 911 | "libc", 912 | ] 913 | 914 | [[package]] 915 | name = "object" 916 | version = "0.26.0" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" 919 | dependencies = [ 920 | "memchr", 921 | ] 922 | 923 | [[package]] 924 | name = "once_cell" 925 | version = "1.8.0" 926 | source = "registry+https://github.com/rust-lang/crates.io-index" 927 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 928 | 929 | [[package]] 930 | name = "opaque-debug" 931 | version = "0.3.0" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 934 | 935 | [[package]] 936 | name = "openssl" 937 | version = "0.10.35" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885" 940 | dependencies = [ 941 | "bitflags", 942 | "cfg-if", 943 | "foreign-types", 944 | "libc", 945 | "once_cell", 946 | "openssl-sys", 947 | ] 948 | 949 | [[package]] 950 | name = "openssl-probe" 951 | version = "0.1.4" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" 954 | 955 | [[package]] 956 | name = "openssl-sys" 957 | version = "0.9.65" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d" 960 | dependencies = [ 961 | "autocfg", 962 | "cc", 963 | "libc", 964 | "pkg-config", 965 | "vcpkg", 966 | ] 967 | 968 | [[package]] 969 | name = "parking_lot" 970 | version = "0.11.1" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" 973 | dependencies = [ 974 | "instant", 975 | "lock_api", 976 | "parking_lot_core", 977 | ] 978 | 979 | [[package]] 980 | name = "parking_lot_core" 981 | version = "0.8.3" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" 984 | dependencies = [ 985 | "cfg-if", 986 | "instant", 987 | "libc", 988 | "redox_syscall", 989 | "smallvec", 990 | "winapi", 991 | ] 992 | 993 | [[package]] 994 | name = "percent-encoding" 995 | version = "2.1.0" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 998 | 999 | [[package]] 1000 | name = "pin-project-lite" 1001 | version = "0.2.7" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 1004 | 1005 | [[package]] 1006 | name = "pin-utils" 1007 | version = "0.1.0" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1010 | 1011 | [[package]] 1012 | name = "pkg-config" 1013 | version = "0.3.19" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" 1016 | 1017 | [[package]] 1018 | name = "ppv-lite86" 1019 | version = "0.2.10" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 1022 | 1023 | [[package]] 1024 | name = "proc-macro-error" 1025 | version = "0.4.12" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" 1028 | dependencies = [ 1029 | "proc-macro-error-attr", 1030 | "proc-macro2", 1031 | "quote", 1032 | "syn", 1033 | "version_check", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "proc-macro-error-attr" 1038 | version = "0.4.12" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" 1041 | dependencies = [ 1042 | "proc-macro2", 1043 | "quote", 1044 | "syn", 1045 | "syn-mid", 1046 | "version_check", 1047 | ] 1048 | 1049 | [[package]] 1050 | name = "proc-macro-hack" 1051 | version = "0.5.19" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 1054 | 1055 | [[package]] 1056 | name = "proc-macro-nested" 1057 | version = "0.1.7" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" 1060 | 1061 | [[package]] 1062 | name = "proc-macro2" 1063 | version = "1.0.28" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" 1066 | dependencies = [ 1067 | "unicode-xid", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "quick-error" 1072 | version = "1.2.3" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1075 | 1076 | [[package]] 1077 | name = "quote" 1078 | version = "1.0.9" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 1081 | dependencies = [ 1082 | "proc-macro2", 1083 | ] 1084 | 1085 | [[package]] 1086 | name = "rand" 1087 | version = "0.8.4" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" 1090 | dependencies = [ 1091 | "libc", 1092 | "rand_chacha", 1093 | "rand_core", 1094 | "rand_hc", 1095 | ] 1096 | 1097 | [[package]] 1098 | name = "rand_chacha" 1099 | version = "0.3.1" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1102 | dependencies = [ 1103 | "ppv-lite86", 1104 | "rand_core", 1105 | ] 1106 | 1107 | [[package]] 1108 | name = "rand_core" 1109 | version = "0.6.3" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 1112 | dependencies = [ 1113 | "getrandom", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "rand_hc" 1118 | version = "0.3.1" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" 1121 | dependencies = [ 1122 | "rand_core", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "redox_syscall" 1127 | version = "0.2.9" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" 1130 | dependencies = [ 1131 | "bitflags", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "regex" 1136 | version = "1.5.4" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 1139 | dependencies = [ 1140 | "aho-corasick", 1141 | "memchr", 1142 | "regex-syntax", 1143 | ] 1144 | 1145 | [[package]] 1146 | name = "regex-syntax" 1147 | version = "0.6.25" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1150 | 1151 | [[package]] 1152 | name = "remove_dir_all" 1153 | version = "0.5.3" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 1156 | dependencies = [ 1157 | "winapi", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "reqwest" 1162 | version = "0.11.4" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22" 1165 | dependencies = [ 1166 | "base64", 1167 | "bytes", 1168 | "encoding_rs", 1169 | "futures-core", 1170 | "futures-util", 1171 | "http", 1172 | "http-body", 1173 | "hyper", 1174 | "hyper-tls", 1175 | "ipnet", 1176 | "js-sys", 1177 | "lazy_static", 1178 | "log", 1179 | "mime", 1180 | "native-tls", 1181 | "percent-encoding", 1182 | "pin-project-lite", 1183 | "serde", 1184 | "serde_json", 1185 | "serde_urlencoded", 1186 | "tokio", 1187 | "tokio-native-tls", 1188 | "url", 1189 | "wasm-bindgen", 1190 | "wasm-bindgen-futures", 1191 | "web-sys", 1192 | "winreg", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "rust_decimal" 1197 | version = "1.15.0" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "c5446d1cf2dfe2d6367c8b27f2082bdf011e60e76fa1fcd140047f535156d6e7" 1200 | dependencies = [ 1201 | "arrayvec", 1202 | "num-traits", 1203 | "serde", 1204 | ] 1205 | 1206 | [[package]] 1207 | name = "rust_decimal_macros" 1208 | version = "1.15.0" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "f1927f5f2552e7c5335f2daef329de05f91efd8ec4a71c3ff4066ad45361b1df" 1211 | dependencies = [ 1212 | "quote", 1213 | "rust_decimal", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "rustc-demangle" 1218 | version = "0.1.20" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" 1221 | 1222 | [[package]] 1223 | name = "ryu" 1224 | version = "1.0.5" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1227 | 1228 | [[package]] 1229 | name = "schannel" 1230 | version = "0.1.19" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" 1233 | dependencies = [ 1234 | "lazy_static", 1235 | "winapi", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "scopeguard" 1240 | version = "1.1.0" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1243 | 1244 | [[package]] 1245 | name = "security-framework" 1246 | version = "2.3.1" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" 1249 | dependencies = [ 1250 | "bitflags", 1251 | "core-foundation", 1252 | "core-foundation-sys", 1253 | "libc", 1254 | "security-framework-sys", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "security-framework-sys" 1259 | version = "2.3.0" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "7e4effb91b4b8b6fb7732e670b6cee160278ff8e6bf485c7805d9e319d76e284" 1262 | dependencies = [ 1263 | "core-foundation-sys", 1264 | "libc", 1265 | ] 1266 | 1267 | [[package]] 1268 | name = "serde" 1269 | version = "1.0.127" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" 1272 | dependencies = [ 1273 | "serde_derive", 1274 | ] 1275 | 1276 | [[package]] 1277 | name = "serde_derive" 1278 | version = "1.0.127" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" 1281 | dependencies = [ 1282 | "proc-macro2", 1283 | "quote", 1284 | "syn", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "serde_json" 1289 | version = "1.0.66" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" 1292 | dependencies = [ 1293 | "itoa", 1294 | "ryu", 1295 | "serde", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "serde_urlencoded" 1300 | version = "0.7.0" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" 1303 | dependencies = [ 1304 | "form_urlencoded", 1305 | "itoa", 1306 | "ryu", 1307 | "serde", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "sha2" 1312 | version = "0.9.5" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" 1315 | dependencies = [ 1316 | "block-buffer", 1317 | "cfg-if", 1318 | "cpufeatures", 1319 | "digest", 1320 | "opaque-debug", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "signal-hook-registry" 1325 | version = "1.4.0" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1328 | dependencies = [ 1329 | "libc", 1330 | ] 1331 | 1332 | [[package]] 1333 | name = "slab" 1334 | version = "0.4.3" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" 1337 | 1338 | [[package]] 1339 | name = "smallvec" 1340 | version = "1.6.1" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 1343 | 1344 | [[package]] 1345 | name = "socket2" 1346 | version = "0.4.1" 1347 | source = "registry+https://github.com/rust-lang/crates.io-index" 1348 | checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" 1349 | dependencies = [ 1350 | "libc", 1351 | "winapi", 1352 | ] 1353 | 1354 | [[package]] 1355 | name = "strsim" 1356 | version = "0.9.3" 1357 | source = "registry+https://github.com/rust-lang/crates.io-index" 1358 | checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" 1359 | 1360 | [[package]] 1361 | name = "syn" 1362 | version = "1.0.74" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" 1365 | dependencies = [ 1366 | "proc-macro2", 1367 | "quote", 1368 | "unicode-xid", 1369 | ] 1370 | 1371 | [[package]] 1372 | name = "syn-mid" 1373 | version = "0.5.3" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "baa8e7560a164edb1621a55d18a0c59abf49d360f47aa7b821061dd7eea7fac9" 1376 | dependencies = [ 1377 | "proc-macro2", 1378 | "quote", 1379 | "syn", 1380 | ] 1381 | 1382 | [[package]] 1383 | name = "synstructure" 1384 | version = "0.12.5" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" 1387 | dependencies = [ 1388 | "proc-macro2", 1389 | "quote", 1390 | "syn", 1391 | "unicode-xid", 1392 | ] 1393 | 1394 | [[package]] 1395 | name = "tempfile" 1396 | version = "3.2.0" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" 1399 | dependencies = [ 1400 | "cfg-if", 1401 | "libc", 1402 | "rand", 1403 | "redox_syscall", 1404 | "remove_dir_all", 1405 | "winapi", 1406 | ] 1407 | 1408 | [[package]] 1409 | name = "termcolor" 1410 | version = "1.1.2" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1413 | dependencies = [ 1414 | "winapi-util", 1415 | ] 1416 | 1417 | [[package]] 1418 | name = "textwrap" 1419 | version = "0.11.0" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1422 | dependencies = [ 1423 | "unicode-width", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "time" 1428 | version = "0.1.43" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 1431 | dependencies = [ 1432 | "libc", 1433 | "winapi", 1434 | ] 1435 | 1436 | [[package]] 1437 | name = "tinyvec" 1438 | version = "1.3.1" 1439 | source = "registry+https://github.com/rust-lang/crates.io-index" 1440 | checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" 1441 | dependencies = [ 1442 | "tinyvec_macros", 1443 | ] 1444 | 1445 | [[package]] 1446 | name = "tinyvec_macros" 1447 | version = "0.1.0" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1450 | 1451 | [[package]] 1452 | name = "tokio" 1453 | version = "1.9.0" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "4b7b349f11a7047e6d1276853e612d152f5e8a352c61917887cc2169e2366b4c" 1456 | dependencies = [ 1457 | "autocfg", 1458 | "bytes", 1459 | "libc", 1460 | "memchr", 1461 | "mio", 1462 | "num_cpus", 1463 | "once_cell", 1464 | "parking_lot", 1465 | "pin-project-lite", 1466 | "signal-hook-registry", 1467 | "tokio-macros", 1468 | "winapi", 1469 | ] 1470 | 1471 | [[package]] 1472 | name = "tokio-macros" 1473 | version = "1.3.0" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" 1476 | dependencies = [ 1477 | "proc-macro2", 1478 | "quote", 1479 | "syn", 1480 | ] 1481 | 1482 | [[package]] 1483 | name = "tokio-native-tls" 1484 | version = "0.3.0" 1485 | source = "registry+https://github.com/rust-lang/crates.io-index" 1486 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" 1487 | dependencies = [ 1488 | "native-tls", 1489 | "tokio", 1490 | ] 1491 | 1492 | [[package]] 1493 | name = "tokio-util" 1494 | version = "0.6.7" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" 1497 | dependencies = [ 1498 | "bytes", 1499 | "futures-core", 1500 | "futures-sink", 1501 | "log", 1502 | "pin-project-lite", 1503 | "tokio", 1504 | ] 1505 | 1506 | [[package]] 1507 | name = "tower-service" 1508 | version = "0.3.1" 1509 | source = "registry+https://github.com/rust-lang/crates.io-index" 1510 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1511 | 1512 | [[package]] 1513 | name = "tracing" 1514 | version = "0.1.26" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" 1517 | dependencies = [ 1518 | "cfg-if", 1519 | "pin-project-lite", 1520 | "tracing-core", 1521 | ] 1522 | 1523 | [[package]] 1524 | name = "tracing-core" 1525 | version = "0.1.18" 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" 1527 | checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" 1528 | dependencies = [ 1529 | "lazy_static", 1530 | ] 1531 | 1532 | [[package]] 1533 | name = "try-lock" 1534 | version = "0.2.3" 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" 1536 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1537 | 1538 | [[package]] 1539 | name = "typenum" 1540 | version = "1.13.0" 1541 | source = "registry+https://github.com/rust-lang/crates.io-index" 1542 | checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" 1543 | 1544 | [[package]] 1545 | name = "unicode-bidi" 1546 | version = "0.3.5" 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" 1548 | checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" 1549 | dependencies = [ 1550 | "matches", 1551 | ] 1552 | 1553 | [[package]] 1554 | name = "unicode-normalization" 1555 | version = "0.1.19" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 1558 | dependencies = [ 1559 | "tinyvec", 1560 | ] 1561 | 1562 | [[package]] 1563 | name = "unicode-segmentation" 1564 | version = "1.8.0" 1565 | source = "registry+https://github.com/rust-lang/crates.io-index" 1566 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 1567 | 1568 | [[package]] 1569 | name = "unicode-width" 1570 | version = "0.1.8" 1571 | source = "registry+https://github.com/rust-lang/crates.io-index" 1572 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 1573 | 1574 | [[package]] 1575 | name = "unicode-xid" 1576 | version = "0.2.2" 1577 | source = "registry+https://github.com/rust-lang/crates.io-index" 1578 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1579 | 1580 | [[package]] 1581 | name = "unreachable" 1582 | version = "1.0.0" 1583 | source = "registry+https://github.com/rust-lang/crates.io-index" 1584 | checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" 1585 | dependencies = [ 1586 | "void", 1587 | ] 1588 | 1589 | [[package]] 1590 | name = "url" 1591 | version = "2.2.2" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 1594 | dependencies = [ 1595 | "form_urlencoded", 1596 | "idna", 1597 | "matches", 1598 | "percent-encoding", 1599 | ] 1600 | 1601 | [[package]] 1602 | name = "vcpkg" 1603 | version = "0.2.15" 1604 | source = "registry+https://github.com/rust-lang/crates.io-index" 1605 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1606 | 1607 | [[package]] 1608 | name = "vec_map" 1609 | version = "0.8.2" 1610 | source = "registry+https://github.com/rust-lang/crates.io-index" 1611 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1612 | 1613 | [[package]] 1614 | name = "version_check" 1615 | version = "0.9.3" 1616 | source = "registry+https://github.com/rust-lang/crates.io-index" 1617 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1618 | 1619 | [[package]] 1620 | name = "void" 1621 | version = "1.0.2" 1622 | source = "registry+https://github.com/rust-lang/crates.io-index" 1623 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 1624 | 1625 | [[package]] 1626 | name = "want" 1627 | version = "0.3.0" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1630 | dependencies = [ 1631 | "log", 1632 | "try-lock", 1633 | ] 1634 | 1635 | [[package]] 1636 | name = "wasi" 1637 | version = "0.10.2+wasi-snapshot-preview1" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1640 | 1641 | [[package]] 1642 | name = "wasm-bindgen" 1643 | version = "0.2.74" 1644 | source = "registry+https://github.com/rust-lang/crates.io-index" 1645 | checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" 1646 | dependencies = [ 1647 | "cfg-if", 1648 | "serde", 1649 | "serde_json", 1650 | "wasm-bindgen-macro", 1651 | ] 1652 | 1653 | [[package]] 1654 | name = "wasm-bindgen-backend" 1655 | version = "0.2.74" 1656 | source = "registry+https://github.com/rust-lang/crates.io-index" 1657 | checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" 1658 | dependencies = [ 1659 | "bumpalo", 1660 | "lazy_static", 1661 | "log", 1662 | "proc-macro2", 1663 | "quote", 1664 | "syn", 1665 | "wasm-bindgen-shared", 1666 | ] 1667 | 1668 | [[package]] 1669 | name = "wasm-bindgen-futures" 1670 | version = "0.4.24" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1" 1673 | dependencies = [ 1674 | "cfg-if", 1675 | "js-sys", 1676 | "wasm-bindgen", 1677 | "web-sys", 1678 | ] 1679 | 1680 | [[package]] 1681 | name = "wasm-bindgen-macro" 1682 | version = "0.2.74" 1683 | source = "registry+https://github.com/rust-lang/crates.io-index" 1684 | checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" 1685 | dependencies = [ 1686 | "quote", 1687 | "wasm-bindgen-macro-support", 1688 | ] 1689 | 1690 | [[package]] 1691 | name = "wasm-bindgen-macro-support" 1692 | version = "0.2.74" 1693 | source = "registry+https://github.com/rust-lang/crates.io-index" 1694 | checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" 1695 | dependencies = [ 1696 | "proc-macro2", 1697 | "quote", 1698 | "syn", 1699 | "wasm-bindgen-backend", 1700 | "wasm-bindgen-shared", 1701 | ] 1702 | 1703 | [[package]] 1704 | name = "wasm-bindgen-shared" 1705 | version = "0.2.74" 1706 | source = "registry+https://github.com/rust-lang/crates.io-index" 1707 | checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" 1708 | 1709 | [[package]] 1710 | name = "web-sys" 1711 | version = "0.3.51" 1712 | source = "registry+https://github.com/rust-lang/crates.io-index" 1713 | checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" 1714 | dependencies = [ 1715 | "js-sys", 1716 | "wasm-bindgen", 1717 | ] 1718 | 1719 | [[package]] 1720 | name = "winapi" 1721 | version = "0.3.9" 1722 | source = "registry+https://github.com/rust-lang/crates.io-index" 1723 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1724 | dependencies = [ 1725 | "winapi-i686-pc-windows-gnu", 1726 | "winapi-x86_64-pc-windows-gnu", 1727 | ] 1728 | 1729 | [[package]] 1730 | name = "winapi-i686-pc-windows-gnu" 1731 | version = "0.4.0" 1732 | source = "registry+https://github.com/rust-lang/crates.io-index" 1733 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1734 | 1735 | [[package]] 1736 | name = "winapi-util" 1737 | version = "0.1.5" 1738 | source = "registry+https://github.com/rust-lang/crates.io-index" 1739 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1740 | dependencies = [ 1741 | "winapi", 1742 | ] 1743 | 1744 | [[package]] 1745 | name = "winapi-x86_64-pc-windows-gnu" 1746 | version = "0.4.0" 1747 | source = "registry+https://github.com/rust-lang/crates.io-index" 1748 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1749 | 1750 | [[package]] 1751 | name = "winreg" 1752 | version = "0.7.0" 1753 | source = "registry+https://github.com/rust-lang/crates.io-index" 1754 | checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" 1755 | dependencies = [ 1756 | "winapi", 1757 | ] 1758 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mina-vrf-rs" 3 | version = "0.1.0" 4 | authors = [ "HAOYUatHZ " ] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | anyhow = "1.0.39" 11 | clap = { package = "clap-v3", version = "3.0.0-beta.1" } # todo: replace with official v3 when it's released to crates.io 12 | dotenv = "0.15.0" 13 | env_logger = "0.5" 14 | graphql_client = "0.9.0" 15 | log = "0.4" 16 | mina-graphql-rs = { git = "https://github.com/zkvalidator/mina-graphql-rs", branch = "main" } 17 | num-bigint = "0.3.2" 18 | bigdecimal = "0.2.0" 19 | reqwest = { version = "0.11.3", features = [ "json", "blocking" ] } 20 | rust_decimal = "1.14" 21 | rust_decimal_macros = "1.14" 22 | serde = { version = "1.0", features = [ "derive" ] } 23 | serde_derive = "1.0" 24 | serde_json = "1.0" 25 | tokio = { version = "1.6.0", features = [ "full" ] } 26 | bs58 = { version = "0.4.0", features = [ "check" ] } 27 | blake2b_simd = "0.5.11" 28 | chrono = { version = "0.4", features = [ "serde" ] } 29 | futures = "0.3" 30 | 31 | [[bin]] 32 | name = "mina-vrf" 33 | path = "src/bin/main.rs" 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mina-vrf-rs 2 | 3 | ## Introduction 4 | 5 | The Mina consensus algorithm uses a VRF to determine whether a block producer is eligible to produce a block at a specific slot. The VRF is produced with the block producer's private key. 6 | A block producer can thus provably see and show whether they were eligible to produce blocks at a given slot, providing two interesting use cases: 7 | 8 | * Knowing ahead of time at which slots a block can be produced, and use that knowledge to improve reliability 9 | * Prove to delegators that you've performed adequately and produced all the blocks you should have produced 10 | 11 | A caveat is that even though a BP is eligible to produce a block at a slot, multiple BPs can be, and so you're not guaranteed to win that slot. 12 | 13 | ## Workflow 14 | 15 | `mina-vrf-rs` currently uses the `mina advanced vrf` set of commands. Therefore, it is mainly responsible for preparing the inputs and processing the outputs of those commands. 16 | 17 | An example workflow - proving to a delegator your eligible blocks: 18 | 19 | ### Run by block producer 20 | 21 | ``` 22 | cargo run --release -- batch-generate-witness --pub B62qrHzjcZbYSsrcXVgGko7go1DzSEBfdQGPon5X4LEGExtNJZA4ECj --epoch 5 > requests 23 | cat requests | mina advanced vrf batch-generate-witness --privkey-path /keys/my-wallet | sed 's/Using password from environment variable CODA_PRIVKEY_PASS//g' > witnesses 24 | ``` 25 | 26 | Send `witnesses` to delegator. 27 | 28 | ### Run by delegator 29 | 30 | ``` 31 | cat witnesses | cargo run --release -- batch-patch-witness --pub B62qrHzjcZbYSsrcXVgGko7go1DzSEBfdQGPon5X4LEGExtNJZA4ECj --epoch 5 > patches 32 | cat patches | mina advanced vrf batch-check-witness | sed 's/Using password from environment variable CODA_PRIVKEY_PASS//g' > check 33 | cat check | cargo run --release -- batch-check-witness --pub B62qrHzjcZbYSsrcXVgGko7go1DzSEBfdQGPon5X4LEGExtNJZA4ECj --epoch 5 34 | ``` 35 | 36 | This will let the delegator see an output of this form: 37 | ``` 38 | invalid slots: [] 39 | invalid local slots: [] 40 | producing slots: [35947, 36239, 36269, 36344, 36431, 36599, 36668, 36700, 36784, 36858, 36985, 37261, 37492, 37509, 37557, 37638, 37762, 37765, 38176, 38232, 38248, 38309, 38316, 38505, 38565, 38800, 38907, 38974, 39083, 39271, 39277, 39403, 39450, 39473, 39538, 39769, 39821, 40177, 40498, 40609, 40615, 40765, 41389, 41573, 42017, 42188, 42311, 42324, 42350, 42407, 42469, 42480, 42601, 42655, 42711] 41 | producing local slots: [247, 539, 569, 644, 731, 899, 968, 1000, 1084, 1158, 1285, 1561, 1792, 1809, 1857, 1938, 2062, 2065, 2476, 2532, 2548, 2609, 2616, 2805, 2865, 3100, 3207, 3274, 3383, 3571, 3577, 3703, 3750, 3773, 3838, 4069, 4121, 4477, 4798, 4909, 4915, 5065, 5689, 5873, 6317, 6488, 6611, 6624, 6650, 6707, 6769, 6780, 6901, 6955, 7011] 42 | ``` 43 | 44 | ## Future development 45 | 46 | * Implement the cryptography internally, to not rely on the Mina node for the VRF evaluation and verification 47 | * Have the ledger data verifiable, or cross-checked, rather than fetched in a trusted manner from Mina explorer and this repository 48 | -------------------------------------------------------------------------------- /scripts/end_to_end.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | PUBKEY=$1 4 | EPOCH=$2 5 | 6 | cargo run --release -- batch-generate-witness --pub $PUBKEY --epoch $EPOCH > requests 7 | cat requests | mina advanced vrf batch-generate-witness --privkey-path /keys/my-wallet | sed 's/Using password from environment variable CODA_PRIVKEY_PASS//g' > witnesses 8 | cat witnesses | cargo run --release -- batch-patch-witness --pub $PUBKEY --epoch $EPOCH > patches 9 | cat patches | mina advanced vrf batch-check-witness | sed 's/Using password from environment variable CODA_PRIVKEY_PASS//g' > check 10 | cat check | cargo run --release -- batch-check-witness --pub $PUBKEY --epoch $EPOCH 11 | -------------------------------------------------------------------------------- /src/bin/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::enum_variant_names)] 2 | 3 | use anyhow::{anyhow, Result}; 4 | use bigdecimal::{BigDecimal, ToPrimitive}; 5 | use blake2b_simd::Params; 6 | use chrono::Duration; 7 | use clap::Clap; 8 | use mina_graphql_rs::*; 9 | use num_bigint::{BigInt, Sign}; 10 | use rust_decimal::Decimal; 11 | use serde::{Deserialize, Serialize}; 12 | use std::collections::HashMap; 13 | use std::fs::File; 14 | use std::io::{self, BufWriter, Write}; 15 | use std::str::FromStr; 16 | 17 | const SLOT_TIME_MINUTES: i64 = 3; 18 | 19 | /// mina-vrf-rs client 20 | #[derive(Clap)] 21 | struct Opts { 22 | #[clap(subcommand)] 23 | command: SubCommand, 24 | } 25 | 26 | #[derive(Clap)] 27 | enum SubCommand { 28 | BatchGenerateWitness(VRFOpts), 29 | BatchPatchWitness(VRFOpts), 30 | BatchCheckWitness(VRFOpts), 31 | } 32 | 33 | /// A subcommand for generating key pair 34 | #[derive(Clap)] 35 | struct KeygenOpts { 36 | /// Output public key file 37 | #[clap(short = "p", long = "pub", default_value = "pub.key")] 38 | _pubkey: String, 39 | /// Output private key file 40 | #[clap(short = "v", long = "prv", default_value = "prv.key")] 41 | _prvkey: String, 42 | } 43 | 44 | #[derive(Clap)] 45 | struct VRFOpts { 46 | /// Graphql endpoint URL 47 | #[clap( 48 | short = "e", 49 | long = "endpoint", 50 | default_value = DEFAULT_LOCAL_ENDPOINT 51 | )] 52 | endpoint: String, 53 | /// User public key string 54 | #[clap(short = "p", long = "pub")] 55 | pubkey: String, 56 | #[clap(short = "n", long = "epoch")] 57 | epoch: usize, 58 | #[clap(short = "o", long = "out-file", default_value = "-")] 59 | out_file: String, 60 | } 61 | 62 | #[derive(Serialize, Deserialize, Debug, Clone)] 63 | #[serde(rename_all = "camelCase")] 64 | pub struct BatchGenerateWitnessSingleRequest { 65 | pub global_slot: String, 66 | pub epoch_seed: String, 67 | pub delegator_index: i64, 68 | } 69 | 70 | #[derive(Serialize, Deserialize, Debug, Clone)] 71 | #[serde(rename_all = "camelCase")] 72 | pub struct BatchPatchWitnessSingleVrfThresholdRequest { 73 | pub delegated_stake: String, 74 | pub total_stake: String, 75 | } 76 | 77 | #[derive(Serialize, Deserialize, Debug, Clone)] 78 | #[serde(rename_all = "camelCase")] 79 | pub struct BatchPatchWitnessSingleRequest { 80 | pub message: BatchGenerateWitnessSingleRequest, 81 | pub public_key: String, 82 | pub c: String, 83 | pub s: String, 84 | #[serde(rename = "ScaledMessageHash")] 85 | pub scaled_message_hash: Vec, 86 | pub vrf_threshold: Option, 87 | } 88 | 89 | #[derive(Serialize, Deserialize, Debug, Clone)] 90 | #[serde(rename_all = "camelCase")] 91 | pub struct BatchCheckWitnessSingleRequest { 92 | pub message: BatchGenerateWitnessSingleRequest, 93 | pub public_key: String, 94 | pub c: String, 95 | pub s: String, 96 | #[serde(rename = "ScaledMessageHash")] 97 | pub scaled_message_hash: Vec, 98 | pub vrf_threshold: BatchPatchWitnessSingleVrfThresholdRequest, 99 | pub vrf_output: String, 100 | pub vrf_output_fractional: f64, 101 | pub threshold_met: bool, 102 | } 103 | 104 | #[derive(Serialize, Deserialize, Debug, Clone)] 105 | #[serde(rename_all = "camelCase")] 106 | pub struct CheckWitnessOutput { 107 | pub producing_slots: Vec, 108 | pub local_producing_slots: Vec, 109 | pub invalid_slots: Vec, 110 | pub local_invalid_slots: Vec, 111 | pub won_slots: Vec, 112 | pub local_won_slots: Vec, 113 | pub lost_slots: Vec, 114 | pub local_lost_slots: Vec, 115 | pub missed_slots: Vec<(usize, MissedBlockReason)>, 116 | pub local_missed_slots: Vec<(usize, MissedBlockReason)>, 117 | pub ambiguous_slots: Vec<(usize, Vec)>, 118 | pub local_ambiguous_slots: Vec<(usize, Vec)>, 119 | } 120 | 121 | fn open_buffered_file(path: &str) -> io::Result> { 122 | return if path == "-" { 123 | Ok(Box::new(BufWriter::new(io::stdout()))) 124 | } else { 125 | Ok(Box::new(BufWriter::new(File::create(path)?))) 126 | }; 127 | } 128 | 129 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] 130 | pub enum SlotResult { 131 | Won, 132 | Lost, 133 | Missed(MissedBlockReason), 134 | } 135 | 136 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] 137 | pub struct SlotAnalysis { 138 | pub slot_result: SlotResult, 139 | pub saw_my_producer_and_same_delegator: bool, 140 | } 141 | 142 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] 143 | pub enum MissedBlockReason { 144 | NotProducedOrPropagated, 145 | PropagatedTooLate(String, String), 146 | HeightTooOld(i64, i64), 147 | } 148 | 149 | #[tokio::main] 150 | async fn main() { 151 | dotenv::dotenv().ok(); 152 | env_logger::init(); 153 | 154 | let opts: Opts = Opts::parse(); 155 | match opts.command { 156 | SubCommand::BatchGenerateWitness(o) => match batch_generate_witness(o).await { 157 | Err(e) => log::error!("{}", e), 158 | _ => { 159 | log::info!("Executed command successfully!"); 160 | } 161 | }, 162 | SubCommand::BatchPatchWitness(o) => match batch_patch_witness(o).await { 163 | Err(e) => log::error!("{}", e), 164 | _ => { 165 | log::info!("Executed command successfully!"); 166 | } 167 | }, 168 | SubCommand::BatchCheckWitness(o) => match batch_check_witness(o).await { 169 | Err(e) => log::error!("{}", e), 170 | _ => { 171 | log::info!("Executed command successfully!"); 172 | } 173 | }, 174 | } 175 | } 176 | 177 | async fn batch_generate_witness(opts: VRFOpts) -> Result<()> { 178 | let (seed, _, _, delegators) = get_staking_data(&opts.endpoint, opts.epoch as i64).await?; 179 | let delegators_indices = delegators 180 | .into_iter() 181 | .filter(|x| x.delegate == opts.pubkey) 182 | .map(|x| x.index) 183 | .collect::>(); 184 | 185 | let (first_slot_in_epoch, last_slot_in_epoch) = ( 186 | NUM_SLOTS_IN_EPOCH * opts.epoch, 187 | (NUM_SLOTS_IN_EPOCH * (opts.epoch + 1) - 1), 188 | ); 189 | log::debug!( 190 | "slot range: {}, {}", 191 | first_slot_in_epoch, 192 | last_slot_in_epoch 193 | ); 194 | let requests = (first_slot_in_epoch..=last_slot_in_epoch) 195 | .flat_map(|slot| { 196 | let local_seed = seed.clone(); 197 | let local_slot = slot.to_string(); 198 | delegators_indices 199 | .iter() 200 | .map(move |index| BatchGenerateWitnessSingleRequest { 201 | epoch_seed: local_seed.clone(), 202 | global_slot: local_slot.clone(), 203 | delegator_index: *index, 204 | }) 205 | .into_iter() 206 | }) 207 | .collect::>(); 208 | 209 | let mut f = open_buffered_file(&opts.out_file)?; 210 | for request in requests { 211 | f.write_all(format!("{}", serde_json::to_string(&request)?).as_bytes())?; 212 | } 213 | f.flush()?; 214 | 215 | Ok(()) 216 | } 217 | 218 | async fn batch_patch_witness(opts: VRFOpts) -> Result<()> { 219 | let (_, total_currency, _, delegators) = 220 | get_staking_data(&opts.endpoint, opts.epoch as i64).await?; 221 | let total_currency = { 222 | let mut currency = Decimal::from_str(&total_currency)?; 223 | currency.set_scale(DIGITS_AFTER_DECIMAL_POINT)?; 224 | currency 225 | }; 226 | 227 | let stdin = std::io::stdin(); 228 | let stdin = stdin.lock(); 229 | let mut f = open_buffered_file(&opts.out_file)?; 230 | 231 | let deserializer = serde_json::Deserializer::from_reader(stdin); 232 | let iterator = deserializer.into_iter::(); 233 | for item in iterator { 234 | let mut patched = item?; 235 | let balance = Decimal::from_str( 236 | &delegators 237 | .iter() 238 | .find(|x| x.index == patched.message.delegator_index) 239 | .ok_or(anyhow!("can't find delegator"))? 240 | .balance, 241 | )?; 242 | patched.vrf_threshold = Some(BatchPatchWitnessSingleVrfThresholdRequest { 243 | delegated_stake: balance.to_string(), 244 | total_stake: total_currency.to_string(), 245 | }); 246 | f.write_all(format!("{}", serde_json::to_string(&patched).unwrap()).as_bytes())?; 247 | } 248 | f.flush()?; 249 | 250 | Ok(()) 251 | } 252 | 253 | #[allow(dead_code)] 254 | fn vrf_output_to_fractional(vrf_output: &str) -> Result { 255 | let vrf_bytes = vrf_output_to_bytes(vrf_output)?; 256 | let vrf = BigDecimal::from((BigInt::from_bytes_le(Sign::Plus, &vrf_bytes), 0i64)); 257 | let adjust = BigDecimal::from((BigInt::from(2).pow(253), 0i64)); 258 | (vrf / adjust) 259 | .to_f64() 260 | .ok_or(anyhow!("should have converted decimal to float")) 261 | } 262 | 263 | fn vrf_output_to_bytes(vrf_output: &str) -> Result> { 264 | let bytes = bs58::decode(vrf_output).into_vec()?; 265 | if bytes.len() < 36 { 266 | return Err(anyhow!("not enough bytes in vrf output")); 267 | } 268 | Ok(bytes[3..35].to_vec()) 269 | } 270 | 271 | fn vrf_output_to_digest_bytes(vrf_output: &str) -> Result> { 272 | let bytes = vrf_output_to_bytes(vrf_output)?; 273 | Ok(Params::new() 274 | .hash_length(32) 275 | .to_state() 276 | .update(&bytes) 277 | .finalize() 278 | .as_bytes() 279 | .to_vec()) 280 | } 281 | 282 | fn compare_vrfs(v1: &[u8], v2: &[u8]) -> bool { 283 | for (i, v) in v1.iter().enumerate() { 284 | if v > &v2[i] { 285 | return true; 286 | } else if v < &v2[i] { 287 | return false; 288 | } 289 | } 290 | return false; 291 | } 292 | 293 | async fn analyze_slot( 294 | delegators_index_to_public_key: &HashMap, 295 | delegator_details: &BatchCheckWitnessSingleRequest, 296 | slot: i64, 297 | winners_for_epoch: &HashMap, 298 | blocks_for_creator_for_epoch: &HashMap, 299 | ) -> Result { 300 | let delegator_public_key = 301 | &delegators_index_to_public_key[&delegator_details.message.delegator_index]; 302 | 303 | let winners_exist = winners_for_epoch.contains_key(&slot); 304 | let saw_my_producer = blocks_for_creator_for_epoch.contains_key(&slot); 305 | if !winners_exist { 306 | if !saw_my_producer { 307 | let reason = MissedBlockReason::NotProducedOrPropagated; 308 | return Ok(SlotAnalysis { 309 | slot_result: SlotResult::Missed(reason), 310 | saw_my_producer_and_same_delegator: false, 311 | }); 312 | } else { 313 | let late = blocks_for_creator_for_epoch[&slot].received_time 314 | > (blocks_for_creator_for_epoch[&slot].date_time 315 | + Duration::minutes(SLOT_TIME_MINUTES)); 316 | let my_producer_block = &blocks_for_creator_for_epoch[&slot]; 317 | if late { 318 | let reason = MissedBlockReason::PropagatedTooLate( 319 | my_producer_block.date_time.to_rfc3339(), 320 | my_producer_block.received_time.to_rfc3339(), 321 | ); 322 | return Ok(SlotAnalysis { 323 | slot_result: SlotResult::Missed(reason), 324 | saw_my_producer_and_same_delegator: &my_producer_block.public_key 325 | == delegator_public_key, 326 | }); 327 | } else { 328 | return Ok(SlotAnalysis { 329 | slot_result: SlotResult::Lost, 330 | saw_my_producer_and_same_delegator: &my_producer_block.public_key 331 | == delegator_public_key, 332 | }); 333 | } 334 | } 335 | } else { 336 | let winner_for_slot = &winners_for_epoch[&slot]; 337 | let my_producer_is_the_winner = &winner_for_slot.public_key == delegator_public_key; 338 | if my_producer_is_the_winner { 339 | return Ok(SlotAnalysis { 340 | slot_result: SlotResult::Won, 341 | saw_my_producer_and_same_delegator: true, 342 | }); 343 | } else { 344 | if saw_my_producer { 345 | let my_producer_block = &blocks_for_creator_for_epoch[&slot]; 346 | let block_height_equal = 347 | my_producer_block.block_height == winner_for_slot.block_height; 348 | if block_height_equal { 349 | let winner_digest = vrf_output_to_digest_bytes(&winner_for_slot.vrf)?; 350 | let our_digest = vrf_output_to_digest_bytes(&delegator_details.vrf_output)?; 351 | if compare_vrfs(&our_digest, &winner_digest) { 352 | let late = blocks_for_creator_for_epoch[&slot].received_time 353 | > (blocks_for_creator_for_epoch[&slot].date_time 354 | + Duration::minutes(SLOT_TIME_MINUTES)); 355 | if late { 356 | let reason = MissedBlockReason::PropagatedTooLate( 357 | my_producer_block.date_time.to_rfc3339(), 358 | my_producer_block.received_time.to_rfc3339(), 359 | ); 360 | return Ok(SlotAnalysis { 361 | slot_result: SlotResult::Missed(reason), 362 | saw_my_producer_and_same_delegator: &my_producer_block.public_key 363 | == delegator_public_key, 364 | }); 365 | } else { 366 | return Ok(SlotAnalysis { 367 | slot_result: SlotResult::Lost, 368 | saw_my_producer_and_same_delegator: &my_producer_block.public_key 369 | == delegator_public_key, 370 | }); 371 | } 372 | } else { 373 | return Ok(SlotAnalysis { 374 | slot_result: SlotResult::Lost, 375 | saw_my_producer_and_same_delegator: &my_producer_block.public_key 376 | == delegator_public_key, 377 | }); 378 | } 379 | } else { 380 | let reason = MissedBlockReason::HeightTooOld( 381 | my_producer_block.block_height, 382 | winner_for_slot.block_height, 383 | ); 384 | return Ok(SlotAnalysis { 385 | slot_result: SlotResult::Missed(reason), 386 | saw_my_producer_and_same_delegator: &my_producer_block.public_key 387 | == delegator_public_key, 388 | }); 389 | } 390 | } else { 391 | let winner_digest = vrf_output_to_digest_bytes(&winner_for_slot.vrf)?; 392 | let our_digest = vrf_output_to_digest_bytes(&delegator_details.vrf_output)?; 393 | if compare_vrfs(&our_digest, &winner_digest) { 394 | let reason = MissedBlockReason::NotProducedOrPropagated; 395 | return Ok(SlotAnalysis { 396 | slot_result: SlotResult::Missed(reason), 397 | saw_my_producer_and_same_delegator: false, 398 | }); 399 | } else { 400 | return Ok(SlotAnalysis { 401 | slot_result: SlotResult::Lost, 402 | saw_my_producer_and_same_delegator: false, 403 | }); 404 | } 405 | } 406 | } 407 | } 408 | } 409 | 410 | async fn batch_check_witness(opts: VRFOpts) -> Result<()> { 411 | let stdin = std::io::stdin(); 412 | let stdin = stdin.lock(); 413 | 414 | let (_, _, _, delegators) = get_staking_data(&opts.endpoint, opts.epoch as i64).await?; 415 | 416 | let deserializer = serde_json::Deserializer::from_reader(stdin); 417 | let iterator = deserializer.into_iter::(); 418 | let mut slot_to_vrf_results: HashMap> = HashMap::new(); 419 | 420 | for item in iterator { 421 | let e = item?; 422 | let slot = e.message.global_slot.clone(); 423 | if !slot_to_vrf_results.contains_key(&slot) { 424 | slot_to_vrf_results.insert(slot.clone(), vec![]); 425 | } 426 | slot_to_vrf_results 427 | .get_mut(&slot) 428 | .ok_or(anyhow!("could not get mut"))? 429 | .push(e.clone()); 430 | } 431 | let (first_slot_in_epoch, last_slot_in_epoch) = ( 432 | NUM_SLOTS_IN_EPOCH * opts.epoch, 433 | (NUM_SLOTS_IN_EPOCH * (opts.epoch + 1) - 1), 434 | ); 435 | 436 | let delegators_indices = delegators 437 | .iter() 438 | .filter(|x| x.delegate == opts.pubkey) 439 | .map(|x| x.index) 440 | .collect::>(); 441 | 442 | let delegators_index_to_public_key = delegators 443 | .into_iter() 444 | .filter(|x| x.delegate == opts.pubkey) 445 | .map(|x| (x.index, x.pk.clone())) 446 | .collect::>(); 447 | 448 | let mut invalid_slots = vec![]; 449 | let mut local_invalid_slots = vec![]; 450 | let mut producing_slots = vec![]; 451 | let mut local_producing_slots = vec![]; 452 | let mut won_slots = vec![]; 453 | let mut local_won_slots = vec![]; 454 | let mut lost_slots = vec![]; 455 | let mut local_lost_slots = vec![]; 456 | let mut missed_slots = vec![]; 457 | let mut local_missed_slots = vec![]; 458 | let mut ambiguous_slots = vec![]; 459 | let mut local_ambiguous_slots = vec![]; 460 | 461 | let winners_for_epoch = get_winners_for_epoch(opts.epoch).await?; 462 | let blocks_for_creator_for_epoch = 463 | get_blocks_for_creator_for_epoch(opts.epoch, &opts.pubkey).await?; 464 | 465 | for slot in first_slot_in_epoch..=last_slot_in_epoch { 466 | if !slot_to_vrf_results.contains_key(&slot.to_string()) { 467 | invalid_slots.push(slot); 468 | local_invalid_slots.push(slot - first_slot_in_epoch); 469 | continue; 470 | } 471 | let vrf_results = &slot_to_vrf_results[&slot.to_string()]; 472 | if vrf_results.iter().any(|v| v.threshold_met) { 473 | producing_slots.push(slot); 474 | local_producing_slots.push(slot - first_slot_in_epoch); 475 | } 476 | if !delegators_indices.iter().all(|x| { 477 | vrf_results 478 | .iter() 479 | .find(|v| v.message.delegator_index == *x) 480 | .is_some() 481 | }) { 482 | invalid_slots.push(slot); 483 | local_invalid_slots.push(slot - first_slot_in_epoch); 484 | continue; 485 | } 486 | let results = vrf_results 487 | .iter() 488 | .filter(|v| v.threshold_met) 489 | .map(|delegator_details| { 490 | analyze_slot( 491 | &delegators_index_to_public_key, 492 | delegator_details, 493 | slot as i64, 494 | &winners_for_epoch, 495 | &blocks_for_creator_for_epoch, 496 | ) 497 | }) 498 | .collect::>(); 499 | let results = futures::future::try_join_all(results).await?; 500 | let mut process_single_result = |result: &SlotAnalysis| match &result.slot_result { 501 | SlotResult::Won => { 502 | won_slots.push(slot); 503 | local_won_slots.push(slot - first_slot_in_epoch); 504 | } 505 | SlotResult::Lost => { 506 | lost_slots.push(slot); 507 | local_lost_slots.push(slot - first_slot_in_epoch); 508 | } 509 | SlotResult::Missed(reason) => { 510 | missed_slots.push((slot, reason.clone())); 511 | local_missed_slots.push((slot - first_slot_in_epoch, reason.clone())); 512 | } 513 | }; 514 | if results.len() > 0 && results.iter().all(|r| r == &results[0]) { 515 | let result = &results[0]; 516 | process_single_result(result); 517 | continue; 518 | } 519 | if let Some(result) = results 520 | .iter() 521 | .find(|r| r.saw_my_producer_and_same_delegator) 522 | { 523 | process_single_result(result); 524 | continue; 525 | } 526 | if results.iter().any(|r| r.slot_result == SlotResult::Won) { 527 | won_slots.push(slot); 528 | local_won_slots.push(slot - first_slot_in_epoch); 529 | continue; 530 | } 531 | 532 | if results.len() > 0 { 533 | ambiguous_slots.push(( 534 | slot, 535 | results.iter().cloned().map(|r| r.slot_result).collect(), 536 | )); 537 | local_ambiguous_slots.push(( 538 | slot - first_slot_in_epoch, 539 | results.iter().cloned().map(|r| r.slot_result).collect(), 540 | )); 541 | continue; 542 | } 543 | } 544 | 545 | if invalid_slots.is_empty() { 546 | log::info!("no invalid slot"); 547 | } else { 548 | log::error!("invalid slots: {:?}", invalid_slots); 549 | } 550 | if local_invalid_slots.is_empty() { 551 | log::info!("no invalid local slot"); 552 | } else { 553 | log::error!("invalid local slots: {:?}", local_invalid_slots); 554 | } 555 | log::info!("producing slots: {:?}", producing_slots); 556 | log::info!("producing local slots: {:?}", local_producing_slots); 557 | log::info!("won slots: {:?}", won_slots); 558 | log::info!("won local slots: {:?}", local_won_slots); 559 | log::info!("lost slots: {:?}", lost_slots); 560 | log::info!("lost local slots: {:?}", local_lost_slots); 561 | log::info!("missed slots: {:?}", missed_slots); 562 | log::info!("missed local slots: {:?}", local_missed_slots); 563 | log::info!("ambiguous slots: {:?}", ambiguous_slots); 564 | log::info!("ambiguous local slots: {:?}", local_ambiguous_slots); 565 | 566 | let result = CheckWitnessOutput { 567 | producing_slots, 568 | local_producing_slots, 569 | invalid_slots, 570 | local_invalid_slots, 571 | won_slots, 572 | local_won_slots, 573 | lost_slots, 574 | local_lost_slots, 575 | missed_slots, 576 | local_missed_slots, 577 | ambiguous_slots, 578 | local_ambiguous_slots, 579 | }; 580 | let mut f = open_buffered_file(&opts.out_file)?; 581 | f.write_all(serde_json::to_string(&result)?.as_bytes())?; 582 | f.flush()?; 583 | 584 | Ok(()) 585 | } 586 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod params; 2 | -------------------------------------------------------------------------------- /src/params.rs: -------------------------------------------------------------------------------- 1 | // (* c is a constant factor on vrf-win likelihood *) 2 | // (* c = 2^0 is production behavior *) 3 | // (* c > 2^0 is a temporary hack for testnets *) 4 | pub const C: i32 = 1; 5 | 6 | // (* f determines the fraction of slots that will have blocks if c = 2^0 *) 7 | pub const F: f32 = 3_f32 / 4_f32; 8 | -------------------------------------------------------------------------------- /uml/decision.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zkvalidator/mina-vrf-rs/0706f66b0befdb3fa0896bafb67748f94707668f/uml/decision.png -------------------------------------------------------------------------------- /uml/decision.uml: -------------------------------------------------------------------------------- 1 | @startuml 2 | !theme kobi from https://raw.githubusercontent.com/kobigurk/uml/master 3 | if (winners) is (0) then 4 | if (saw my producer) is (yes) then 5 | if (late) is (yes) then 6 | #coral:too late; 7 | detach 8 | else (no) 9 | #lightyellow:lost (reorg); 10 | detach 11 | endif 12 | else (no) 13 | #coral:not produced; 14 | detach 15 | endif 16 | else (>0) 17 | if (my producer is the winner) is (yes) then 18 | #lightgreen:won; 19 | detach 20 | else (no) 21 | if (saw my producer) is (yes) then 22 | if (block height) is (old) then 23 | #coral:block height too old; 24 | detach 25 | else (equal) 26 | if (VRF) is (better) then 27 | if (late) is (yes) then 28 | #coral:too late; 29 | detach 30 | else (no) 31 | #lightyellow:lost (reorg); 32 | detach 33 | endif 34 | else (worse) 35 | #lightyellow:lost; 36 | detach 37 | endif 38 | endif 39 | else (no) 40 | if (VRF) is (better) then 41 | #coral:not produced; 42 | detach 43 | else (worse) 44 | #lightyellow:lost; 45 | detach 46 | endif 47 | endif 48 | endif 49 | endif 50 | @enduml 51 | --------------------------------------------------------------------------------