├── .github └── workflows │ ├── client-test.yaml │ ├── composer-test.yaml │ ├── sheth-bench.yaml │ └── sheth-test.yaml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── HACKING.md ├── LICENSE ├── Makefile ├── README.md ├── benches └── execution.rs ├── chisel.toml ├── client ├── Cargo.lock ├── Cargo.toml ├── README.md └── src │ ├── client │ ├── command.rs │ ├── error.rs │ ├── mod.rs │ └── parse.rs │ ├── main.rs │ └── package.rs ├── composer ├── Cargo.lock ├── Cargo.toml └── src │ ├── accounts.rs │ ├── blob.rs │ ├── lib.rs │ ├── proof │ ├── h256.rs │ ├── mod.rs │ ├── offsets.rs │ ├── sort.rs │ └── uncompressed.rs │ └── transactions.rs └── src ├── account.rs ├── address.rs ├── bls.rs ├── error.rs ├── hash.rs ├── lib.rs ├── main.rs ├── process.rs ├── state ├── imp.rs ├── mock.rs └── mod.rs ├── transaction.rs └── u264.rs /.github/workflows/client-test.yaml: -------------------------------------------------------------------------------- 1 | name: client-test 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Build 13 | run: 14 | cargo build --manifest-path=client/Cargo.toml --release --verbose 15 | - name: Run tests 16 | run: 17 | cargo test --manifest-path=client/Cargo.toml --release --verbose 18 | -------------------------------------------------------------------------------- /.github/workflows/composer-test.yaml: -------------------------------------------------------------------------------- 1 | name: composer-test 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Build 13 | run: 14 | cargo build --manifest-path=composer/Cargo.toml --release --verbose 15 | - name: Run tests 16 | run: 17 | cargo test --manifest-path=composer/Cargo.toml --release --verbose 18 | -------------------------------------------------------------------------------- /.github/workflows/sheth-bench.yaml: -------------------------------------------------------------------------------- 1 | name: sheth-bench 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Install WebAssembly target 13 | uses: actions-rs/toolchain@v1 14 | with: 15 | toolchain: stable 16 | target: wasm32-unknown-unknown 17 | - name: Install Chisel 18 | run: 19 | cargo install chisel 20 | - name: Build 21 | run: 22 | make build-wasm 23 | - name: Run benchmark 24 | run: 25 | cargo bench --bench execution -- --noplot --sample-size=10 26 | -------------------------------------------------------------------------------- /.github/workflows/sheth-test.yaml: -------------------------------------------------------------------------------- 1 | name: sheth-test 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Build 13 | run: 14 | cargo build --release --verbose 15 | - name: Run tests 16 | run: 17 | cargo test --release --verbose 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target 2 | **/*.rs.bk 3 | /scout 4 | flamegraph.svg 5 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "arrayref" 5 | version = "0.3.5" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "arrayvec" 10 | version = "0.4.11" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | dependencies = [ 13 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 14 | ] 15 | 16 | [[package]] 17 | name = "atty" 18 | version = "0.2.13" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | dependencies = [ 21 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 23 | ] 24 | 25 | [[package]] 26 | name = "autocfg" 27 | version = "0.1.6" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | 30 | [[package]] 31 | name = "bigint" 32 | version = "4.4.1" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | dependencies = [ 35 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 36 | "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 37 | ] 38 | 39 | [[package]] 40 | name = "bitflags" 41 | version = "1.2.0" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | 44 | [[package]] 45 | name = "block-buffer" 46 | version = "0.7.3" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | dependencies = [ 49 | "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 50 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 51 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 52 | "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", 53 | ] 54 | 55 | [[package]] 56 | name = "block-padding" 57 | version = "0.1.4" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | dependencies = [ 60 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 61 | ] 62 | 63 | [[package]] 64 | name = "bstr" 65 | version = "0.2.8" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | dependencies = [ 68 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 69 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 70 | "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 71 | "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 72 | ] 73 | 74 | [[package]] 75 | name = "byte-tools" 76 | version = "0.3.1" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | 79 | [[package]] 80 | name = "byteorder" 81 | version = "1.3.2" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | 84 | [[package]] 85 | name = "c2-chacha" 86 | version = "0.2.2" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | dependencies = [ 89 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 90 | "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 91 | ] 92 | 93 | [[package]] 94 | name = "cast" 95 | version = "0.2.2" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | 98 | [[package]] 99 | name = "cfg-if" 100 | version = "0.1.10" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | 103 | [[package]] 104 | name = "clap" 105 | version = "2.33.0" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | dependencies = [ 108 | "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 109 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 110 | "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 111 | ] 112 | 113 | [[package]] 114 | name = "composer" 115 | version = "0.1.0" 116 | dependencies = [ 117 | "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 118 | "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "imp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 121 | "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 122 | "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 123 | "sheth 0.1.0", 124 | ] 125 | 126 | [[package]] 127 | name = "criterion" 128 | version = "0.3.0" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | dependencies = [ 131 | "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 132 | "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 133 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 134 | "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 135 | "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 136 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 137 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 138 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 139 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 140 | "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 141 | "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 142 | "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 143 | "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 144 | "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 145 | "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 146 | "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 147 | "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 148 | ] 149 | 150 | [[package]] 151 | name = "criterion-plot" 152 | version = "0.4.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | dependencies = [ 155 | "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 156 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 157 | ] 158 | 159 | [[package]] 160 | name = "crossbeam-deque" 161 | version = "0.7.1" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | dependencies = [ 164 | "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 165 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 166 | ] 167 | 168 | [[package]] 169 | name = "crossbeam-epoch" 170 | version = "0.7.2" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | dependencies = [ 173 | "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", 174 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 175 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 176 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 177 | "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 178 | "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 179 | ] 180 | 181 | [[package]] 182 | name = "crossbeam-queue" 183 | version = "0.1.2" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | dependencies = [ 186 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 187 | ] 188 | 189 | [[package]] 190 | name = "crossbeam-utils" 191 | version = "0.6.6" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | dependencies = [ 194 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 195 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 196 | ] 197 | 198 | [[package]] 199 | name = "crunchy" 200 | version = "0.1.6" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | 203 | [[package]] 204 | name = "csv" 205 | version = "1.1.1" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | dependencies = [ 208 | "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 209 | "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 210 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 211 | "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 212 | "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 213 | ] 214 | 215 | [[package]] 216 | name = "csv-core" 217 | version = "0.1.6" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | dependencies = [ 220 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 221 | ] 222 | 223 | [[package]] 224 | name = "digest" 225 | version = "0.8.1" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | dependencies = [ 228 | "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", 229 | ] 230 | 231 | [[package]] 232 | name = "either" 233 | version = "1.5.3" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | 236 | [[package]] 237 | name = "ewasm" 238 | version = "0.1.2" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | dependencies = [ 241 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 242 | "wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 243 | ] 244 | 245 | [[package]] 246 | name = "fake-simd" 247 | version = "0.1.2" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | 250 | [[package]] 251 | name = "generic-array" 252 | version = "0.12.3" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | dependencies = [ 255 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 256 | ] 257 | 258 | [[package]] 259 | name = "getrandom" 260 | version = "0.1.12" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | dependencies = [ 263 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 264 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 265 | "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 266 | ] 267 | 268 | [[package]] 269 | name = "hex" 270 | version = "0.3.2" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | 273 | [[package]] 274 | name = "imp" 275 | version = "0.1.0" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | dependencies = [ 278 | "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 279 | "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 280 | ] 281 | 282 | [[package]] 283 | name = "itertools" 284 | version = "0.8.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | dependencies = [ 287 | "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 288 | ] 289 | 290 | [[package]] 291 | name = "itoa" 292 | version = "0.4.4" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | 295 | [[package]] 296 | name = "lazy_static" 297 | version = "1.4.0" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | 300 | [[package]] 301 | name = "libc" 302 | version = "0.2.62" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | 305 | [[package]] 306 | name = "log" 307 | version = "0.4.8" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | dependencies = [ 310 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 311 | ] 312 | 313 | [[package]] 314 | name = "memchr" 315 | version = "2.2.1" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | dependencies = [ 318 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 319 | ] 320 | 321 | [[package]] 322 | name = "memoffset" 323 | version = "0.5.1" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | dependencies = [ 326 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 327 | ] 328 | 329 | [[package]] 330 | name = "memory_units" 331 | version = "0.3.0" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | 334 | [[package]] 335 | name = "nodrop" 336 | version = "0.1.13" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | 339 | [[package]] 340 | name = "num-bigint" 341 | version = "0.2.3" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | dependencies = [ 344 | "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 345 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 346 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 347 | ] 348 | 349 | [[package]] 350 | name = "num-integer" 351 | version = "0.1.41" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | dependencies = [ 354 | "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 355 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 356 | ] 357 | 358 | [[package]] 359 | name = "num-rational" 360 | version = "0.2.2" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | dependencies = [ 363 | "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 364 | "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 365 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 366 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 367 | ] 368 | 369 | [[package]] 370 | name = "num-traits" 371 | version = "0.2.8" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | dependencies = [ 374 | "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 375 | ] 376 | 377 | [[package]] 378 | name = "num_cpus" 379 | version = "1.10.1" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | dependencies = [ 382 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 383 | ] 384 | 385 | [[package]] 386 | name = "opaque-debug" 387 | version = "0.2.3" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | 390 | [[package]] 391 | name = "parity-wasm" 392 | version = "0.40.3" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | 395 | [[package]] 396 | name = "ppv-lite86" 397 | version = "0.2.5" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | 400 | [[package]] 401 | name = "proc-macro2" 402 | version = "1.0.4" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | dependencies = [ 405 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 406 | ] 407 | 408 | [[package]] 409 | name = "qimalloc" 410 | version = "0.1.0" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | 413 | [[package]] 414 | name = "quote" 415 | version = "1.0.2" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | dependencies = [ 418 | "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 419 | ] 420 | 421 | [[package]] 422 | name = "rand" 423 | version = "0.7.2" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | dependencies = [ 426 | "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 427 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 428 | "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 429 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 430 | "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 431 | ] 432 | 433 | [[package]] 434 | name = "rand_chacha" 435 | version = "0.2.1" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | dependencies = [ 438 | "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 439 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 440 | ] 441 | 442 | [[package]] 443 | name = "rand_core" 444 | version = "0.5.1" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | dependencies = [ 447 | "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 448 | ] 449 | 450 | [[package]] 451 | name = "rand_hc" 452 | version = "0.2.0" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | dependencies = [ 455 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 456 | ] 457 | 458 | [[package]] 459 | name = "rand_os" 460 | version = "0.2.2" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | dependencies = [ 463 | "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 464 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 465 | ] 466 | 467 | [[package]] 468 | name = "rand_xoshiro" 469 | version = "0.3.1" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | dependencies = [ 472 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 473 | ] 474 | 475 | [[package]] 476 | name = "rayon" 477 | version = "1.2.0" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | dependencies = [ 480 | "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 481 | "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 482 | "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 483 | ] 484 | 485 | [[package]] 486 | name = "rayon-core" 487 | version = "1.6.0" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | dependencies = [ 490 | "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 491 | "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 492 | "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 493 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 494 | "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 495 | ] 496 | 497 | [[package]] 498 | name = "regex-automata" 499 | version = "0.1.8" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | dependencies = [ 502 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 503 | ] 504 | 505 | [[package]] 506 | name = "rustc_version" 507 | version = "0.2.3" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | dependencies = [ 510 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 511 | ] 512 | 513 | [[package]] 514 | name = "ryu" 515 | version = "1.0.0" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | 518 | [[package]] 519 | name = "same-file" 520 | version = "1.0.5" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | dependencies = [ 523 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 524 | ] 525 | 526 | [[package]] 527 | name = "scopeguard" 528 | version = "1.0.0" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | 531 | [[package]] 532 | name = "semver" 533 | version = "0.9.0" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | dependencies = [ 536 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 537 | ] 538 | 539 | [[package]] 540 | name = "semver-parser" 541 | version = "0.7.0" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | 544 | [[package]] 545 | name = "serde" 546 | version = "1.0.101" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | 549 | [[package]] 550 | name = "serde_derive" 551 | version = "1.0.101" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | dependencies = [ 554 | "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 555 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 556 | "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 557 | ] 558 | 559 | [[package]] 560 | name = "serde_json" 561 | version = "1.0.40" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | dependencies = [ 564 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 565 | "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 566 | "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 567 | ] 568 | 569 | [[package]] 570 | name = "sha2" 571 | version = "0.8.0" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | dependencies = [ 574 | "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 575 | "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 576 | "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 577 | "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 578 | ] 579 | 580 | [[package]] 581 | name = "sheth" 582 | version = "0.1.0" 583 | dependencies = [ 584 | "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 585 | "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 586 | "composer 0.1.0", 587 | "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 588 | "ewasm 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 589 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 590 | "imp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 591 | "qimalloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 592 | "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 593 | ] 594 | 595 | [[package]] 596 | name = "syn" 597 | version = "1.0.5" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | dependencies = [ 600 | "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 601 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 602 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 603 | ] 604 | 605 | [[package]] 606 | name = "textwrap" 607 | version = "0.11.0" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | dependencies = [ 610 | "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 611 | ] 612 | 613 | [[package]] 614 | name = "tinytemplate" 615 | version = "1.0.2" 616 | source = "registry+https://github.com/rust-lang/crates.io-index" 617 | dependencies = [ 618 | "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 619 | "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 620 | ] 621 | 622 | [[package]] 623 | name = "typenum" 624 | version = "1.10.0" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | 627 | [[package]] 628 | name = "unicode-width" 629 | version = "0.1.6" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | 632 | [[package]] 633 | name = "unicode-xid" 634 | version = "0.2.0" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | 637 | [[package]] 638 | name = "walkdir" 639 | version = "2.2.9" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | dependencies = [ 642 | "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 643 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 644 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 645 | ] 646 | 647 | [[package]] 648 | name = "wasi" 649 | version = "0.7.0" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | 652 | [[package]] 653 | name = "wasmi" 654 | version = "0.5.1" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | dependencies = [ 657 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 658 | "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 659 | "num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 660 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 661 | "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", 662 | "wasmi-validation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 663 | ] 664 | 665 | [[package]] 666 | name = "wasmi-validation" 667 | version = "0.2.0" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | dependencies = [ 670 | "parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)", 671 | ] 672 | 673 | [[package]] 674 | name = "winapi" 675 | version = "0.3.8" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | dependencies = [ 678 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 679 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 680 | ] 681 | 682 | [[package]] 683 | name = "winapi-i686-pc-windows-gnu" 684 | version = "0.4.0" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | 687 | [[package]] 688 | name = "winapi-util" 689 | version = "0.1.2" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | dependencies = [ 692 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 693 | ] 694 | 695 | [[package]] 696 | name = "winapi-x86_64-pc-windows-gnu" 697 | version = "0.4.0" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | 700 | [metadata] 701 | "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" 702 | "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" 703 | "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 704 | "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" 705 | "checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" 706 | "checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" 707 | "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" 708 | "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" 709 | "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" 710 | "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 711 | "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 712 | "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" 713 | "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" 714 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 715 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 716 | "checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" 717 | "checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" 718 | "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" 719 | "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" 720 | "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" 721 | "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" 722 | "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" 723 | "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" 724 | "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" 725 | "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" 726 | "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" 727 | "checksum ewasm 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d43ab814809fde499fff080b93bbf4e4d276dc29787ca067cd0a82c58a533ed2" 728 | "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 729 | "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" 730 | "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" 731 | "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 732 | "checksum imp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "015f618e11715d4c739509a030fdac9278f2b036a74ca008889e95a9e186cc0e" 733 | "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" 734 | "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 735 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 736 | "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" 737 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 738 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" 739 | "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" 740 | "checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" 741 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 742 | "checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" 743 | "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" 744 | "checksum num-rational 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" 745 | "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" 746 | "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" 747 | "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" 748 | "checksum parity-wasm 0.40.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1e39faaa292a687ea15120b1ac31899b13586446521df6c149e46f1584671e0f" 749 | "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" 750 | "checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc" 751 | "checksum qimalloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "500cbe6252656ab00e340633090f7ccca4053a1dad2ef1f83f96e5074488f384" 752 | "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 753 | "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" 754 | "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" 755 | "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 756 | "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 757 | "checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" 758 | "checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" 759 | "checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123" 760 | "checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b" 761 | "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" 762 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 763 | "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" 764 | "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" 765 | "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" 766 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 767 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 768 | "checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" 769 | "checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" 770 | "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" 771 | "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" 772 | "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" 773 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 774 | "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" 775 | "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 776 | "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" 777 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 778 | "checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" 779 | "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" 780 | "checksum wasmi 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f31d26deb2d9a37e6cfed420edce3ed604eab49735ba89035e13c98f9a528313" 781 | "checksum wasmi-validation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6bc0356e3df56e639fc7f7d8a99741915531e27ed735d911ed83d7e1339c8188" 782 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 783 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 784 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" 785 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 786 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sheth" 3 | version = "0.1.0" 4 | authors = ["Matt Garnett <14004106+lightclient@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "sheth" 9 | crate-type = ["cdylib", "lib"] 10 | path = "src/lib.rs" 11 | 12 | [[bin]] 13 | name = "binsheth" 14 | path = "src/main.rs" 15 | 16 | [features] 17 | default = ["std"] 18 | std = [] 19 | scout = [] 20 | 21 | [profile.release] 22 | lto = true 23 | debug = false 24 | 25 | [dependencies] 26 | arrayref = "0.3.5" 27 | bigint = "4.4.1" 28 | hex = "0.3.2" 29 | imp = "0.1.0" 30 | qimalloc = "0.1.0" 31 | sha2 = "0.8.0" 32 | 33 | [dev-dependencies] 34 | composer = { path = "./composer" } 35 | criterion = "0.3" 36 | ewasm = "0.1.2" 37 | 38 | [[bench]] 39 | name = "execution" 40 | harness = false 41 | -------------------------------------------------------------------------------- /HACKING.md: -------------------------------------------------------------------------------- 1 | # Hacking `sheth` 2 | 3 | Read on to learn how to use `sheth` as a foundation for your execution 4 | environment! 5 | 6 | ## Overview 7 | 8 | `sheth`'s motivations list various performance metrics -- however, it is 9 | unlikely that `sheth` will ever be maximally performant. This reasons for this 10 | is long, but idiomatic Rust does create overhead when compiling to 11 | WebAssembly. In some cases, idiomatic Rust is chosen over performance to create 12 | an inviting codebase for new researchers & developers. 13 | 14 | ## Getting Started 15 | 16 | It's easier to think of `sheth` as a rough framework in which transaction-based 17 | execution environments may be developed. In that vein, `sheth` is composed of 18 | several interfaces that can be thought of as plug-n-play compatible. 19 | 20 | ```text 21 | +------------------------+---------------------------+------------------------+ 22 | | | | | 23 | | transfer | deposit | withdraw | 24 | | | | | 25 | +------------------------+---------------------------+------------------------+ 26 | | | 27 | | tx interpreter | 28 | | | 29 | +-----------+-----------+-----------+-------------+-------------+-------------+ 30 | | | | | | | | 31 | | root | value | nonce | add_value | sub_value | inc_nonce | 32 | | | | | | | | 33 | +-----------+-----------+-----------+-------------+-------------+-------------+ 34 | | | 35 | | multiproof db (imp) | 36 | | | 37 | +-----------------------------------------------------------------------------+ 38 | | | 39 | | sheth | 40 | | | 41 | +-----------------------------------------------------------------------------+ 42 | ``` 43 | 44 | In the diagram above, `sheth` is the core interface. Essentially everything on 45 | top of it can be added to or swapped out with alternative implementations. 46 | 47 | 48 | ## Multiproof database 49 | 50 | In accordance with Ethereum 2.0 specification, `sheth` adheres to the stateless 51 | paradigm. This means that at runtime the only state provided by the protocol is 52 | a 32 byte hash. Any other information that an EE wants to authenticate must be 53 | authenticated against that hash. As of now, `sheth` uses the `Imp` merkle proof 54 | format. This can be replaced with any type of backend, so long as it implements 55 | the `State` trait. 56 | 57 | ## Extending the `State` trait 58 | 59 | The `State` trait defines an interface for accessing data from the backend. 60 | There is nothing particularly special about the methods defined in the trait, 61 | other than the fact that they are needed for `sheth` to operate. 62 | 63 | A good place to add additional functionality to `sheth` or transform `sheth` 64 | into something completely different is the `State` trait. Treat the `State` 65 | trait similarly to how contract variables are treated in Solidity. The main 66 | difference is that Solidity already defines how to retrieve certain data types 67 | from their definitions alone. `sheth` is still primitive in this respect, so 68 | the `State` trait requires that a retrieval algorithm be defined alongside 69 | the definition of the member variables. 70 | 71 | ## New Transaction Types 72 | 73 | The transaction interpreter is really just a pretentious term for the match 74 | statement which defines how certain transaction types are dealt with. `sheth` 75 | comes with the concept of three types of transactions: `transfer`, `deposit`, 76 | and `withdraw`. Adding additional transaction types should be as simple as 77 | defining its structure, processing it in the transaction processor, and 78 | unmarshalling it from the input data. 79 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | setup: 2 | git clone --single-branch --branch sheth git@github.com:lightclient/scout.git 3 | 4 | build: 5 | cargo build --manifest-path=client/Cargo.toml --release 6 | cargo build --manifest-path=scout/Cargo.toml --release 7 | 8 | build-wasm: 9 | cargo build --lib --release --no-default-features --features=scout --target wasm32-unknown-unknown 10 | chisel run --config chisel.toml 11 | 12 | scout: build build-wasm 13 | client/target/release/client package 2 1 --height=256 --scout > scout/sheth.yaml 14 | cp target/wasm32-unknown-unknown/release/sheth.wasm scout/sheth.wasm 15 | scout/target/release/phase2-scout scout/sheth.yaml 16 | 17 | test: build 18 | cargo build --bin binsheth --release 19 | client/target/release/client package 2 1 --height=256 > blob 20 | -target/release/binsheth blob 21 | rm blob 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sheth 2 | 3 | ![sheth test status](https://github.com/lightclient/sheth/workflows/sheth-test/badge.svg) 4 | ![client test status](https://github.com/lightclient/sheth/workflows/client-test/badge.svg) 5 | ![composer test status](https://github.com/lightclient/sheth/workflows/composer-test/badge.svg) 6 | [![Apache License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/lightclient/sheth#license) 7 | 8 | `sheth` [ ˈshēth ] is an [execution 9 | environment](https://hackmd.io/UzysWse1Th240HELswKqVA?view#Execution-Environment-EE) 10 | (EE) for Ethereum 2.0 that facilitates the movement of ether within a shard and 11 | provides mechanisms to move ether between a shard and the beacon chain. 12 | 13 | ## Quick Start 14 | 15 | First, setup your environment: 16 | ```console 17 | rustup target install wasm32-unknown-unknown 18 | cargo install chisel 19 | make setup 20 | ``` 21 | 22 | Then simulate execution using [Scout](https://github.com/ewasm/scout): 23 | ```console 24 | make scout 25 | ``` 26 | 27 | Or run on your local architecture (useful for tracking down bugs): 28 | ```console 29 | make test 30 | ``` 31 | 32 | #### Recommended Reading 33 | The design space for EEs is broad and builds on many different Ethereum 2.0 34 | related concepts. If you're lost, here are a few places to get started: 35 | 36 | * [Phase 2 Wiki](https://hackmd.io/UzysWse1Th240HELswKqVA) 37 | * [Phase 2 Proposal](https://notes.ethereum.org/w1Pn2iMmSTqCmVUTGV4T5A?view#Implementing-in-shard-ETH-transfers) 38 | * [Eth EE Proposal](https://ethresear.ch/t/eth-execution-environment-proposal/5507) 39 | 40 | Ping me [@lightclients](https://twitter.com/lightclients) for any 41 | other questions / concerns. 42 | 43 | ## Motivation 44 | * Understanding the developer experience regarding EEs could influence design 45 | decisions of the protocol and EE runtime. 46 | * Efficiently authenticating and updating merkle multi-proofs is critical to the 47 | success of stateless execution environments. 48 | * In order to develop strong tooling for EE development, it's important to 49 | determine a lower bound for execution time and binary size to target. 50 | * Provide a framework on which others can develop and experiment. 51 | 52 | 53 | ## Architecture 54 | At a high level, `sheth` provides a single state transition function: 55 | 56 | ```rust 57 | pub fn main(pre_state: &[u8; 32], data: &[u8]) -> [u8; 32]; 58 | ``` 59 | 60 | The main function essentially takes in the latest merkle root of the state as 61 | `pre_state` and some amount of `data`. It deserializes the data into the 62 | transactions that will be executed and the merkle multi-proof which is used 63 | authenticate the transactions. Due to some of the semantics of WebAssembly, it 64 | isn't quite this simple (see the [FFI interface](src/lib.rs)) -- but the general 65 | idea remains intact. 66 | 67 | `sheth`'s design is heavily influenced by Vitalik's sample EE in his [phase 2 68 | proposal](https://notes.ethereum.org/w1Pn2iMmSTqCmVUTGV4T5A?view#Implementing-in-shard-ETH-transfers). 69 | 70 | ### State 71 | The `state` can be thought of abstractly as an array `[Account, 2**256]`, where 72 | an account's index in the array is equal to `Sha256(account.pubkey)`. This is 73 | far too large to fit into memory all at once, so operations are done on specific 74 | elements within a merkle multi-proof. 75 | 76 | The sparse merkle tree for `sheth`'s `state` can be roughly visualized as 77 | follows: 78 | 79 | ``` 80 | FL = first leaf node = 2**256 81 | LL = last leaf node = 2**257 - 1 82 | 83 | +---------- 1 ----------+ 84 | / \ 85 | +-- 2 --+ +-- 3 --+ 86 | / \ / \ 87 | ... ... ... ... 88 | / \ / \ / \ / \ 89 | FL+0 FL+1 FL+2 FL+3 ... LL-3 LL-2 LL-1 LL-0 90 | ``` 91 | 92 | Each leaf node is the root of the corresponding `account`. An `account`'s merkle 93 | tree structure is as follows: 94 | 95 | ``` 96 | +--- account ---+ 97 | / \ 98 | pubkey_root sub_root 99 | / \ / \ 100 | pk[0..32] pk[32..48] nonce value 101 | ``` 102 | 103 | ### Merkle Multi-Proof 104 | A merkle multi-proof is a data structure which stores multiple branches proving 105 | various items within the `state`. For a formal definition, see the 106 | [specification](https://github.com/ethereum/eth2.0-specs/blob/dev/specs/light_client/merkle_proofs.md#merkle-multiproofs). 107 | 108 | #### Example 109 | Imagine a merkle tree of this shape (e.g. an `account`): 110 | 111 | ``` 112 | 1 113 | / \ 114 | 2 3 115 | / \ / \ 116 | 4 5 6 7 117 | ``` 118 | 119 | In order to prove `6` is included in the root at `1`, the nodes [2, 6, 7] would 120 | be needed since `1` and `3` can be calculated from that set. 121 | 122 | ``` 123 | 1 124 | / \ 125 | [2] 3 126 | / \ / \ 127 | 4 5[6] [7] 128 | ``` 129 | 130 | ## Roadmap 131 | - [x] Support intra-shard transfers 132 | - [ ] Consume beacon chain withdrawal receipts 133 | - [ ] Allow shard ether to be deposited to the beacon chain 134 | - [ ] Validate transaction signature against BLS pubkey 135 | - [x] Verify transaction nonce against account 136 | - [ ] Implement `merge` functionality for multiple packages 137 | - [ ] Minimize binary size 138 | - [ ] Minimize execution time 139 | - [ ] Minimize multi-proof size 140 | 141 | ## License 142 | Licensed under Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 143 | -------------------------------------------------------------------------------- /benches/execution.rs: -------------------------------------------------------------------------------- 1 | use composer::blob; 2 | use criterion::{criterion_group, criterion_main, Criterion}; 3 | use ewasm::{Execute, Runtime}; 4 | 5 | static SHETH_BINARY: &'static [u8] = 6 | include_bytes!("../target/wasm32-unknown-unknown/release/sheth.wasm"); 7 | 8 | fn large_proof(c: &mut Criterion) { 9 | let (blob, pre_state, _) = blob::generate_with_roots(2, 1, 256); 10 | let blob = blob.to_bytes(); 11 | 12 | c.bench_function("execute(2, 1, 256)", |b| { 13 | b.iter(|| { 14 | let mut runtime = Runtime::new(SHETH_BINARY, &blob, pre_state); 15 | runtime.execute(); 16 | }) 17 | }); 18 | } 19 | 20 | criterion_group!(benches, large_proof); 21 | criterion_main!(benches); 22 | -------------------------------------------------------------------------------- /chisel.toml: -------------------------------------------------------------------------------- 1 | transfer: 2 | file: "target/wasm32-unknown-unknown/release/sheth.wasm" 3 | trimexports: 4 | preset: "ewasm" 5 | verifyexports: 6 | preset: "ewasm" 7 | repack: 8 | preset: "ewasm" 9 | snip: 10 | preset: "ewasm" 11 | -------------------------------------------------------------------------------- /client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "client" 3 | version = "0.1.0" 4 | authors = ["Matt Garnett <14004106+lightclient@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | arrayref = "0.3.5" 9 | bigint = "4.4.1" 10 | clap = "2.33.0" 11 | composer = { path = "../composer" } 12 | dialoguer = "0.4.0" 13 | hex = "0.3.2" 14 | imp = "0.1.0" 15 | reqwest = "0.9.20" 16 | sheth = { path = "../", features = ["std"] } 17 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # `sheth` CLI 2 | 3 | The `sheth` CLI provides a command line interface to the tooling which supports 4 | the execution environment. 5 | 6 | ## Packager 7 | 8 | The packager is used to generate random transaction packages (transactions + 9 | multiproof). It's usage is defined as: 10 | 11 | ``` 12 | USAGE: 13 | client package [FLAGS] [OPTIONS] 14 | 15 | FLAGS: 16 | -h, --help Prints help information 17 | --scout When set, the output will be in the format of a Scout YAML file 18 | -V, --version Prints version information 19 | 20 | OPTIONS: 21 | -d, --height defines the height of sparse state structure [default: 256] 22 | 23 | ARGS: 24 | number of accounts that will be represented in the proof 25 | number of transactions to be generated 26 | ``` 27 | 28 | ## Client 29 | 30 | The client is an interactive tool which maintains the full state of the 31 | execution environment (e.g. all the accounts) and can process a few commands 32 | which lets users submit transactions and monitor balances. 33 | 34 | ``` 35 | USAGE: 36 | client start [OPTIONS] 37 | 38 | FLAGS: 39 | -h, --help Prints help information 40 | -V, --version Prints version information 41 | 42 | OPTIONS: 43 | -d, --height defines the height of sparse state structure [default: 256] 44 | 45 | ARGS: 46 | number of accounts that will be represented in the proof 47 | ``` 48 | 49 | -------------------------------------------------------------------------------- /client/src/client/command.rs: -------------------------------------------------------------------------------- 1 | use super::error::Error; 2 | use bigint::U256; 3 | use composer::accounts::AddressedAccount; 4 | use composer::transactions::serialize; 5 | use imp::Imp; 6 | use sheth::process::process_transactions; 7 | use sheth::state::State; 8 | use sheth::transaction::{Transaction, Transfer}; 9 | use sheth::u264::U264; 10 | use std::collections::HashMap; 11 | 12 | /// A enum that describes the possible commands a user might send to the client and their required 13 | /// arguments. 14 | #[derive(Debug, PartialEq)] 15 | pub enum Command { 16 | Balance(BalanceCmd), 17 | Transfer(TransferCmd), 18 | Accounts(AccountsCmd), 19 | Exit, 20 | } 21 | 22 | /// The balance command will return the balance of a specified address. 23 | #[derive(Debug, PartialEq)] 24 | pub struct BalanceCmd { 25 | pub(crate) address: U256, 26 | } 27 | 28 | /// The transfer command will transfer some amount from one specified account to another. 29 | #[derive(Debug, PartialEq)] 30 | pub struct TransferCmd { 31 | pub(crate) from: U256, 32 | pub(crate) to: U256, 33 | pub(crate) amount: u64, 34 | } 35 | 36 | /// The accounts command will list the accounts managed by the client. 37 | #[derive(Debug, PartialEq)] 38 | pub struct AccountsCmd(); 39 | 40 | impl BalanceCmd { 41 | pub fn execute(&self, db: &Imp) -> Result<(), Error> { 42 | let value = db 43 | .value(self.address.into()) 44 | .map_err(|_| Error::AddressUnknown("".to_string()))?; 45 | 46 | println!("Balance is: {}", value); 47 | 48 | Ok(()) 49 | } 50 | } 51 | 52 | impl TransferCmd { 53 | pub fn execute(&self, db: &mut Imp) -> Result<(), Error> { 54 | let nonce = db 55 | .nonce(self.from.into()) 56 | .map_err(|_| Error::AddressUnknown("".to_string()))?; 57 | 58 | let tx = Transaction::Transfer(Transfer { 59 | to: self.to.into(), 60 | from: self.from.into(), 61 | nonce, 62 | amount: self.amount, 63 | signature: [0u8; 96], 64 | }); 65 | 66 | let mut body = serialize(&vec![tx.clone()]); 67 | body.extend(imp_to_bytes(db)); 68 | let mut request: HashMap = HashMap::new(); 69 | request.insert("block_body".to_string(), hex::encode(body)); 70 | 71 | reqwest::Client::new() 72 | .post("http://127.0.0.1:5052/shard/0/block_body") 73 | .json(&request) 74 | .send() 75 | .map_err(|_| Error::TransactionFailed("connection error".to_string()))?; 76 | 77 | process_transactions(db, &vec![tx]) 78 | .map_err(|_| Error::TransactionFailed("local error".to_string()))?; 79 | 80 | Ok(()) 81 | } 82 | } 83 | 84 | impl AccountsCmd { 85 | pub fn execute(&self, accounts: &Vec) -> Result<(), Error> { 86 | for account in accounts { 87 | let mut buf = [0u8; 32]; 88 | account.0.to_big_endian(&mut buf); 89 | println!("0x{}", hex::encode(buf)); 90 | } 91 | 92 | Ok(()) 93 | } 94 | } 95 | 96 | fn imp_to_bytes(proof: &Imp) -> Vec { 97 | let mut ret: Vec = vec![]; 98 | ret.extend( 99 | (((proof.offsets.len() + 8) / 8) as u64) 100 | .to_le_bytes() 101 | .to_vec(), 102 | ); 103 | ret.extend(proof.offsets); 104 | ret.extend(&*proof.db); 105 | ret 106 | } 107 | 108 | #[cfg(test)] 109 | mod test { 110 | use super::*; 111 | 112 | use composer::blob; 113 | 114 | const ADDRESS: [u8; 32] = [ 115 | 185, 79, 94, 160, 186, 57, 73, 76, 232, 57, 97, 63, 255, 186, 116, 39, 149, 121, 38, 138, 116 | 116, 39, 149, 121, 38, 131, 66, 69, 103, 137, 101, 35, 117 | ]; 118 | 119 | macro_rules! create_db { 120 | ($blob_name: ident, $db_name: ident, $accounts_expr: expr, $tree_height: expr) => { 121 | #[allow(unused_mut)] 122 | let mut $blob_name = blob::generate($accounts_expr, 0, $tree_height); 123 | #[allow(unused_mut)] 124 | let mut $db_name = Imp::::new(&mut $blob_name.proof, $tree_height + 3); 125 | }; 126 | } 127 | 128 | fn create_test_transfer(accounts: &Vec) -> TransferCmd { 129 | TransferCmd { 130 | from: accounts[0].0, 131 | to: accounts[1].0, 132 | amount: 45, 133 | } 134 | } 135 | 136 | #[test] 137 | fn balance_known_address_ok() { 138 | create_db!(blob, db, 1, 256); 139 | assert_eq!( 140 | Ok(()), 141 | BalanceCmd { 142 | address: blob.accounts[0].0 143 | } 144 | .execute(&db) 145 | ); 146 | } 147 | 148 | #[test] 149 | #[ignore] // TODO: error handling in Imp(State)::value() and re-enable 150 | fn balance_unknown_address_ko() { 151 | create_db!(blob, db, 1, 256); 152 | assert_eq!( 153 | Err(Error::AddressUnknown("".to_string())), 154 | BalanceCmd { 155 | address: U256::from(ADDRESS) 156 | } 157 | .execute(&db) 158 | ); 159 | } 160 | 161 | #[test] 162 | fn accounts_ok() { 163 | create_db!(blob, _db, 2, 256); 164 | assert_eq!(Ok(()), AccountsCmd {}.execute(&blob.accounts)); 165 | } 166 | 167 | #[test] 168 | fn transfer_ko() { 169 | create_db!(blob, db, 2, 256); 170 | let accounts = blob.accounts; 171 | assert_eq!( 172 | Err(Error::TransactionFailed("connection error".to_string())), 173 | create_test_transfer(&accounts).execute(&mut db) 174 | ); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /client/src/client/error.rs: -------------------------------------------------------------------------------- 1 | /// An enum of errors that can occur while running a client. 2 | #[derive(Debug, PartialEq)] 3 | pub enum Error { 4 | /// Unable to parse command string into a new command 5 | CommandUnknown(String), 6 | 7 | /// The amount could not be parsed into an integer 8 | AmountInvalid(String), 9 | 10 | /// The address could not be parsed into a 32 byte value 11 | AddressInvalid(String), 12 | 13 | /// The arguments did not match the command's syntax 14 | ArgumentsIncorrect(String), 15 | 16 | /// The transaction was not able to be processed 17 | TransactionFailed(String), 18 | 19 | /// The address did not match a known account 20 | AddressUnknown(String), 21 | } 22 | -------------------------------------------------------------------------------- /client/src/client/mod.rs: -------------------------------------------------------------------------------- 1 | mod command; 2 | mod error; 3 | mod parse; 4 | 5 | use command::Command; 6 | use composer::blob; 7 | use dialoguer::{theme::CustomPromptCharacterTheme, Input}; 8 | use imp::Imp; 9 | use parse::parse_command; 10 | use sheth::u264::U264; 11 | use std::io; 12 | use std::io::prelude::*; 13 | 14 | pub fn start(accounts: usize, tree_height: usize) { 15 | println!("Starting sheth client"); 16 | 17 | print!("Initializing database ... "); 18 | io::stdout().flush().ok().expect("Could not flush stdout"); 19 | 20 | let blob = blob::generate(accounts, 0, tree_height); 21 | let accounts = blob.accounts; 22 | let mut proof = blob.proof; 23 | let mut db = Imp::::new(&mut proof, tree_height); 24 | 25 | println!("Ok.\n"); 26 | 27 | let theme = CustomPromptCharacterTheme::new('>'); 28 | 29 | loop { 30 | let command_str: String = Input::with_theme(&theme) 31 | .with_prompt("") 32 | .interact() 33 | .unwrap(); 34 | 35 | let command = parse_command(command_str); 36 | 37 | let result = match command { 38 | Ok(Command::Balance(b)) => b.execute(&db), 39 | Ok(Command::Transfer(t)) => t.execute(&mut db), 40 | Ok(Command::Exit) => std::process::exit(0), 41 | Ok(Command::Accounts(a)) => a.execute(&accounts), 42 | Err(e) => Err(e), 43 | }; 44 | 45 | if let Err(e) = result { 46 | println!("{:?}", e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /client/src/client/parse.rs: -------------------------------------------------------------------------------- 1 | use super::command::{AccountsCmd, BalanceCmd, Command, TransferCmd}; 2 | use super::error::Error; 3 | use arrayref::array_ref; 4 | use bigint::U256; 5 | 6 | /// Parse a given string and return the resulting `Command` or `Error`. 7 | pub fn parse_command(command: String) -> Result { 8 | let command: Vec<&str> = command.split_whitespace().collect(); 9 | 10 | match command[0] { 11 | "balance" | "b" => Ok(Command::Balance(parse_balance(command[1..].to_vec())?)), 12 | "transfer" | "t" => Ok(Command::Transfer(parse_transfer(command[1..].to_vec())?)), 13 | "accounts" | "a" => Ok(Command::Accounts(parse_accounts(command[1..].to_vec())?)), 14 | "exit" | "e" => Ok(Command::Exit), 15 | _ => Err(Error::CommandUnknown(command[0].to_string())), 16 | } 17 | } 18 | 19 | /// Parse the arguments for the balance command to determine the address to look up. 20 | pub fn parse_balance(balance_args: Vec<&str>) -> Result { 21 | if balance_args.len() != 1 { 22 | return Err(Error::ArgumentsIncorrect(balance_args.join(" "))); 23 | } 24 | 25 | let address = parse_address(balance_args[0])?; 26 | 27 | Ok(BalanceCmd { address }) 28 | } 29 | 30 | /// Parse the arguments for the transfer command to determine the values of the transaction that 31 | /// will be built. 32 | pub fn parse_transfer(transfer_args: Vec<&str>) -> Result { 33 | if transfer_args.len() != 3 { 34 | return Err(Error::ArgumentsIncorrect(transfer_args.join(" "))); 35 | } 36 | 37 | let from = parse_address(transfer_args[0])?; 38 | let to = parse_address(transfer_args[1])?; 39 | let amount = transfer_args[2] 40 | .parse::() 41 | .map_err(|_| Error::AmountInvalid(transfer_args[2].to_string()))?; 42 | 43 | Ok(TransferCmd { from, to, amount }) 44 | } 45 | 46 | /// Ensure that no arguments were given to the accounts command. 47 | pub fn parse_accounts(accounts_args: Vec<&str>) -> Result { 48 | if accounts_args.len() > 0 { 49 | return Err(Error::ArgumentsIncorrect(accounts_args.join(" "))); 50 | } 51 | 52 | Ok(AccountsCmd()) 53 | } 54 | 55 | /// Parse a hex string into a U256 value or return `Error`. 56 | pub fn parse_address(s: &str) -> Result { 57 | // If the address is prepended by `"0x"`, strip it. 58 | let s = if s.len() > 2 && &s[0..2] == "0x" { 59 | &s[2..] 60 | } else { 61 | &s 62 | }; 63 | 64 | let bytes = hex::decode(s).map_err(|_| Error::AddressInvalid(s.to_string()))?; 65 | 66 | if bytes.len() != 32 { 67 | Err(Error::AddressInvalid(s.to_string())) 68 | } else { 69 | Ok(U256::from(array_ref![bytes, 0, 32])) 70 | } 71 | } 72 | 73 | #[cfg(test)] 74 | mod test { 75 | use super::*; 76 | 77 | const ADDRESS: &str = "b94F5eA0ba39494cE839613fffBA74279579268A742795792683424567896523"; 78 | const PARSED_ADDRESS: [u8; 32] = [ 79 | 185, 79, 94, 160, 186, 57, 73, 76, 232, 57, 97, 63, 255, 186, 116, 39, 149, 121, 38, 138, 80 | 116, 39, 149, 121, 38, 131, 66, 69, 103, 137, 101, 35, 81 | ]; 82 | 83 | fn create_correct_balance_arguments<'a>() -> Vec<&'a str> { 84 | let mut arguments = vec![]; 85 | arguments.push(ADDRESS); 86 | arguments 87 | } 88 | 89 | fn create_correct_balance() -> BalanceCmd { 90 | let address = U256::from(PARSED_ADDRESS); 91 | BalanceCmd { address } 92 | } 93 | 94 | fn create_correct_transfer() -> TransferCmd { 95 | let from_to = U256::from(PARSED_ADDRESS); 96 | TransferCmd { 97 | from: from_to, 98 | to: from_to, 99 | amount: 34, 100 | } 101 | } 102 | 103 | fn create_correct_transfer_arguments<'a>() -> Vec<&'a str> { 104 | let mut arguments = vec![]; 105 | arguments.push(ADDRESS); 106 | arguments.push(ADDRESS); 107 | arguments.push("34"); 108 | arguments 109 | } 110 | 111 | macro_rules! assert_arguments_incorrect { 112 | ($arguments_expr: expr, $parser_expr: expr, $error_string_expr: expr) => { 113 | assert_eq!( 114 | $parser_expr($arguments_expr).unwrap_err(), 115 | Error::ArgumentsIncorrect($error_string_expr.to_string()) 116 | ) 117 | }; 118 | } 119 | 120 | macro_rules! assert_address_ok { 121 | ($address_expr: expr, $expected_expr: expr) => { 122 | assert_eq!( 123 | parse_address($address_expr).unwrap(), 124 | U256::from(*$expected_expr) 125 | ); 126 | }; 127 | } 128 | 129 | macro_rules! assert_address_invalid { 130 | ($address_expr: expr) => { 131 | assert_eq!( 132 | parse_address($address_expr).unwrap_err(), 133 | Error::AddressInvalid($address_expr.to_string()) 134 | ); 135 | }; 136 | } 137 | 138 | #[test] 139 | fn parse_command_ok() { 140 | let correct_balance = Command::Balance(create_correct_balance()); 141 | 142 | let mut long_arguments = vec!["balance"]; 143 | long_arguments.append(&mut create_correct_balance_arguments()); 144 | assert_eq!( 145 | parse_command(long_arguments.join(" ")).unwrap(), 146 | correct_balance 147 | ); 148 | 149 | let mut short_arguments = vec!["b"]; 150 | short_arguments.append(&mut create_correct_balance_arguments()); 151 | assert_eq!( 152 | parse_command(short_arguments.join(" ")).unwrap(), 153 | correct_balance 154 | ); 155 | 156 | let correct_transfer = Command::Transfer(create_correct_transfer()); 157 | 158 | let mut long_arguments = vec!["transfer"]; 159 | long_arguments.append(&mut create_correct_transfer_arguments()); 160 | assert_eq!( 161 | parse_command(long_arguments.join(" ")).unwrap(), 162 | correct_transfer 163 | ); 164 | 165 | let mut short_arguments = vec!["t"]; 166 | short_arguments.append(&mut create_correct_transfer_arguments()); 167 | assert_eq!( 168 | parse_command(short_arguments.join(" ")).unwrap(), 169 | correct_transfer 170 | ); 171 | 172 | let correct_accounts = Command::Accounts(AccountsCmd {}); 173 | 174 | assert_eq!( 175 | parse_command("accounts".to_string()).unwrap(), 176 | correct_accounts 177 | ); 178 | 179 | assert_eq!(parse_command("a".to_string()).unwrap(), correct_accounts); 180 | 181 | let correct_exit = Command::Exit; 182 | 183 | assert_eq!(parse_command("exit".to_string()).unwrap(), correct_exit); 184 | 185 | assert_eq!(parse_command("e".to_string()).unwrap(), correct_exit); 186 | } 187 | 188 | #[test] 189 | fn parse_command_ko() { 190 | assert_eq!( 191 | parse_command("x".to_string()).unwrap_err(), 192 | Error::CommandUnknown("x".to_string()) 193 | ); 194 | } 195 | 196 | #[test] 197 | fn parse_balance_correct_arguments_ok() { 198 | assert_eq!( 199 | create_correct_balance(), 200 | parse_balance(create_correct_balance_arguments()).unwrap() 201 | ); 202 | } 203 | 204 | #[test] 205 | fn parse_balance_wrong_arguments_ko() { 206 | let short_arguments = vec![]; 207 | assert_arguments_incorrect!(short_arguments, parse_balance, ""); 208 | 209 | let mut long_arguments = create_correct_balance_arguments(); 210 | long_arguments.push(ADDRESS); 211 | assert_arguments_incorrect!( 212 | long_arguments, 213 | parse_balance, 214 | [ADDRESS, " ", ADDRESS].concat() 215 | ); 216 | } 217 | 218 | #[test] 219 | fn parse_transfer_correct_arguments_ok() { 220 | assert_eq!( 221 | create_correct_transfer(), 222 | parse_transfer(create_correct_transfer_arguments()).unwrap() 223 | ); 224 | } 225 | 226 | #[test] 227 | fn parse_transfer_wrong_arguments_ko() { 228 | let arguments = vec![]; 229 | assert_arguments_incorrect!(arguments, parse_transfer, ""); 230 | 231 | let mut short_arguments = create_correct_transfer_arguments(); 232 | short_arguments.pop(); 233 | short_arguments.pop(); 234 | assert_arguments_incorrect!(short_arguments, parse_transfer, ADDRESS); 235 | 236 | let mut short_arguments = create_correct_transfer_arguments(); 237 | short_arguments.pop(); 238 | assert_arguments_incorrect!( 239 | short_arguments, 240 | parse_transfer, 241 | [ADDRESS, " ", ADDRESS].concat() 242 | ); 243 | 244 | let mut wrong_arguments = create_correct_transfer_arguments(); 245 | wrong_arguments[2] = "a"; 246 | assert_eq!( 247 | Error::AmountInvalid("a".to_string()), 248 | parse_transfer(wrong_arguments).unwrap_err() 249 | ); 250 | 251 | let mut long_arguments = create_correct_transfer_arguments(); 252 | long_arguments.push("a"); 253 | let check_long_arguments = long_arguments.clone(); 254 | assert_arguments_incorrect!( 255 | long_arguments, 256 | parse_transfer, 257 | check_long_arguments.join(" ") 258 | ); 259 | } 260 | 261 | #[test] 262 | fn parse_accounts_no_arguments_ok() { 263 | assert_eq!(AccountsCmd(), parse_accounts(vec!()).unwrap()); 264 | } 265 | 266 | #[test] 267 | fn parse_accounts_with_arguments_ko() { 268 | let mut arguments = vec![]; 269 | arguments.push("mine"); 270 | let check_arguments = arguments.clone(); 271 | assert_arguments_incorrect!(arguments, parse_accounts, check_arguments.join(" ")); 272 | } 273 | 274 | #[test] 275 | fn parse_address_32b_prefixed_by_0x_ok() { 276 | let mut address = "0x".to_string(); 277 | address.push_str(ADDRESS); 278 | assert_address_ok!(&address, &PARSED_ADDRESS); 279 | } 280 | 281 | #[test] 282 | fn parse_address_32b_not_prefixed_ok() { 283 | assert_address_ok!(ADDRESS, &PARSED_ADDRESS); 284 | } 285 | 286 | #[test] 287 | fn parse_address_wrong_length_ko() { 288 | let short_address = &ADDRESS[..31]; 289 | 290 | assert_address_invalid!(short_address); 291 | 292 | let mut long_address = ADDRESS.to_string(); 293 | long_address.push('3'); 294 | 295 | assert_address_invalid!(&long_address); 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /client/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate clap; 3 | 4 | mod client; 5 | mod package; 6 | 7 | use clap::{App, Arg, SubCommand}; 8 | 9 | fn main() { 10 | let matches = App::new("sheth-client") 11 | .version("0.0.1") 12 | .author("Matt G. ") 13 | .about("Builds transaction packages for the Sheth EE") 14 | .subcommand( 15 | SubCommand::with_name("package") 16 | .about("Builds a random transaction package") 17 | .version("0.0.1") 18 | .arg( 19 | Arg::with_name("accounts") 20 | .required(true) 21 | .help("number of accounts that will be represented in the proof"), 22 | ) 23 | .arg( 24 | Arg::with_name("transactions") 25 | .required(true) 26 | .help("number of transactions to be generated"), 27 | ) 28 | .arg( 29 | Arg::with_name("height") 30 | .long("height") 31 | .short("d") 32 | .takes_value(true) 33 | .default_value("256") 34 | .help("defines the height of sparse state structure"), 35 | ) 36 | .arg( 37 | Arg::with_name("scout") 38 | .long("scout") 39 | .help("When set, the output will be in the format of a Scout YAML file"), 40 | ), 41 | ) 42 | .subcommand( 43 | SubCommand::with_name("start") 44 | .about("Starts a Sheth client") 45 | .arg( 46 | Arg::with_name("accounts") 47 | .required(true) 48 | .help("number of accounts that will be represented in the proof"), 49 | ) 50 | .arg( 51 | Arg::with_name("height") 52 | .long("height") 53 | .short("d") 54 | .takes_value(true) 55 | .default_value("256") 56 | .help("defines the height of sparse state structure"), 57 | ), 58 | ) 59 | .get_matches(); 60 | 61 | // Run packager 62 | if let Some(matches) = matches.subcommand_matches("package") { 63 | let accounts = value_t!(matches.value_of("accounts"), usize).unwrap_or_else(|e| e.exit()); 64 | let txs = value_t!(matches.value_of("transactions"), usize).unwrap_or_else(|e| e.exit()); 65 | let height = value_t!(matches.value_of("height"), usize).unwrap_or_else(|e| e.exit()); 66 | let scout = matches.is_present("scout"); 67 | 68 | let output = package::build(accounts, txs, height, scout); 69 | println!("{}", output); 70 | } 71 | 72 | // Start client 73 | if let Some(matches) = matches.subcommand_matches("start") { 74 | let accounts = value_t!(matches.value_of("accounts"), usize).unwrap_or_else(|e| e.exit()); 75 | let height = value_t!(matches.value_of("height"), usize).unwrap_or_else(|e| e.exit()); 76 | 77 | client::start(accounts, height); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /client/src/package.rs: -------------------------------------------------------------------------------- 1 | use composer::blob; 2 | 3 | pub fn build(accounts: usize, transactions: usize, height: usize, scout: bool) -> String { 4 | let (blob, pre_state, post_state) = blob::generate_with_roots(accounts, transactions, height); 5 | 6 | if scout { 7 | format!( 8 | "\ 9 | beacon_state: 10 | execution_scripts: 11 | - scout/sheth.wasm 12 | shard_pre_state: 13 | exec_env_states: 14 | - \"{}\" 15 | shard_blocks: 16 | - env: 0 17 | data: \"{}\" 18 | shard_post_state: 19 | exec_env_states: 20 | - \"{}\"", 21 | hex::encode(pre_state), 22 | hex::encode(blob.to_bytes()), 23 | hex::encode(post_state) 24 | ) 25 | } else { 26 | format!( 27 | "{} {} {}", 28 | hex::encode(pre_state), 29 | hex::encode(post_state), 30 | hex::encode(blob.to_bytes()), 31 | ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /composer/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "arrayref" 5 | version = "0.3.5" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "bigint" 10 | version = "4.4.1" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | dependencies = [ 13 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 14 | "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 15 | ] 16 | 17 | [[package]] 18 | name = "block-buffer" 19 | version = "0.7.3" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | dependencies = [ 22 | "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 24 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", 26 | ] 27 | 28 | [[package]] 29 | name = "block-padding" 30 | version = "0.1.4" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | dependencies = [ 33 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 34 | ] 35 | 36 | [[package]] 37 | name = "byte-tools" 38 | version = "0.3.1" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | 41 | [[package]] 42 | name = "byteorder" 43 | version = "1.3.2" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | 46 | [[package]] 47 | name = "c2-chacha" 48 | version = "0.2.2" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | dependencies = [ 51 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 52 | "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 53 | ] 54 | 55 | [[package]] 56 | name = "cfg-if" 57 | version = "0.1.10" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | 60 | [[package]] 61 | name = "composer" 62 | version = "0.1.0" 63 | dependencies = [ 64 | "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 66 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "imp 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 68 | "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 69 | "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 70 | "sheth 0.1.0", 71 | ] 72 | 73 | [[package]] 74 | name = "crunchy" 75 | version = "0.1.6" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | 78 | [[package]] 79 | name = "digest" 80 | version = "0.8.1" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | dependencies = [ 83 | "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", 84 | ] 85 | 86 | [[package]] 87 | name = "fake-simd" 88 | version = "0.1.2" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | 91 | [[package]] 92 | name = "generic-array" 93 | version = "0.12.3" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | dependencies = [ 96 | "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "getrandom" 101 | version = "0.1.12" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | dependencies = [ 104 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 105 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 106 | "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 107 | ] 108 | 109 | [[package]] 110 | name = "hex" 111 | version = "0.3.2" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | 114 | [[package]] 115 | name = "imp" 116 | version = "0.0.1" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | dependencies = [ 119 | "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 121 | ] 122 | 123 | [[package]] 124 | name = "lazy_static" 125 | version = "1.4.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | 128 | [[package]] 129 | name = "libc" 130 | version = "0.2.62" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | 133 | [[package]] 134 | name = "opaque-debug" 135 | version = "0.2.3" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | 138 | [[package]] 139 | name = "ppv-lite86" 140 | version = "0.2.5" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | 143 | [[package]] 144 | name = "qimalloc" 145 | version = "0.1.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | 148 | [[package]] 149 | name = "rand" 150 | version = "0.7.2" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | dependencies = [ 153 | "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 154 | "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 155 | "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 156 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 157 | "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 158 | ] 159 | 160 | [[package]] 161 | name = "rand_chacha" 162 | version = "0.2.1" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | dependencies = [ 165 | "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 166 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 167 | ] 168 | 169 | [[package]] 170 | name = "rand_core" 171 | version = "0.5.1" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | dependencies = [ 174 | "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 175 | ] 176 | 177 | [[package]] 178 | name = "rand_hc" 179 | version = "0.2.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | dependencies = [ 182 | "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 183 | ] 184 | 185 | [[package]] 186 | name = "sha2" 187 | version = "0.8.0" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | dependencies = [ 190 | "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", 191 | "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 192 | "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 193 | "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 194 | ] 195 | 196 | [[package]] 197 | name = "sheth" 198 | version = "0.1.0" 199 | dependencies = [ 200 | "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 201 | "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 202 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 203 | "imp 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 204 | "qimalloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 205 | "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 206 | ] 207 | 208 | [[package]] 209 | name = "typenum" 210 | version = "1.11.2" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | 213 | [[package]] 214 | name = "wasi" 215 | version = "0.7.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | 218 | [metadata] 219 | "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" 220 | "checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" 221 | "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" 222 | "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" 223 | "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" 224 | "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 225 | "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" 226 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 227 | "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" 228 | "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" 229 | "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 230 | "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" 231 | "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" 232 | "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 233 | "checksum imp 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5357a47ab57a37ef873ccfc8cd8448dd817e3663fe742b468fbc6104902f61de" 234 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 235 | "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" 236 | "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" 237 | "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" 238 | "checksum qimalloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "500cbe6252656ab00e340633090f7ccca4053a1dad2ef1f83f96e5074488f384" 239 | "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" 240 | "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" 241 | "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 242 | "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 243 | "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" 244 | "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" 245 | "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" 246 | -------------------------------------------------------------------------------- /composer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "composer" 3 | version = "0.1.0" 4 | authors = ["Matt Garnett <14004106+lightclient@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | arrayref = "0.3.5" 9 | bigint = "4.4.1" 10 | rand = "0.7" 11 | sha2 = "0.8.0" 12 | hex = "0.3.2" 13 | imp = "0.1.0" 14 | sheth = { path = "../", features = ["std"] } 15 | -------------------------------------------------------------------------------- /composer/src/accounts.rs: -------------------------------------------------------------------------------- 1 | use bigint::U256; 2 | use rand::{rngs::StdRng, Rng, SeedableRng}; 3 | use sha2::{Digest, Sha256}; 4 | use sheth::account::Account; 5 | use sheth::bls::PublicKey; 6 | use std::collections::HashMap; 7 | 8 | /// A tuple consisting of an `Account` and its address. 9 | /// 10 | /// The address is important for other stages in the `Blob` generation process since it defines 11 | /// where in the multi-proof the account resides. 12 | #[derive(Clone)] 13 | pub struct AddressedAccount(pub U256, pub Account); 14 | 15 | pub fn random_accounts(n: usize, height: usize) -> Vec { 16 | // TODO: check that the number of accounts can be generated from the tree 17 | 18 | let mut rng = StdRng::seed_from_u64(42); 19 | let mut map: HashMap = HashMap::new(); 20 | 21 | (0..n).fold(vec![], |mut acc, _| { 22 | let mut pubkey = [0u8; 48]; 23 | let address = loop { 24 | rng.fill(&mut pubkey[..]); 25 | 26 | // Hash public key to get address 27 | let mut address = U256::from(Sha256::digest(&pubkey).as_ref()); 28 | 29 | if height < 256 { 30 | address = address % (U256::one() << height); 31 | } 32 | 33 | if !map.contains_key(&address) { 34 | map.insert(address, true); 35 | break address; 36 | } 37 | }; 38 | 39 | acc.push(AddressedAccount( 40 | address, 41 | Account { 42 | pubkey: PublicKey::new(pubkey), 43 | nonce: rng.gen(), 44 | value: rng.gen_range(1, 1000), 45 | }, 46 | )); 47 | 48 | let mut buf = [0u8; 32]; 49 | address.to_big_endian(&mut buf); 50 | 51 | acc 52 | }) 53 | } 54 | 55 | #[cfg(test)] 56 | mod test { 57 | use super::*; 58 | 59 | #[test] 60 | fn generates_random_accounts() { 61 | let accounts = random_accounts(2, 256); 62 | 63 | for AddressedAccount(address, account) in accounts { 64 | assert_eq!( 65 | address, 66 | U256::from(Sha256::digest(&account.pubkey.as_bytes()).as_ref()) 67 | ); 68 | 69 | assert_ne!(account.pubkey.as_bytes().to_vec(), [0u8; 48].to_vec()); 70 | assert_ne!(account.nonce, 0); 71 | assert_ne!(account.value, 0); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /composer/src/blob.rs: -------------------------------------------------------------------------------- 1 | use crate::accounts::{random_accounts, AddressedAccount}; 2 | use crate::proof::offsets::calculate as calculate_offsets; 3 | use crate::proof::uncompressed::generate as generate_uncompressed_proof; 4 | use crate::transactions; 5 | use imp::Imp; 6 | use sheth::process::process_transactions; 7 | use sheth::transaction::Transaction; 8 | use sheth::u264::U264; 9 | 10 | /// A `Blob` includes all the neccessary data to construct the input data blob to `sheth`. 11 | #[derive(Clone)] 12 | pub struct Blob { 13 | pub proof: Vec, 14 | pub transactions: Vec, 15 | pub accounts: Vec, 16 | } 17 | 18 | impl Blob { 19 | /// Returns a serialized blob that can be used as input to `sheth`. 20 | pub fn to_bytes(&self) -> Vec { 21 | let mut ret = transactions::serialize(&self.transactions); 22 | ret.extend(&self.proof); 23 | ret 24 | } 25 | } 26 | 27 | /// Build a blob with specified tree height, accounts, and transactions. 28 | pub fn generate(accounts: usize, transactions: usize, tree_height: usize) -> Blob { 29 | let accounts = random_accounts(accounts, tree_height); 30 | let proof = generate_uncompressed_proof(accounts.clone(), tree_height); 31 | let offsets = calculate_offsets(proof.indexes); 32 | let transactions = transactions::generate(transactions, accounts.clone()); 33 | 34 | let mut compressed_proof = offsets.iter().fold(vec![], |mut acc, x| { 35 | acc.extend(&x.to_le_bytes()); 36 | acc 37 | }); 38 | 39 | compressed_proof = proof.values.iter().fold(compressed_proof, |mut acc, x| { 40 | acc.extend(x.as_bytes()); 41 | acc 42 | }); 43 | 44 | Blob { 45 | proof: compressed_proof, 46 | transactions, 47 | accounts, 48 | } 49 | } 50 | 51 | /// Returns a `Blob` and the pre-state root + post-state root for the blob. 52 | pub fn generate_with_roots( 53 | accounts: usize, 54 | transactions: usize, 55 | tree_height: usize, 56 | ) -> (Blob, [u8; 32], [u8; 32]) { 57 | let mut blob = generate(accounts, transactions, tree_height); 58 | let ret_blob = blob.clone(); 59 | 60 | let mut mem = Imp::::new(&mut blob.proof, tree_height + 3); 61 | 62 | let pre_state = mem.root(); 63 | assert_eq!(process_transactions(&mut mem, &blob.transactions), Ok(())); 64 | let post_state = mem.root(); 65 | 66 | (ret_blob, pre_state, post_state) 67 | } 68 | 69 | #[cfg(test)] 70 | mod test { 71 | use super::*; 72 | use arrayref::array_ref; 73 | 74 | #[test] 75 | fn generate_small_tree() { 76 | // Indexes = [16, 17, 9, 10, 11, 3] 77 | let mut proof = vec![ 78 | 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 79 | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 218, 109, 128, 80 | 123, 247, 149, 16, 97, 70, 229, 130, 39, 117, 217, 20, 176, 39, 122, 101, 36, 15, 101, 81 | 14, 212, 200, 167, 202, 119, 130, 78, 90, 223, 120, 72, 181, 215, 17, 188, 152, 131, 82 | 153, 99, 23, 163, 249, 201, 2, 105, 213, 103, 113, 0, 93, 84, 10, 25, 24, 73, 57, 201, 83 | 232, 208, 219, 42, 85, 242, 146, 169, 167, 93, 196, 41, 170, 134, 245, 251, 132, 117, 84 | 101, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 197, 33, 10, 45, 228, 168, 85 | 212, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 86 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88 | 0, 0, 0, 0, 0, 89 | ]; 90 | 91 | let root = vec![ 92 | 179, 144, 157, 22, 254, 252, 53, 30, 82, 212, 135, 5, 7, 48, 170, 16, 3, 127, 72, 133, 93 | 211, 52, 50, 189, 96, 107, 228, 122, 11, 68, 182, 28, 94 | ]; 95 | 96 | assert_eq!(generate(1, 0, 1).to_bytes(), proof); 97 | let mut mem = Imp::::new(&mut proof[4..], 4); 98 | assert_eq!(mem.root(), *array_ref![root, 0, 32]); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /composer/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod accounts; 2 | pub mod blob; 3 | pub mod proof; 4 | pub mod transactions; 5 | -------------------------------------------------------------------------------- /composer/src/proof/h256.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | use arrayref::array_ref; 3 | 4 | #[derive(Clone, Copy, Debug, PartialEq)] 5 | pub struct H256([u8; 32]); 6 | 7 | impl H256 { 8 | pub fn new(arr: &[u8; 32]) -> Self { 9 | H256(arr.clone()) 10 | } 11 | 12 | pub fn as_bytes(&self) -> &[u8; 32] { 13 | &self.0 14 | } 15 | } 16 | 17 | #[cfg(test)] 18 | pub fn zh(depth: usize) -> H256 { 19 | let mut buf = [0u8; 64]; 20 | sheth::hash::zh(depth, &mut buf); 21 | H256::new(array_ref![buf, 0, 32]) 22 | } 23 | -------------------------------------------------------------------------------- /composer/src/proof/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod h256; 2 | pub mod offsets; 3 | pub mod sort; 4 | pub mod uncompressed; 5 | -------------------------------------------------------------------------------- /composer/src/proof/offsets.rs: -------------------------------------------------------------------------------- 1 | use bigint::U512; 2 | 3 | /// Returns a vector of offsets that is read by an in-place lookup algorithm to determine the 4 | /// location of a particular 32 byte value in the multiproof. 5 | /// 6 | /// For more info, see: https://github.com/protolambda/eth-merkle-trees 7 | pub fn calculate(indexes: Vec) -> Vec { 8 | let mut raw_indexes = vec![]; 9 | 10 | // Convert indexes into arrays of bits 11 | for index in indexes.clone() { 12 | let mut bits = vec![0u8; 260]; 13 | for i in 0..260 { 14 | bits[260 - i - 1] = index.bit(i) as u8; 15 | } 16 | 17 | raw_indexes.push(bits); 18 | } 19 | 20 | // Translate everything to an end node (padding with 1s from the right) 21 | let raw_indexes = raw_indexes 22 | .iter() 23 | .map(|index| { 24 | let mut index = index.clone(); 25 | 26 | while index[0] == 0 { 27 | index.remove(0); 28 | index.push(1); 29 | } 30 | 31 | index 32 | }) 33 | .collect(); 34 | 35 | let mut ret: Vec = vec![indexes.len() as u64]; 36 | ret.extend(helper(raw_indexes)); 37 | ret 38 | } 39 | 40 | fn helper(indexes: Vec>) -> Vec { 41 | if indexes.len() <= 1 || indexes[0].len() == 0 { 42 | return vec![]; 43 | } 44 | 45 | let mut left_subtree: Vec> = vec![]; 46 | let mut right_subtree: Vec> = vec![]; 47 | 48 | for mut index in indexes { 49 | let bit = index.remove(0); 50 | 51 | if bit == 0 { 52 | left_subtree.push(index); 53 | } else { 54 | right_subtree.push(index); 55 | } 56 | } 57 | 58 | let left_subtree_size = left_subtree.len() as u64; 59 | let left_subtree_offsets = helper(left_subtree); 60 | let right_subtree_offsets = helper(right_subtree); 61 | 62 | let mut ret = if left_subtree_size == 0 { 63 | vec![] 64 | } else { 65 | vec![left_subtree_size] 66 | }; 67 | 68 | ret.extend(left_subtree_offsets); 69 | ret.extend(right_subtree_offsets); 70 | 71 | ret 72 | } 73 | 74 | #[cfg(test)] 75 | mod test { 76 | use super::*; 77 | 78 | #[test] 79 | fn offset_4_bit_left() { 80 | let indexes: Vec = vec![8.into(), 9.into(), 5.into(), 12.into(), 13.into(), 7.into()]; 81 | assert_eq!(calculate(indexes), vec![6, 3, 2, 1, 2, 1]); 82 | } 83 | 84 | #[test] 85 | fn offset_4_bit_right() { 86 | let indexes: Vec = vec![ 87 | 4.into(), 88 | 10.into(), 89 | 11.into(), 90 | 12.into(), 91 | 13.into(), 92 | 7.into(), 93 | ]; 94 | 95 | assert_eq!(calculate(indexes), vec![6, 3, 1, 1, 2, 1]); 96 | } 97 | 98 | #[test] 99 | fn offset_4_bit_full() { 100 | let indexes: Vec = vec![ 101 | 8.into(), 102 | 9.into(), 103 | 10.into(), 104 | 11.into(), 105 | 12.into(), 106 | 13.into(), 107 | 14.into(), 108 | 15.into(), 109 | ]; 110 | 111 | assert_eq!(calculate(indexes), vec![8, 4, 2, 1, 1, 2, 1, 1]); 112 | } 113 | 114 | #[test] 115 | fn offset_4_bit_left_small_branch() { 116 | let indexes: Vec = vec![4.into(), 10.into(), 11.into(), 3.into()]; 117 | assert_eq!(calculate(indexes), vec![4, 3, 1, 1]); 118 | } 119 | 120 | #[test] 121 | fn offset_4_bit_right_small_branch() { 122 | let indexes: Vec = vec![2.into(), 12.into(), 13.into(), 7.into()]; 123 | assert_eq!(calculate(indexes), vec![4, 1, 2, 1]); 124 | } 125 | 126 | #[test] 127 | fn offset_5_bit_right_small_branch() { 128 | let indexes: Vec = vec![16.into(), 17.into(), 9.into(), 5.into(), 3.into()]; 129 | assert_eq!(calculate(indexes), vec![5, 4, 3, 2, 1]); 130 | } 131 | 132 | #[test] 133 | fn offset_5_bit_left_branch() { 134 | let indexes: Vec = vec![ 135 | 16.into(), 136 | 17.into(), 137 | 9.into(), 138 | 10.into(), 139 | 11.into(), 140 | 3.into(), 141 | ]; 142 | 143 | assert_eq!(calculate(indexes), vec![6, 5, 3, 2, 1, 1]); 144 | } 145 | 146 | #[test] 147 | fn offset_5_bit_right_branch() { 148 | let indexes: Vec = vec![4.into(), 10.into(), 22.into(), 23.into(), 3.into()]; 149 | assert_eq!(calculate(indexes), vec![5, 4, 1, 1, 1]); 150 | } 151 | 152 | #[test] 153 | fn offset_5_bit_full() { 154 | let mut indexes: Vec = vec![]; 155 | 156 | for i in 16..32 { 157 | indexes.push(i.into()); 158 | } 159 | 160 | assert_eq!( 161 | calculate(indexes), 162 | vec![16, 8, 4, 2, 1, 1, 2, 1, 1, 4, 2, 1, 1, 2, 1, 1] 163 | ); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /composer/src/proof/sort.rs: -------------------------------------------------------------------------------- 1 | use bigint::U512; 2 | use std::ops::Shl; 3 | 4 | /// Sort a vector bit-alphabetically 5 | /// 6 | /// For more info, see: https://github.com/ethereum/eth2.0-specs/issues/1303 7 | pub fn alpha_sort(n: &Vec) -> Vec { 8 | let mut ret = n.clone(); 9 | 10 | ret.sort_by(|a, b| { 11 | let (a, a_shift, b, b_shift) = normalize(*a, *b); 12 | match a.cmp(&b) { 13 | std::cmp::Ordering::Less => std::cmp::Ordering::Less, 14 | std::cmp::Ordering::Greater => std::cmp::Ordering::Greater, 15 | std::cmp::Ordering::Equal => a_shift.cmp(&b_shift), 16 | } 17 | }); 18 | 19 | ret 20 | } 21 | 22 | fn normalize(a: U512, b: U512) -> (U512, usize, U512, usize) { 23 | // Normalize (e.g. right pad until the the most significant bit in `a` and `b` align) 24 | let max = std::cmp::max(a.bits(), b.bits()); 25 | 26 | let (a, a_shift) = if a.bits() < max { 27 | let shift = max - a.bits(); 28 | (a.shl(shift), shift) 29 | } else { 30 | (a, 0) 31 | }; 32 | 33 | let (b, b_shift) = if b.bits() < max { 34 | let shift = max - b.bits(); 35 | (b.shl(shift), shift) 36 | } else { 37 | (b, 0) 38 | }; 39 | 40 | (a, a_shift, b, b_shift) 41 | } 42 | 43 | #[cfg(test)] 44 | mod test { 45 | use super::*; 46 | 47 | #[test] 48 | fn normalize_numbers() { 49 | let one = U512::from(1); 50 | let two = U512::from(2); 51 | let big = U512::from(std::u64::MAX); 52 | 53 | assert_eq!(normalize(one, two), (two, 1, two, 0)); 54 | assert_eq!(normalize(big, one), (big, 0, U512::from(2u64.pow(63)), 63)); 55 | } 56 | 57 | #[test] 58 | fn alpha_sort_two_numbers() { 59 | assert_eq!( 60 | alpha_sort(&vec![3.into(), 2.into()]), 61 | vec![2.into(), 3.into()] 62 | ); 63 | } 64 | 65 | #[test] 66 | fn alphas_sort_branch() { 67 | let unsorted: Vec = vec![20, 21, 11, 4, 3] 68 | .into_iter() 69 | .fold(vec![], |mut acc, n| { 70 | acc.push(n.into()); 71 | acc 72 | }); 73 | 74 | let sorted: Vec = vec![4, 20, 21, 11, 3] 75 | .into_iter() 76 | .fold(vec![], |mut acc, n| { 77 | acc.push(n.into()); 78 | acc 79 | }); 80 | 81 | assert_eq!(alpha_sort(&unsorted), sorted); 82 | } 83 | 84 | #[ignore] // Current implementation only works on branches 85 | #[test] 86 | fn alpha_sort_many_numbers() { 87 | let unsorted: Vec = (1..4).fold(vec![], |mut acc, n| { 88 | acc.push(n.into()); 89 | acc 90 | }); 91 | 92 | let sorted: Vec = vec![ 93 | 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23, 1, 24, 12, 25, 6, 26, 13, 27, 3, 94 | 28, 14, 29, 7, 30, 15, 31, 95 | ] 96 | .into_iter() 97 | .fold(vec![], |mut acc, n| { 98 | acc.push(n.into()); 99 | acc 100 | }); 101 | 102 | assert_eq!(alpha_sort(&unsorted), sorted); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /composer/src/proof/uncompressed.rs: -------------------------------------------------------------------------------- 1 | use crate::accounts::AddressedAccount; 2 | use crate::proof::h256::H256; 3 | use crate::proof::sort::alpha_sort; 4 | use arrayref::array_ref; 5 | use bigint::U512; 6 | use sheth::hash::{hash, zh}; 7 | use std::collections::HashMap; 8 | 9 | #[derive(Debug, PartialEq)] 10 | pub struct UncompressedProof { 11 | pub indexes: Vec, 12 | pub values: Vec, 13 | } 14 | 15 | pub fn generate(accounts: Vec, height: usize) -> UncompressedProof { 16 | let mut map = init_multiproof(accounts, height); 17 | let indexes = fill_proof(&mut map, height); 18 | let indexes = alpha_sort(&indexes); 19 | 20 | UncompressedProof { 21 | indexes: indexes.clone(), 22 | values: indexes 23 | .iter() 24 | .map(|i| map.get(&i).unwrap().clone()) 25 | .collect(), 26 | } 27 | } 28 | 29 | pub fn init_multiproof(accounts: Vec, height: usize) -> HashMap { 30 | let mut map: HashMap = HashMap::new(); 31 | 32 | for account in accounts.into_iter() { 33 | let (address, account) = (account.0, account.1); 34 | 35 | // Calulate the root index of the account (e.g. `first_leaf` + address) 36 | let index = (U512::one() << height) + U512::from(address); 37 | 38 | // Copy the values of the account into a buffer 39 | let mut buf = [0u8; 128]; 40 | buf[0..48].copy_from_slice(&account.pubkey.as_bytes()); 41 | buf[64..72].copy_from_slice(&account.nonce.to_le_bytes()); 42 | buf[96..104].copy_from_slice(&account.value.to_le_bytes()); 43 | 44 | // Insert children nodes of the account, where structure looks like: 45 | map.insert(index << 3, H256::new(array_ref![buf, 0, 32])); 46 | map.insert((index << 3) + 1.into(), H256::new(array_ref![buf, 32, 32])); 47 | map.insert((index << 2) + 1.into(), H256::new(array_ref![buf, 64, 32])); 48 | map.insert((index << 2) + 2.into(), H256::new(array_ref![buf, 96, 32])); 49 | map.insert((index << 2) + 3.into(), H256::new(&[0u8; 32])); 50 | } 51 | 52 | map 53 | } 54 | 55 | fn fill_proof(map: &mut HashMap, height: usize) -> Vec { 56 | let mut indexes: Vec = map.keys().map(|x| x.to_owned()).collect(); 57 | indexes.sort(); 58 | indexes.reverse(); 59 | 60 | let mut proof_indexes: Vec = indexes.clone(); 61 | 62 | let mut position = 0; 63 | 64 | while indexes[position] > U512::from(1) { 65 | let left = indexes[position] & (!U512::zero() - U512::one()); 66 | let right = left + 1.into(); 67 | let parent = left / 2.into(); 68 | 69 | if !map.contains_key(&parent) { 70 | let left = get_or_generate( 71 | map, 72 | &mut proof_indexes, 73 | height, 74 | left, 75 | indexes[position].bits(), 76 | ); 77 | 78 | let right = get_or_generate( 79 | map, 80 | &mut proof_indexes, 81 | height, 82 | right, 83 | indexes[position].bits(), 84 | ); 85 | 86 | // Calculate hash 87 | let mut buf = [0u8; 64]; 88 | buf[0..32].copy_from_slice(left.as_bytes()); 89 | buf[32..64].copy_from_slice(right.as_bytes()); 90 | hash(&mut buf); 91 | 92 | // Insert hash to map 93 | map.insert(parent, H256::new(array_ref![buf, 0, 32])); 94 | 95 | // Push parent index to calculate next level 96 | indexes.push(parent); 97 | } 98 | 99 | indexes.sort(); 100 | indexes.reverse(); 101 | position += 1; 102 | } 103 | 104 | proof_indexes 105 | } 106 | 107 | fn get_or_generate( 108 | map: &mut HashMap, 109 | proof_indexes: &mut Vec, 110 | height: usize, 111 | index: U512, 112 | zero_bits: usize, 113 | ) -> H256 { 114 | match map.get(&index) { 115 | Some(x) => x.clone(), 116 | None => { 117 | let mut buf = [0u8; 64]; 118 | zh(height + 1 - zero_bits, &mut buf); 119 | let buf = H256::new(array_ref![buf, 0, 32]); 120 | proof_indexes.push(index); 121 | map.insert(index, buf.clone()); 122 | buf 123 | } 124 | } 125 | } 126 | 127 | #[cfg(test)] 128 | mod test { 129 | use super::*; 130 | use crate::proof::h256::zh; 131 | use sheth::account::Account; 132 | use sheth::bls::PublicKey; 133 | 134 | #[test] 135 | fn one_bit_tree() { 136 | // +---------- 1 ----------+ 137 | // / \ 138 | // +-- 2 --+ <= account 0 root 3 139 | // / \ 140 | // 4 5 141 | // / \ / \ 142 | // 8 9 10 11 143 | // / \ 144 | // 16 17 ^ ^ ^ 145 | // | | | 146 | // ^ ^ nonce value padding 147 | // | | 148 | // | | 149 | // | pk[32..48] 150 | // pk[0..32] 151 | 152 | let account = Account { 153 | pubkey: PublicKey::one(), 154 | nonce: 123, 155 | value: 42, 156 | }; 157 | 158 | let mut buf = [0u8; 128]; 159 | buf[0..48].copy_from_slice(&account.pubkey.as_bytes()); 160 | buf[64..72].copy_from_slice(&account.nonce.to_le_bytes()); 161 | buf[96..104].copy_from_slice(&account.value.to_le_bytes()); 162 | 163 | assert_eq!( 164 | generate(vec![AddressedAccount(0.into(), account.clone())], 1), 165 | UncompressedProof { 166 | indexes: vec![ 167 | 16.into(), 168 | 17.into(), 169 | 9.into(), 170 | 10.into(), 171 | 11.into(), 172 | 3.into() 173 | ], 174 | values: vec![ 175 | H256::new(array_ref![buf, 0, 32]), 176 | H256::new(array_ref![buf, 32, 32]), 177 | H256::new(array_ref![buf, 64, 32]), 178 | H256::new(array_ref![buf, 96, 32]), 179 | H256::new(&[0u8; 32]), 180 | zh(0), 181 | ] 182 | } 183 | ); 184 | 185 | assert_eq!( 186 | generate(vec![AddressedAccount(1.into(), account)], 1), 187 | UncompressedProof { 188 | indexes: vec![ 189 | 2.into(), 190 | 24.into(), 191 | 25.into(), 192 | 13.into(), 193 | 14.into(), 194 | 15.into() 195 | ], 196 | values: vec![ 197 | zh(0), 198 | H256::new(array_ref![buf, 0, 32]), 199 | H256::new(array_ref![buf, 32, 32]), 200 | H256::new(array_ref![buf, 64, 32]), 201 | H256::new(array_ref![buf, 96, 32]), 202 | H256::new(&[0u8; 32]), 203 | ] 204 | } 205 | ); 206 | } 207 | 208 | #[test] 209 | fn four_bit_tree_single_account() { 210 | // 211 | // +-------- 1 --------+ 212 | // / \ 213 | // +-- 2 --+ +-- 3 --+ 214 | // / \ / \ 215 | // 4 5 6 7 216 | // / \ / \ / \ / \ 217 | // 8 9 10 11 12 13 14 15 218 | // / \ / \ / \ / \ / \ / \ / \ / \ 219 | // 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 220 | // / \ 221 | // / \ 222 | // 50 51 223 | // / \ / \ 224 | // 100 101 102 103 225 | // / \ ^ ^ ^ 226 | // 200 201 | | | 227 | // ^ ^ | | padding 228 | // | | | value 229 | // | | nonce 230 | // | pk[32..48] 231 | // pk[0..32] 232 | 233 | let account = Account { 234 | pubkey: PublicKey::one(), 235 | nonce: 42, 236 | value: 123, 237 | }; 238 | 239 | let mut buf = [0u8; 128]; 240 | buf[0..48].copy_from_slice(&account.pubkey.as_bytes()); 241 | buf[64..72].copy_from_slice(&account.nonce.to_le_bytes()); 242 | buf[96..104].copy_from_slice(&account.value.to_le_bytes()); 243 | 244 | assert_eq!( 245 | generate(vec![AddressedAccount(9.into(), account.clone())], 4), 246 | UncompressedProof { 247 | indexes: vec![ 248 | 2.into(), 249 | 24.into(), 250 | 200.into(), 251 | 201.into(), 252 | 101.into(), 253 | 102.into(), 254 | 103.into(), 255 | 13.into(), 256 | 7.into(), 257 | ], 258 | values: vec![ 259 | zh(3), 260 | zh(0), 261 | H256::new(array_ref![buf, 0, 32]), 262 | H256::new(array_ref![buf, 32, 32]), 263 | H256::new(array_ref![buf, 64, 32]), 264 | H256::new(array_ref![buf, 96, 32]), 265 | H256::new(&[0u8; 32]), 266 | zh(1), 267 | zh(2), 268 | ] 269 | } 270 | ); 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /composer/src/transactions.rs: -------------------------------------------------------------------------------- 1 | use crate::accounts::AddressedAccount; 2 | use rand::{rngs::StdRng, Rng, SeedableRng}; 3 | use sheth::transaction::{Transaction, Transfer}; 4 | 5 | /// Generate `n` number of transactions between `accounts`. 6 | pub fn generate(n: usize, mut accounts: Vec) -> Vec { 7 | let mut rng = StdRng::seed_from_u64(42); 8 | 9 | let mut transactions: Vec = vec![]; 10 | 11 | for _ in 0..n { 12 | let to = rng.gen_range(0, accounts.len()); 13 | let from = rng.gen_range(0, accounts.len()); 14 | 15 | let tx = Transaction::Transfer(Transfer { 16 | to: accounts[to].0.into(), 17 | from: accounts[from].0.into(), 18 | nonce: accounts[from].1.nonce, 19 | amount: rng.gen_range(0, accounts[from].1.value), 20 | signature: [0u8; 96], 21 | }); 22 | 23 | match &tx { 24 | Transaction::Transfer(t) => { 25 | accounts[from].1.nonce += 1; 26 | accounts[from].1.value -= t.amount; 27 | accounts[to].1.value += t.amount; 28 | } 29 | _ => unreachable!(), 30 | } 31 | 32 | transactions.push(tx); 33 | } 34 | 35 | transactions 36 | } 37 | 38 | /// Convert an array of `Transaction` to an unaligned array of `u8`. 39 | pub fn serialize(transactions: &[Transaction]) -> Vec { 40 | let mut bytes = transactions.len().to_le_bytes()[0..4].to_vec(); 41 | 42 | for tx in transactions { 43 | match tx { 44 | Transaction::Transfer(tx) => { 45 | bytes.extend_from_slice(&<[u8; 32]>::from(tx.to)); 46 | bytes.extend_from_slice(&<[u8; 32]>::from(tx.from)); 47 | bytes.extend_from_slice(&tx.nonce.to_le_bytes()); 48 | bytes.extend_from_slice(&tx.amount.to_le_bytes()); 49 | bytes.extend_from_slice(&tx.signature); 50 | } 51 | _ => unimplemented!(), 52 | } 53 | } 54 | 55 | bytes 56 | } 57 | -------------------------------------------------------------------------------- /src/account.rs: -------------------------------------------------------------------------------- 1 | use crate::address::Address; 2 | use crate::bls::PublicKey; 3 | use crate::u264::U264; 4 | 5 | /// Account merkle tree schema: 6 | /// 7 | /// ```text 8 | /// root 9 | /// / \ 10 | /// pubkey other_root 11 | /// / \ 12 | /// nonce value 13 | /// ``` 14 | #[derive(Clone)] 15 | #[cfg_attr(feature = "std", derive(Hash))] 16 | pub struct Account { 17 | pub pubkey: PublicKey, 18 | pub nonce: u64, 19 | pub value: u64, 20 | } 21 | 22 | impl Account { 23 | pub fn zero() -> Self { 24 | Account { 25 | pubkey: PublicKey::zero(), 26 | nonce: 0, 27 | value: 0, 28 | } 29 | } 30 | } 31 | 32 | /// Given an address and tree height, calculate the `value`'s general index. 33 | /// 34 | /// ```text 35 | /// value_index = (first_leaf + account) * 4 + 2 36 | /// ``` 37 | #[inline] 38 | pub fn calc_value_index(address: Address, height: usize) -> U264 { 39 | ((((U264::one() << height) + address.into()) << 2) + 2.into()) << 1 40 | } 41 | 42 | /// Given an address and tree height, calculate the `nonce`'s general index. 43 | /// 44 | /// ```text 45 | /// nonce_index = (first_leaf + account) * 4 + 1 46 | /// ``` 47 | #[inline] 48 | pub fn calc_nonce_index(address: Address, height: usize) -> U264 { 49 | ((((U264::one() << height) + address.into()) << 2) + 1.into()) << 1 50 | } 51 | -------------------------------------------------------------------------------- /src/address.rs: -------------------------------------------------------------------------------- 1 | use crate::u264::U264; 2 | use bigint::{U256, U512}; 3 | 4 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 5 | pub struct Address(U256); 6 | 7 | impl Address { 8 | pub const fn new(n: U256) -> Address { 9 | Address(n) 10 | } 11 | } 12 | 13 | impl From for Address { 14 | fn from(n: usize) -> Address { 15 | Address(n.into()) 16 | } 17 | } 18 | 19 | impl From for Address { 20 | fn from(n: U256) -> Address { 21 | Address(n) 22 | } 23 | } 24 | 25 | impl From for Address { 26 | fn from(n: U512) -> Address { 27 | Address(n.into()) 28 | } 29 | } 30 | 31 | impl From<[u8; 32]> for Address { 32 | fn from(arr: [u8; 32]) -> Address { 33 | Address(arr.into()) 34 | } 35 | } 36 | 37 | impl From
for U264 { 38 | fn from(address: Address) -> U264 { 39 | U264::from(address.0) 40 | } 41 | } 42 | 43 | impl From
for [u8; 32] { 44 | fn from(a: Address) -> [u8; 32] { 45 | a.0.into() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/bls.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub struct PublicKey([u8; 48]); 3 | 4 | impl PublicKey { 5 | pub fn new(bytes: [u8; 48]) -> Self { 6 | PublicKey(bytes) 7 | } 8 | 9 | pub fn zero() -> Self { 10 | PublicKey([0u8; 48]) 11 | } 12 | 13 | pub fn one() -> Self { 14 | PublicKey([1u8; 48]) 15 | } 16 | 17 | pub fn as_bytes(&self) -> [u8; 48] { 18 | self.0 19 | } 20 | } 21 | 22 | #[cfg(feature = "std")] 23 | impl std::hash::Hash for PublicKey { 24 | fn hash(&self, state: &mut H) { 25 | std::hash::Hash::hash(&self.0[..], state) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use crate::u264::U264; 2 | 3 | #[derive(Debug, PartialEq)] 4 | pub enum Error { 5 | SignatureInvalid, 6 | NonceInvalid, 7 | BalanceInsufficient, 8 | StateIncomplete(U264), 9 | Overflow, 10 | } 11 | -------------------------------------------------------------------------------- /src/hash.rs: -------------------------------------------------------------------------------- 1 | use sha2::{Digest, Sha256}; 2 | 3 | pub type H256 = [u8; 32]; 4 | 5 | pub fn hash(buf: &mut [u8; 64]) { 6 | let mut tmp = [0u8; 32]; 7 | tmp.copy_from_slice(Sha256::digest(buf).as_ref()); 8 | buf[0..32].copy_from_slice(&tmp); 9 | } 10 | 11 | pub fn zh(mut depth: usize, buf: &mut [u8; 64]) { 12 | // Hash of an account with a balance of zero. 13 | let mut tmp = [ 14 | 218, 109, 128, 123, 247, 149, 16, 97, 70, 229, 130, 39, 117, 217, 20, 176, 39, 122, 101, 15 | 36, 15, 101, 14, 212, 200, 167, 202, 119, 130, 78, 90, 223, 16 | ]; 17 | 18 | buf[0..32].copy_from_slice(&tmp); 19 | buf[32..64].copy_from_slice(&tmp); 20 | 21 | while depth > 0 { 22 | tmp.copy_from_slice(&buf[0..32]); 23 | buf[32..64].copy_from_slice(&tmp); 24 | hash(buf); 25 | depth -= 1; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | extern crate alloc; 4 | extern crate qimalloc; 5 | 6 | pub mod account; 7 | pub mod address; 8 | pub mod bls; 9 | pub mod error; 10 | pub mod hash; 11 | pub mod process; 12 | pub mod state; 13 | pub mod transaction; 14 | pub mod u264; 15 | 16 | use crate::process::process_transactions; 17 | use crate::transaction::{Transaction, Transfer}; 18 | 19 | #[cfg(feature = "scout")] 20 | use alloc::vec::Vec; 21 | use arrayref::array_ref; 22 | use imp::Imp; 23 | 24 | // A global memory allocator is provided as part of the Rust standard library. When a crate is 25 | // compiled using `no_std` and dynamically allocates memory, it must specify an allocator it wishes 26 | // to use. `QIMalloc` is a "quick incremental memory allocator" that doesn't bother with 27 | // deallocating memory, since these runtimes are short-lived. 28 | #[cfg(not(feature = "std"))] 29 | #[global_allocator] 30 | static ALLOC: qimalloc::QIMalloc = qimalloc::QIMalloc::INIT; 31 | 32 | // This is a list of functions that `ewasm` environments support. They provide additional data and 33 | // functionality to execution environments. Each function is implemented in the host environment. 34 | #[cfg(feature = "scout")] 35 | mod native { 36 | extern "C" { 37 | pub fn eth2_loadPreStateRoot(offset: *const u32); 38 | pub fn eth2_blockDataSize() -> u32; 39 | pub fn eth2_blockDataCopy(outputOfset: *const u32, offset: u32, length: u32); 40 | pub fn eth2_savePostStateRoot(offset: *const u32); 41 | } 42 | } 43 | 44 | #[cfg(feature = "scout")] 45 | #[no_mangle] 46 | pub extern "C" fn main() { 47 | let input_size = unsafe { native::eth2_blockDataSize() as usize }; 48 | 49 | // Copy input into buffer (buffer fixed at 42kb for now) 50 | let mut input = [0u8; 42000]; 51 | unsafe { 52 | native::eth2_blockDataCopy(input.as_mut_ptr() as *const u32, 0, input_size as u32); 53 | } 54 | 55 | // Get pre-state-root 56 | let mut pre_state_root = [0u8; 32]; 57 | unsafe { native::eth2_loadPreStateRoot(pre_state_root.as_mut_ptr() as *const u32) } 58 | 59 | // Process input data 60 | let post_root = process_data_blob(&mut input, &pre_state_root); 61 | 62 | // Return post state 63 | unsafe { native::eth2_savePostStateRoot(post_root.as_ptr() as *const u32) } 64 | } 65 | 66 | pub fn process_data_blob(blob: &mut [u8], pre_state_root: &[u8; 32]) -> [u8; 32] { 67 | // Deserialize transactions from byte array. Although this is essentially copying all the 68 | // transactions, it appears to not have a massive cost. We can optimize later. 69 | let tx_count = u32::from_le_bytes(*array_ref!(blob, 0, 4)) as usize; 70 | let transactions = deserialize_transactions(&blob, tx_count); 71 | 72 | // Load multi-merkle proof 73 | let mut mem = Imp::new(&mut blob[(4 + tx_count * 176)..], 259); 74 | 75 | // Verify pre_state_root 76 | let pre_root = mem.root(); 77 | assert_eq!(pre_state_root, &pre_root); 78 | 79 | // Proccess all transactions (only transfers for now) 80 | assert_eq!(process_transactions(&mut mem, &transactions), Ok(())); 81 | 82 | mem.root() 83 | } 84 | 85 | pub fn deserialize_transactions(data: &[u8], tx_count: usize) -> Vec { 86 | unsafe { 87 | let mut ret = Vec::::new(); 88 | 89 | for i in (0..4 + (tx_count * 176)).skip(4).step_by(176) { 90 | let mut buf = [0u8; 176]; 91 | buf.copy_from_slice(&data[i..(i + 176)]); 92 | 93 | let tx = Transaction::Transfer(Transfer { 94 | to: (*array_ref![buf, 0, 32]).into(), 95 | from: (*array_ref![buf, 32, 32]).into(), 96 | nonce: u64::from_le_bytes(*array_ref![buf, 64, 8]), 97 | amount: u64::from_le_bytes(*array_ref![buf, 72, 8]), 98 | signature: *array_ref![buf, 80, 96], 99 | }); 100 | 101 | ret.push(tx); 102 | } 103 | 104 | ret 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use arrayref::array_ref; 2 | use sheth::process_data_blob; 3 | use std::fs; 4 | 5 | /// The `main` function is the entry point when `sheth` is compiled as an executable binary. 6 | /// Testing `sheth` in this manner is usually better than running through `Scout`, because your 7 | /// local system will print coherent stack traces where as the WebAssembly interpreter will just 8 | /// notify that a `Trap` has been detected. 9 | pub fn main() { 10 | let input = fs::read_to_string("blob").expect("File to exist"); 11 | 12 | let args: Vec<&str> = input.split_whitespace().collect(); 13 | let pre_state_root = hex::decode(args[0]).unwrap(); 14 | let post_state_root = hex::decode(args[1]).unwrap(); 15 | let mut input = hex::decode(args[2]).unwrap(); 16 | 17 | // Process input data 18 | let post_root = process_data_blob(&mut input, array_ref![pre_state_root, 0, 32]); 19 | 20 | assert_eq!(post_root, *array_ref![post_state_root, 0, 32]); 21 | 22 | println!("pre_state_root => {:?}", hex::encode(pre_state_root)); 23 | println!("post_state_root => {:?}", hex::encode(post_root)); 24 | } 25 | -------------------------------------------------------------------------------- /src/process.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Error; 2 | use crate::state::State; 3 | use crate::transaction::{Transaction, Transfer}; 4 | 5 | pub fn process_transactions<'a, T: State>( 6 | db: &mut T, 7 | transactions: &[Transaction], 8 | ) -> Result<(), Error> { 9 | for tx in transactions { 10 | if let Err(_) = tx.verify(db) { 11 | continue; 12 | } 13 | 14 | db.inc_nonce(tx.from())?; 15 | 16 | match tx { 17 | Transaction::Transfer(t) => transfer(db, t)?, 18 | Transaction::Deposit(_) => unimplemented!(), 19 | Transaction::Withdrawal(_) => unimplemented!(), 20 | } 21 | } 22 | 23 | Ok(()) 24 | } 25 | 26 | fn transfer<'a, T: State>(db: &mut T, tx: &Transfer) -> Result<(), Error> { 27 | db.sub_value(tx.from, tx.amount)?; 28 | db.add_value(tx.to, tx.amount)?; 29 | 30 | Ok(()) 31 | } 32 | 33 | #[cfg(feature = "std")] 34 | #[cfg(test)] 35 | mod test { 36 | use super::*; 37 | use crate::account::Account; 38 | use crate::address::Address; 39 | use crate::bls::PublicKey; 40 | use crate::state::MockState; 41 | use crate::transaction::{Transaction, Transfer}; 42 | use bigint::U256; 43 | use std::collections::BTreeMap; 44 | 45 | fn build_state() -> MockState { 46 | let mut accounts: BTreeMap = BTreeMap::new(); 47 | accounts.insert( 48 | 0.into(), 49 | Account { 50 | pubkey: PublicKey::zero(), 51 | nonce: 0, 52 | value: 5, 53 | }, 54 | ); 55 | accounts.insert( 56 | 1.into(), 57 | Account { 58 | pubkey: PublicKey::zero(), 59 | nonce: 0, 60 | value: 2, 61 | }, 62 | ); 63 | 64 | MockState::new(accounts) 65 | } 66 | 67 | #[test] 68 | fn two_accounts() { 69 | let transactions = vec![ 70 | Transaction::Transfer(Transfer { 71 | to: U256::from(1).into(), 72 | from: U256::from(0).into(), 73 | nonce: 0, 74 | amount: 2, 75 | signature: [0; 96], 76 | }), 77 | Transaction::Transfer(Transfer { 78 | to: U256::from(1).into(), 79 | from: U256::from(0).into(), 80 | nonce: 1, 81 | amount: 3, 82 | signature: [0; 96], 83 | }), 84 | Transaction::Transfer(Transfer { 85 | to: U256::from(0).into(), 86 | from: U256::from(1).into(), 87 | nonce: 0, 88 | amount: 5, 89 | signature: [0; 96], 90 | }), 91 | ]; 92 | 93 | let mut mem = build_state(); 94 | 95 | let pre_root = mem.root().unwrap(); 96 | assert_eq!(process_transactions(&mut mem, &transactions), Ok(())); 97 | let post_root = mem.root().unwrap(); 98 | 99 | assert_eq!( 100 | "000000000000000000000000000000000000000000000000babe8b8a8d142623", 101 | hex::encode(pre_root) 102 | ); 103 | 104 | assert_eq!( 105 | "0000000000000000000000000000000000000000000000003265323fcea3d6a2", 106 | hex::encode(post_root) 107 | ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/state/imp.rs: -------------------------------------------------------------------------------- 1 | use crate::account::{calc_nonce_index, calc_value_index}; 2 | use crate::address::Address; 3 | use crate::error::Error; 4 | use crate::state::State; 5 | use crate::u264::U264; 6 | use arrayref::array_ref; 7 | use imp::Imp; 8 | 9 | impl<'a> State for Imp<'a, U264> { 10 | fn root(&mut self) -> Result<[u8; 32], Error> { 11 | Ok(self.root()) 12 | } 13 | 14 | fn value(&self, address: Address) -> Result { 15 | let index = calc_value_index(address, self.height); 16 | let chunk = self.get(index); 17 | Ok(u64::from_le_bytes(*array_ref![&chunk, 0, 8])) 18 | } 19 | 20 | fn nonce(&self, address: Address) -> Result { 21 | let index = calc_nonce_index(address, self.height); 22 | let chunk = self.get(index); 23 | Ok(u64::from_le_bytes(*array_ref![&chunk, 0, 8])) 24 | } 25 | 26 | fn add_value(&mut self, address: Address, amount: u64) -> Result { 27 | let index = calc_value_index(address, self.height); 28 | let chunk = self.get(index); 29 | 30 | let value = u64::from_le_bytes(*array_ref![&chunk, 0, 8]); 31 | 32 | let (value, overflow) = value.overflowing_add(amount); 33 | if overflow { 34 | return Err(Error::Overflow); 35 | } 36 | 37 | let mut buf = [0u8; 32]; 38 | buf[0..8].copy_from_slice(&value.to_le_bytes()); 39 | self.update(index, buf); 40 | 41 | Ok(value) 42 | } 43 | 44 | fn sub_value(&mut self, address: Address, amount: u64) -> Result { 45 | let index = calc_value_index(address, self.height); 46 | let chunk = self.get(index); 47 | 48 | let value = u64::from_le_bytes(*array_ref![chunk, 0, 8]); 49 | 50 | let (value, overflow) = value.overflowing_sub(amount); 51 | if overflow { 52 | return Err(Error::Overflow); 53 | } 54 | 55 | let mut buf = [0u8; 32]; 56 | buf[0..8].copy_from_slice(&value.to_le_bytes()); 57 | self.update(index, buf); 58 | 59 | Ok(value) 60 | } 61 | 62 | fn inc_nonce(&mut self, address: Address) -> Result { 63 | let index = calc_nonce_index(address, self.height); 64 | let chunk = self.get(index); 65 | 66 | let nonce = u64::from_le_bytes(*array_ref![chunk, 0, 8]); 67 | 68 | let (nonce, overflow) = nonce.overflowing_add(1); 69 | if overflow { 70 | return Err(Error::Overflow); 71 | } 72 | 73 | let mut buf = [0u8; 32]; 74 | buf[0..8].copy_from_slice(&nonce.to_le_bytes()); 75 | self.update(index, buf); 76 | 77 | Ok(nonce) 78 | } 79 | } 80 | 81 | #[cfg(test)] 82 | mod test { 83 | use super::*; 84 | use crate::hash::H256; 85 | 86 | fn zh(depth: usize) -> H256 { 87 | let mut buf = [0u8; 64]; 88 | crate::hash::zh(depth, &mut buf); 89 | *array_ref![buf, 0, 32] 90 | } 91 | 92 | fn h256(n: u8) -> H256 { 93 | let mut ret = [0u8; 32]; 94 | ret[0] = n; 95 | ret 96 | } 97 | 98 | fn get_proof() -> Vec { 99 | // indexes = [16, 17, 9, 10, 11, 3] 100 | let offsets: Vec = vec![6, 5, 3, 2, 1, 1].iter().fold(vec![], |mut acc, x| { 101 | let x = *x as u64; 102 | acc.extend(&x.to_le_bytes()); 103 | acc 104 | }); 105 | 106 | let proof: Vec = vec![h256(0), h256(0), h256(1), h256(1), zh(0), zh(0)] 107 | .iter() 108 | .fold(vec![], |mut acc, x| { 109 | acc.extend(x); 110 | acc 111 | }); 112 | 113 | let mut ret = offsets; 114 | ret.extend(proof); 115 | 116 | ret 117 | } 118 | 119 | #[test] 120 | fn add_value() { 121 | let mut proof = get_proof(); 122 | let mut mem = Imp::new(&mut proof, 4); 123 | 124 | assert_eq!(mem.add_value(0.into(), 1), Ok(2)); 125 | assert_eq!(mem.get((10 << 1).into()), h256(2)); 126 | } 127 | 128 | #[test] 129 | fn sub_value() { 130 | let mut proof = get_proof(); 131 | let mut mem = Imp::new(&mut proof, 4); 132 | 133 | assert_eq!(mem.sub_value(0.into(), 1), Ok(0)); 134 | assert_eq!(mem.get((10 << 1).into()), h256(0)); 135 | } 136 | 137 | #[test] 138 | fn inc_nonce() { 139 | let mut proof = get_proof(); 140 | let mut mem = Imp::new(&mut proof, 4); 141 | 142 | assert_eq!(mem.inc_nonce(0.into()), Ok(2)); 143 | assert_eq!(mem.get((9 << 1).into()), h256(2)); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/state/mock.rs: -------------------------------------------------------------------------------- 1 | use crate::account::Account; 2 | use crate::address::Address; 3 | use crate::error::Error; 4 | use crate::hash::H256; 5 | use crate::state::State; 6 | use bigint::U256; 7 | use std::collections::hash_map::DefaultHasher; 8 | use std::collections::BTreeMap; 9 | use std::hash::{Hash, Hasher}; 10 | 11 | pub struct MockState { 12 | accounts: BTreeMap, 13 | } 14 | 15 | impl MockState { 16 | pub fn new(accounts: BTreeMap) -> MockState { 17 | MockState { accounts } 18 | } 19 | } 20 | 21 | impl State for MockState { 22 | fn root(&mut self) -> Result { 23 | let mut s = DefaultHasher::new(); 24 | self.accounts.hash(&mut s); 25 | let hash = U256::from(s.finish()); 26 | Ok(hash.into()) 27 | } 28 | 29 | fn value(&self, address: Address) -> Result { 30 | let value = self 31 | .accounts 32 | .get(&address) 33 | .ok_or(Error::StateIncomplete(address.into()))? 34 | .value; 35 | 36 | Ok(value) 37 | } 38 | 39 | fn nonce(&self, address: Address) -> Result { 40 | let nonce = self 41 | .accounts 42 | .get(&address) 43 | .ok_or(Error::StateIncomplete(address.into()))? 44 | .nonce; 45 | 46 | Ok(nonce) 47 | } 48 | 49 | fn add_value(&mut self, address: Address, amount: u64) -> Result { 50 | let mut account = self 51 | .accounts 52 | .get(&address) 53 | .ok_or(Error::StateIncomplete(address.into()))? 54 | .clone(); 55 | 56 | account.value += amount; 57 | self.accounts.insert(address, account.clone()); 58 | 59 | Ok(account.value) 60 | } 61 | 62 | fn sub_value(&mut self, address: Address, amount: u64) -> Result { 63 | let mut account = self 64 | .accounts 65 | .get(&address) 66 | .ok_or(Error::StateIncomplete(address.into()))? 67 | .clone(); 68 | 69 | account.value -= amount; 70 | self.accounts.insert(address, account.clone()); 71 | 72 | Ok(account.value) 73 | } 74 | 75 | fn inc_nonce(&mut self, address: Address) -> Result { 76 | let mut account = self 77 | .accounts 78 | .get(&address) 79 | .ok_or(Error::StateIncomplete(address.into()))? 80 | .clone(); 81 | 82 | account.nonce += 1; 83 | self.accounts.insert(address, account.clone()); 84 | 85 | Ok(account.nonce) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/state/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod imp; 2 | 3 | #[cfg(test)] 4 | pub mod mock; 5 | 6 | #[cfg(test)] 7 | pub use mock::MockState; 8 | 9 | use crate::address::Address; 10 | use crate::error::Error; 11 | use crate::hash::H256; 12 | 13 | /// Interface for interacting with the state's Sparse Merkle Tree (SMT). 14 | /// 15 | /// The SMT can be modeled as a `FixedVector[Account, 2**256]`. It's merkle tree structure is as 16 | /// follows: 17 | /// 18 | /// ```text 19 | /// root 20 | /// / \ 21 | /// ... ... <= intermediate nodes 22 | /// / \ / \ 23 | /// 0 1 n n+1 <= account roots 24 | /// ``` 25 | pub trait State { 26 | /// Calculates the root before making changes to the structure and after in one pass. 27 | fn root(&mut self) -> Result; 28 | 29 | /// Returns the value of a specified address. 30 | fn value(&self, address: Address) -> Result; 31 | 32 | /// Returns the nonce of a specified address. 33 | fn nonce(&self, address: Address) -> Result; 34 | 35 | /// Increase the value of an account at `address`. 36 | fn add_value(&mut self, address: Address, amount: u64) -> Result; 37 | 38 | /// Decrease the value of an account at `address`. 39 | fn sub_value(&mut self, address: Address, amount: u64) -> Result; 40 | 41 | /// Increment the `nonce` of the account at `address` by `1`. 42 | fn inc_nonce(&mut self, address: Address) -> Result; 43 | } 44 | -------------------------------------------------------------------------------- /src/transaction.rs: -------------------------------------------------------------------------------- 1 | use crate::address::Address; 2 | use crate::error::Error; 3 | use crate::state::State; 4 | 5 | #[cfg_attr(feature = "std", derive(Clone, Debug))] 6 | pub enum Transaction { 7 | Transfer(Transfer), 8 | Withdrawal(Transfer), 9 | Deposit(Deposit), 10 | } 11 | 12 | impl Transaction { 13 | pub fn from(&self) -> Address { 14 | match self { 15 | Transaction::Transfer(t) => t.from, 16 | Transaction::Withdrawal(_) => unimplemented!(), 17 | Transaction::Deposit(_) => unimplemented!(), 18 | } 19 | } 20 | 21 | pub fn nonce(&self) -> u64 { 22 | match self { 23 | Transaction::Transfer(t) => t.nonce, 24 | Transaction::Withdrawal(_) => unimplemented!(), 25 | Transaction::Deposit(_) => unimplemented!(), 26 | } 27 | } 28 | 29 | pub fn verify<'a, T: State>(&self, db: &T) -> Result<(), Error> { 30 | self.verify_signature(db)?; 31 | self.verify_nonce(db)?; 32 | 33 | Ok(()) 34 | } 35 | 36 | pub fn verify_signature<'a, T: State>(&self, _db: &T) -> Result<(), Error> { 37 | // TODO: Implement BLS verification 38 | Ok(()) 39 | } 40 | 41 | pub fn verify_nonce<'a, T: State>(&self, db: &T) -> Result<(), Error> { 42 | let nonce = db.nonce(self.from())?; 43 | 44 | if nonce == self.nonce() { 45 | Ok(()) 46 | } else { 47 | Err(Error::NonceInvalid) 48 | } 49 | } 50 | } 51 | 52 | #[cfg_attr(feature = "std", derive(Clone))] 53 | pub struct Transfer { 54 | pub to: Address, 55 | pub from: Address, 56 | pub nonce: u64, 57 | pub amount: u64, 58 | pub signature: [u8; 96], 59 | } 60 | 61 | #[cfg(feature = "std")] 62 | impl std::fmt::Debug for Transfer { 63 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 64 | write!( 65 | f, 66 | "{{\n\tto: {:?},\n\tfrom: {:?},\n\tnonce: {},\n\tamount: {},\n\t, signature: {:?}\n}}", 67 | self.to, 68 | self.from, 69 | self.nonce, 70 | self.amount, 71 | self.signature.to_vec() 72 | ) 73 | } 74 | } 75 | 76 | #[cfg_attr(feature = "std", derive(Clone, Debug))] 77 | pub struct Withdrawal; 78 | 79 | #[cfg_attr(feature = "std", derive(Clone, Debug))] 80 | pub struct Deposit; 81 | 82 | #[cfg(test)] 83 | mod test { 84 | use super::*; 85 | use crate::account::Account; 86 | use crate::address::Address; 87 | use crate::bls::PublicKey; 88 | use crate::state::MockState; 89 | use std::collections::BTreeMap; 90 | 91 | fn build_transfer() -> Transaction { 92 | Transaction::Transfer(Transfer { 93 | to: 0.into(), 94 | from: 1.into(), 95 | nonce: 3, 96 | amount: 4, 97 | signature: [0u8; 96], 98 | }) 99 | } 100 | 101 | #[test] 102 | fn general_from() { 103 | let transfer = build_transfer(); 104 | assert_eq!(transfer.from(), 1.into()); 105 | } 106 | 107 | #[test] 108 | fn general_nonce() { 109 | let transfer = build_transfer(); 110 | assert_eq!(transfer.nonce(), 3); 111 | } 112 | 113 | #[test] 114 | fn verify_nonce() { 115 | let transfer = build_transfer(); 116 | let mut accounts: BTreeMap = BTreeMap::new(); 117 | 118 | accounts.insert(1.into(), Account::zero()); 119 | let mem = MockState::new(accounts.clone()); 120 | assert_eq!(transfer.verify_nonce(&mem), Err(Error::NonceInvalid)); 121 | 122 | accounts.insert( 123 | 1.into(), 124 | Account { 125 | pubkey: PublicKey::zero(), 126 | nonce: 3, 127 | value: 0, 128 | }, 129 | ); 130 | let mem = MockState::new(accounts); 131 | assert_eq!(transfer.verify_nonce(&mem), Ok(())); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/u264.rs: -------------------------------------------------------------------------------- 1 | use arrayref::array_refs; 2 | use bigint::U256; 3 | 4 | #[cfg(feature = "std")] 5 | use std::cmp::{Eq, Ordering}; 6 | #[cfg(feature = "std")] 7 | use std::fmt; 8 | #[cfg(feature = "std")] 9 | use std::hash::{Hash, Hasher}; 10 | #[cfg(feature = "std")] 11 | use std::ops::{Add, BitAnd, Not, Shl, Shr, Sub}; 12 | 13 | #[cfg(not(feature = "std"))] 14 | use core::cmp::{Eq, Ordering}; 15 | #[cfg(not(feature = "std"))] 16 | use core::fmt; 17 | #[cfg(not(feature = "std"))] 18 | use core::hash::{Hash, Hasher}; 19 | #[cfg(not(feature = "std"))] 20 | use core::ops::{Add, BitAnd, Not, Shl, Shr, Sub}; 21 | 22 | #[repr(C)] 23 | #[derive(Copy, Clone)] 24 | pub struct U264([u8; 33]); 25 | 26 | impl U264 { 27 | pub fn zero() -> Self { 28 | Self([0; 33]) 29 | } 30 | 31 | pub fn one() -> Self { 32 | Self([ 33 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34 | 0, 0, 0, 0, 35 | ]) 36 | } 37 | 38 | pub fn overflowing_add(self, other: Self) -> (Self, bool) { 39 | let Self(ref me) = self; 40 | let Self(ref you) = other; 41 | 42 | let mut ret = [0u8; 33]; 43 | let mut carry; 44 | 45 | // TODO: Write macro to unroll all this: 46 | 47 | let (me_1, me_2, me_3, me_4, me_5) = array_refs!(me, 8, 8, 8, 8, 1); 48 | let (you_1, you_2, you_3, you_4, you_5) = array_refs!(you, 8, 8, 8, 8, 1); 49 | 50 | // Convert from le bytes to unsigned integers 51 | let me_1 = u64::from_le_bytes(*me_1); 52 | let me_2 = u64::from_le_bytes(*me_2); 53 | let me_3 = u64::from_le_bytes(*me_3); 54 | let me_4 = u64::from_le_bytes(*me_4); 55 | let me_5 = u8::from_le_bytes(*me_5); 56 | 57 | let you_1 = u64::from_le_bytes(*you_1); 58 | let you_2 = u64::from_le_bytes(*you_2); 59 | let you_3 = u64::from_le_bytes(*you_3); 60 | let you_4 = u64::from_le_bytes(*you_4); 61 | let you_5 = u8::from_le_bytes(*you_5); 62 | 63 | // Self[0..8] 64 | let (v, o1) = me_1.overflowing_add(you_1); 65 | ret[0..8].copy_from_slice(&v.to_le_bytes()); 66 | carry = o1; 67 | 68 | // Self[8..16] 69 | let (v, o1) = me_2.overflowing_add(you_2); 70 | let (v, o2) = v.overflowing_add(if carry { 1 } else { 0 }); 71 | ret[8..16].copy_from_slice(&v.to_le_bytes()); 72 | carry = o1 || o2; 73 | 74 | // Self[16..24] 75 | let (v, o1) = me_3.overflowing_add(you_3); 76 | let (v, o2) = v.overflowing_add(if carry { 1 } else { 0 }); 77 | ret[16..24].copy_from_slice(&v.to_le_bytes()); 78 | carry = o1 || o2; 79 | 80 | // Self[24..32] 81 | let (v, o1) = me_4.overflowing_add(you_4); 82 | let (v, o2) = v.overflowing_add(if carry { 1 } else { 0 }); 83 | ret[24..32].copy_from_slice(&v.to_le_bytes()); 84 | carry = o1 || o2; 85 | 86 | // Self[33] 87 | let (v, o1) = me_5.overflowing_add(you_5); 88 | let (v, o2) = v.overflowing_add(if carry { 1 } else { 0 }); 89 | ret[32] = v; 90 | carry = o1 || o2; 91 | 92 | (U264(ret), carry) 93 | } 94 | 95 | pub fn overflowing_sub(self, other: Self) -> (Self, bool) { 96 | let Self(ref me) = self; 97 | let Self(ref you) = other; 98 | 99 | let mut ret = [0u8; 33]; 100 | let mut carry; 101 | 102 | // TODO: Write macro to unroll all this: 103 | 104 | let (me_1, me_2, me_3, me_4, me_5) = array_refs!(me, 8, 8, 8, 8, 1); 105 | let (you_1, you_2, you_3, you_4, you_5) = array_refs!(you, 8, 8, 8, 8, 1); 106 | 107 | // Convert from le bytes to unsigned integers 108 | let me_1 = u64::from_le_bytes(*me_1); 109 | let me_2 = u64::from_le_bytes(*me_2); 110 | let me_3 = u64::from_le_bytes(*me_3); 111 | let me_4 = u64::from_le_bytes(*me_4); 112 | let me_5 = u8::from_le_bytes(*me_5); 113 | 114 | let you_1 = u64::from_le_bytes(*you_1); 115 | let you_2 = u64::from_le_bytes(*you_2); 116 | let you_3 = u64::from_le_bytes(*you_3); 117 | let you_4 = u64::from_le_bytes(*you_4); 118 | let you_5 = u8::from_le_bytes(*you_5); 119 | 120 | // Self[0..8] 121 | let (v, o1) = me_1.overflowing_sub(you_1); 122 | ret[0..8].copy_from_slice(&v.to_le_bytes()); 123 | carry = o1; 124 | 125 | // Self[8..16] 126 | let (v, o1) = me_2.overflowing_sub(you_2); 127 | let (v, o2) = v.overflowing_sub(if carry { 1 } else { 0 }); 128 | ret[8..16].copy_from_slice(&v.to_le_bytes()); 129 | carry = o1 || o2; 130 | 131 | // Self[16..24] 132 | let (v, o1) = me_3.overflowing_sub(you_3); 133 | let (v, o2) = v.overflowing_sub(if carry { 1 } else { 0 }); 134 | ret[16..24].copy_from_slice(&v.to_le_bytes()); 135 | carry = o1 || o2; 136 | 137 | // Self[24..32] 138 | let (v, o1) = me_4.overflowing_sub(you_4); 139 | let (v, o2) = v.overflowing_sub(if carry { 1 } else { 0 }); 140 | ret[24..32].copy_from_slice(&v.to_le_bytes()); 141 | carry = o1 || o2; 142 | 143 | // Self[33] 144 | let (v, o1) = me_5.overflowing_sub(you_5); 145 | let (v, o2) = v.overflowing_sub(if carry { 1 } else { 0 }); 146 | ret[32] = v; 147 | carry = o1 || o2; 148 | 149 | (U264(ret), carry) 150 | } 151 | 152 | pub fn low_u32(&self) -> u32 { 153 | let &Self(ref arr) = self; 154 | let (arr, _) = array_refs!(arr, 4, 29); 155 | u32::from_le_bytes(*arr) 156 | } 157 | 158 | pub fn as_le_bytes(&self) -> &[u8; 33] { 159 | let &U264(ref me) = self; 160 | me 161 | } 162 | } 163 | 164 | impl Add for U264 { 165 | type Output = U264; 166 | 167 | fn add(self, other: U264) -> U264 { 168 | let (o, v) = self.overflowing_add(other); 169 | assert!(v == false); 170 | o 171 | } 172 | } 173 | 174 | impl Sub for U264 { 175 | type Output = U264; 176 | 177 | fn sub(self, other: U264) -> U264 { 178 | let (o, v) = self.overflowing_sub(other); 179 | assert!(v == false); 180 | o 181 | } 182 | } 183 | 184 | impl Shr for U264 { 185 | type Output = U264; 186 | 187 | fn shr(self, shift: usize) -> U264 { 188 | let U264(ref original) = self; 189 | let mut ret = [0u8; 33]; 190 | 191 | let word_shift = shift / 8; 192 | let bit_shift = shift % 8; 193 | 194 | for i in word_shift..33 { 195 | // Shift 196 | ret[i - word_shift] += original[i] >> bit_shift; 197 | // Carry 198 | if bit_shift > 0 && i < 33 - 1 { 199 | ret[i - word_shift] += original[i + 1] << (8 - bit_shift); 200 | } 201 | } 202 | 203 | U264(ret) 204 | } 205 | } 206 | 207 | impl Shl for U264 { 208 | type Output = U264; 209 | 210 | fn shl(self, shift: usize) -> U264 { 211 | let U264(ref original) = self; 212 | let mut ret = [0u8; 33]; 213 | 214 | let word_shift = shift / 8; 215 | let bit_shift = shift % 8; 216 | 217 | for i in 0..33 { 218 | // Shift 219 | if bit_shift < 8 && i + word_shift < 33 { 220 | ret[i + word_shift] += original[i] << bit_shift; 221 | } 222 | // Carry 223 | if bit_shift > 0 && i + word_shift + 1 < 33 { 224 | ret[i + word_shift + 1] += original[i] >> (8 - bit_shift); 225 | } 226 | } 227 | 228 | U264(ret) 229 | } 230 | } 231 | 232 | impl BitAnd for U264 { 233 | type Output = Self; 234 | 235 | fn bitand(self, rhs: Self) -> Self::Output { 236 | let Self(ref me) = self; 237 | let Self(ref you) = rhs; 238 | 239 | let (me_1, me_2, me_3, me_4, me_5) = array_refs!(me, 8, 8, 8, 8, 1); 240 | let (you_1, you_2, you_3, you_4, you_5) = array_refs!(you, 8, 8, 8, 8, 1); 241 | 242 | let mut ret = [0u8; 33]; 243 | ret[0..8].copy_from_slice( 244 | &(u64::from_le_bytes(*me_1) & u64::from_le_bytes(*you_1)).to_le_bytes(), 245 | ); 246 | ret[8..16].copy_from_slice( 247 | &(u64::from_le_bytes(*me_2) & u64::from_le_bytes(*you_2)).to_le_bytes(), 248 | ); 249 | ret[16..24].copy_from_slice( 250 | &(u64::from_le_bytes(*me_3) & u64::from_le_bytes(*you_3)).to_le_bytes(), 251 | ); 252 | ret[24..32].copy_from_slice( 253 | &(u64::from_le_bytes(*me_4) & u64::from_le_bytes(*you_4)).to_le_bytes(), 254 | ); 255 | ret[32..33] 256 | .copy_from_slice(&(u8::from_le_bytes(*me_5) & u8::from_le_bytes(*you_5)).to_le_bytes()); 257 | 258 | ret.into() 259 | } 260 | } 261 | 262 | impl Not for U264 { 263 | type Output = Self; 264 | 265 | fn not(self) -> Self::Output { 266 | let Self(ref me) = self; 267 | 268 | let (me_1, me_2, me_3, me_4, me_5) = array_refs!(me, 8, 8, 8, 8, 1); 269 | 270 | let mut ret = [0u8; 33]; 271 | ret[0..8].copy_from_slice(&(!u64::from_le_bytes(*me_1)).to_le_bytes()); 272 | ret[8..16].copy_from_slice(&(!u64::from_le_bytes(*me_2)).to_le_bytes()); 273 | ret[16..24].copy_from_slice(&(!u64::from_le_bytes(*me_3)).to_le_bytes()); 274 | ret[24..32].copy_from_slice(&(!u64::from_le_bytes(*me_4)).to_le_bytes()); 275 | ret[32..33].copy_from_slice(&(!u8::from_le_bytes(*me_5)).to_le_bytes()); 276 | 277 | ret.into() 278 | } 279 | } 280 | 281 | impl Eq for U264 {} 282 | 283 | impl PartialEq for U264 { 284 | fn eq(&self, other: &U264) -> bool { 285 | let U264(ref me) = self; 286 | let U264(ref you) = other; 287 | 288 | // TODO: Write macro to unroll all this: 289 | 290 | let (me_1, me_2, me_3, me_4, me_5) = array_refs!(me, 8, 8, 8, 8, 1); 291 | let (you_1, you_2, you_3, you_4, you_5) = array_refs!(you, 8, 8, 8, 8, 1); 292 | 293 | // Convert from le bytes to unsigned integers 294 | let me_1 = u64::from_le_bytes(*me_1); 295 | let me_2 = u64::from_le_bytes(*me_2); 296 | let me_3 = u64::from_le_bytes(*me_3); 297 | let me_4 = u64::from_le_bytes(*me_4); 298 | let me_5 = u8::from_le_bytes(*me_5); 299 | let you_1 = u64::from_le_bytes(*you_1); 300 | let you_2 = u64::from_le_bytes(*you_2); 301 | let you_3 = u64::from_le_bytes(*you_3); 302 | let you_4 = u64::from_le_bytes(*you_4); 303 | let you_5 = u8::from_le_bytes(*you_5); 304 | 305 | // These comparisions need to be in this otherwise would produce incorrect results 306 | 307 | if me_1 < you_1 { 308 | return false; 309 | } 310 | 311 | if me_1 > you_1 { 312 | return false; 313 | } 314 | 315 | if me_2 < you_2 { 316 | return false; 317 | } 318 | 319 | if me_2 > you_2 { 320 | return false; 321 | } 322 | 323 | if me_3 < you_3 { 324 | return false; 325 | } 326 | 327 | if me_3 > you_3 { 328 | return false; 329 | } 330 | 331 | if me_4 < you_4 { 332 | return false; 333 | } 334 | 335 | if me_4 > you_4 { 336 | return false; 337 | } 338 | 339 | if me_5 < you_5 { 340 | return false; 341 | } 342 | 343 | if me_5 > you_5 { 344 | return false; 345 | } 346 | 347 | true 348 | } 349 | } 350 | 351 | impl PartialOrd for U264 { 352 | fn partial_cmp(&self, other: &U264) -> Option { 353 | let Self(ref me) = self; 354 | let Self(ref you) = other; 355 | 356 | Some(me.cmp(you)) 357 | } 358 | } 359 | 360 | impl Ord for U264 { 361 | fn cmp(&self, other: &Self) -> Ordering { 362 | let Self(ref me) = self; 363 | let Self(ref you) = other; 364 | me.cmp(you) 365 | } 366 | } 367 | 368 | impl Hash for U264 { 369 | fn hash(&self, state: &mut H) { 370 | let Self(ref me) = self; 371 | me.hash(state); 372 | } 373 | } 374 | 375 | // Chops off most significant byte 376 | impl From for U264 { 377 | fn from(n: U256) -> U264 { 378 | let mut buf = [0u8; 33]; 379 | n.to_little_endian(&mut buf[0..32]); 380 | U264::from(buf) 381 | } 382 | } 383 | 384 | impl From for U264 { 385 | fn from(n: u8) -> U264 { 386 | U264([ 387 | n, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 388 | 0, 0, 0, 0, 389 | ]) 390 | } 391 | } 392 | 393 | impl From<[u8; 33]> for U264 { 394 | fn from(arr: [u8; 33]) -> U264 { 395 | U264(arr) 396 | } 397 | } 398 | 399 | impl From for [u8; 33] { 400 | fn from(n: U264) -> [u8; 33] { 401 | n.0 402 | } 403 | } 404 | 405 | impl fmt::Debug for U264 { 406 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 407 | write!(f, "{:?}", &self.0[..]) 408 | } 409 | } 410 | 411 | #[cfg(test)] 412 | mod tests { 413 | use super::*; 414 | 415 | #[test] 416 | fn add() { 417 | let x = U264::zero(); 418 | let y = U264::one(); 419 | assert_eq!(x + y, U264::one()); 420 | } 421 | 422 | #[test] 423 | fn overflowing_add() { 424 | let x = U264::one(); 425 | let y = U264([ 426 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 427 | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 428 | ]); 429 | assert_eq!(x.overflowing_add(U264::zero()), (x, false)); 430 | assert_eq!(x.overflowing_add(y), (U264::zero(), true)); 431 | } 432 | 433 | #[test] 434 | fn shift_right_zero() { 435 | let x = U264::zero(); 436 | let y = x.shr(10); 437 | assert_eq!(x, y); 438 | } 439 | 440 | #[test] 441 | fn shift_right() { 442 | let x = U264::one(); 443 | assert_eq!(x.shr(1), U264::zero()); 444 | } 445 | 446 | #[test] 447 | fn shift_left_zero() { 448 | let x = U264::zero(); 449 | let y = x.shl(10); 450 | assert_eq!(x, y); 451 | } 452 | 453 | #[test] 454 | fn shift_left() { 455 | let x = U264::one(); 456 | assert_eq!(x.shl(1), U264::from(2)); 457 | } 458 | 459 | } 460 | --------------------------------------------------------------------------------