├── .dockerignore ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs └── src ├── abi.rs ├── keyman.rs ├── lib.rs ├── main.rs ├── printer.rs ├── program.rs └── testcall.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | Jenkinsfile 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .vscode 3 | .idea/ 4 | 5 | tests/Wallet2.code 6 | tests/Wallet2.map.json 7 | *.tvc 8 | *.tmp 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## Version: 0.17.0 6 | 7 | ### New 8 | - Added functionality to work with private function ids. 9 | 10 | ### Breaking changes 11 | - Changed `test` command option `--abi-header` short version from `-h` to `-d` for not to match with help. 12 | 13 | ## Version: 0.15.71 14 | 15 | ### New 16 | - Added option for `compile` command to print code cell and not generate TVC file. 17 | 18 | ## Version: 0.15.45 19 | 20 | ### Breaking changes 21 | - Removed deprecated `init` command. `ever-cli genaddr` command should be used instead. 22 | - Removed `genkey`, `setkey` and `ctor-params` options for `compile` command. `ever-cli genaddr` command should be used instead. 23 | 24 | ## Version: 0.15.44 25 | 26 | ### New 27 | - Added support for ABI 2.3 28 | 29 | ## Version: 0.15.0 30 | 31 | ### New 32 | - fix builder 33 | - Automatic project update 34 | - Auto update patch version 35 | - Update CHANGELOG.md 36 | 37 | 38 | ## Version: 0.14.52 39 | 40 | ### New 41 | 42 | 43 | ## Version: 0.14.51 44 | 45 | ### New 46 | 47 | 48 | ## Version: 0.14.45 49 | 50 | ### New 51 | 52 | 53 | ## Version: 0.14.43 54 | 55 | ### New 56 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aes-ctr" 7 | version = "0.6.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "7729c3cde54d67063be556aeac75a81330d802f0259500ca40cb52967f975763" 10 | dependencies = [ 11 | "aes-soft", 12 | "aesni", 13 | "cipher", 14 | "ctr", 15 | ] 16 | 17 | [[package]] 18 | name = "aes-soft" 19 | version = "0.6.4" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" 22 | dependencies = [ 23 | "cipher", 24 | "opaque-debug", 25 | ] 26 | 27 | [[package]] 28 | name = "aesni" 29 | version = "0.10.0" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" 32 | dependencies = [ 33 | "cipher", 34 | "opaque-debug", 35 | ] 36 | 37 | [[package]] 38 | name = "aho-corasick" 39 | version = "1.1.3" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 42 | dependencies = [ 43 | "memchr", 44 | ] 45 | 46 | [[package]] 47 | name = "android-tzdata" 48 | version = "0.1.1" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 51 | 52 | [[package]] 53 | name = "android_system_properties" 54 | version = "0.1.5" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 57 | dependencies = [ 58 | "libc", 59 | ] 60 | 61 | [[package]] 62 | name = "ansi_term" 63 | version = "0.12.1" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 66 | dependencies = [ 67 | "winapi", 68 | ] 69 | 70 | [[package]] 71 | name = "anstream" 72 | version = "0.6.15" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" 75 | dependencies = [ 76 | "anstyle", 77 | "anstyle-parse", 78 | "anstyle-query", 79 | "anstyle-wincon", 80 | "colorchoice", 81 | "is_terminal_polyfill", 82 | "utf8parse", 83 | ] 84 | 85 | [[package]] 86 | name = "anstyle" 87 | version = "1.0.8" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" 90 | 91 | [[package]] 92 | name = "anstyle-parse" 93 | version = "0.2.5" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" 96 | dependencies = [ 97 | "utf8parse", 98 | ] 99 | 100 | [[package]] 101 | name = "anstyle-query" 102 | version = "1.1.1" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" 105 | dependencies = [ 106 | "windows-sys", 107 | ] 108 | 109 | [[package]] 110 | name = "anstyle-wincon" 111 | version = "3.0.4" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" 114 | dependencies = [ 115 | "anstyle", 116 | "windows-sys", 117 | ] 118 | 119 | [[package]] 120 | name = "anyhow" 121 | version = "1.0.86" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" 124 | 125 | [[package]] 126 | name = "arrayref" 127 | version = "0.3.8" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" 130 | 131 | [[package]] 132 | name = "arrayvec" 133 | version = "0.5.2" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 136 | 137 | [[package]] 138 | name = "assert_cmd" 139 | version = "2.0.16" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" 142 | dependencies = [ 143 | "anstyle", 144 | "bstr", 145 | "doc-comment", 146 | "libc", 147 | "predicates", 148 | "predicates-core", 149 | "predicates-tree", 150 | "wait-timeout", 151 | ] 152 | 153 | [[package]] 154 | name = "atty" 155 | version = "0.2.14" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 158 | dependencies = [ 159 | "hermit-abi 0.1.19", 160 | "libc", 161 | "winapi", 162 | ] 163 | 164 | [[package]] 165 | name = "autocfg" 166 | version = "1.3.0" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 169 | 170 | [[package]] 171 | name = "base64" 172 | version = "0.13.1" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 175 | 176 | [[package]] 177 | name = "base64ct" 178 | version = "1.6.0" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 181 | 182 | [[package]] 183 | name = "bitflags" 184 | version = "1.3.2" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 187 | 188 | [[package]] 189 | name = "blake2b_simd" 190 | version = "0.5.11" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" 193 | dependencies = [ 194 | "arrayref", 195 | "arrayvec", 196 | "constant_time_eq", 197 | ] 198 | 199 | [[package]] 200 | name = "block-buffer" 201 | version = "0.10.4" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 204 | dependencies = [ 205 | "generic-array", 206 | ] 207 | 208 | [[package]] 209 | name = "blst" 210 | version = "0.3.13" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" 213 | dependencies = [ 214 | "cc", 215 | "glob", 216 | "threadpool", 217 | "zeroize", 218 | ] 219 | 220 | [[package]] 221 | name = "bstr" 222 | version = "1.10.0" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" 225 | dependencies = [ 226 | "memchr", 227 | "regex-automata", 228 | "serde", 229 | ] 230 | 231 | [[package]] 232 | name = "bumpalo" 233 | version = "3.16.0" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 236 | 237 | [[package]] 238 | name = "byteorder" 239 | version = "1.5.0" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 242 | 243 | [[package]] 244 | name = "cc" 245 | version = "1.1.12" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "68064e60dbf1f17005c2fde4d07c16d8baa506fd7ffed8ccab702d93617975c7" 248 | dependencies = [ 249 | "jobserver", 250 | "libc", 251 | "shlex", 252 | ] 253 | 254 | [[package]] 255 | name = "cfg-if" 256 | version = "1.0.0" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 259 | 260 | [[package]] 261 | name = "chrono" 262 | version = "0.4.38" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 265 | dependencies = [ 266 | "android-tzdata", 267 | "iana-time-zone", 268 | "js-sys", 269 | "num-traits", 270 | "wasm-bindgen", 271 | "windows-targets", 272 | ] 273 | 274 | [[package]] 275 | name = "cipher" 276 | version = "0.2.5" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" 279 | dependencies = [ 280 | "generic-array", 281 | ] 282 | 283 | [[package]] 284 | name = "clap" 285 | version = "2.34.0" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" 288 | dependencies = [ 289 | "ansi_term", 290 | "atty", 291 | "bitflags", 292 | "strsim 0.8.0", 293 | "textwrap", 294 | "unicode-width", 295 | "vec_map", 296 | ] 297 | 298 | [[package]] 299 | name = "clap" 300 | version = "4.5.16" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" 303 | dependencies = [ 304 | "clap_builder", 305 | "clap_derive", 306 | ] 307 | 308 | [[package]] 309 | name = "clap_builder" 310 | version = "4.5.15" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" 313 | dependencies = [ 314 | "anstream", 315 | "anstyle", 316 | "clap_lex", 317 | "strsim 0.11.1", 318 | ] 319 | 320 | [[package]] 321 | name = "clap_derive" 322 | version = "4.5.13" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" 325 | dependencies = [ 326 | "heck", 327 | "proc-macro2", 328 | "quote", 329 | "syn", 330 | ] 331 | 332 | [[package]] 333 | name = "clap_lex" 334 | version = "0.7.2" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" 337 | 338 | [[package]] 339 | name = "colorchoice" 340 | version = "1.0.2" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" 343 | 344 | [[package]] 345 | name = "const-oid" 346 | version = "0.9.6" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 349 | 350 | [[package]] 351 | name = "constant_time_eq" 352 | version = "0.1.5" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 355 | 356 | [[package]] 357 | name = "core-foundation-sys" 358 | version = "0.8.7" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 361 | 362 | [[package]] 363 | name = "cpufeatures" 364 | version = "0.2.13" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" 367 | dependencies = [ 368 | "libc", 369 | ] 370 | 371 | [[package]] 372 | name = "crc" 373 | version = "3.2.1" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" 376 | dependencies = [ 377 | "crc-catalog", 378 | ] 379 | 380 | [[package]] 381 | name = "crc-catalog" 382 | version = "2.4.0" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 385 | 386 | [[package]] 387 | name = "crossbeam-deque" 388 | version = "0.8.5" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 391 | dependencies = [ 392 | "crossbeam-epoch", 393 | "crossbeam-utils", 394 | ] 395 | 396 | [[package]] 397 | name = "crossbeam-epoch" 398 | version = "0.9.18" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 401 | dependencies = [ 402 | "crossbeam-utils", 403 | ] 404 | 405 | [[package]] 406 | name = "crossbeam-utils" 407 | version = "0.8.20" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 410 | 411 | [[package]] 412 | name = "crypto-common" 413 | version = "0.1.6" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 416 | dependencies = [ 417 | "generic-array", 418 | "typenum", 419 | ] 420 | 421 | [[package]] 422 | name = "ctr" 423 | version = "0.6.0" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" 426 | dependencies = [ 427 | "cipher", 428 | ] 429 | 430 | [[package]] 431 | name = "curve25519-dalek" 432 | version = "4.1.3" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" 435 | dependencies = [ 436 | "cfg-if", 437 | "cpufeatures", 438 | "curve25519-dalek-derive", 439 | "digest", 440 | "fiat-crypto", 441 | "rustc_version", 442 | "subtle", 443 | "zeroize", 444 | ] 445 | 446 | [[package]] 447 | name = "curve25519-dalek-derive" 448 | version = "0.1.1" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" 451 | dependencies = [ 452 | "proc-macro2", 453 | "quote", 454 | "syn", 455 | ] 456 | 457 | [[package]] 458 | name = "der" 459 | version = "0.7.9" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" 462 | dependencies = [ 463 | "const-oid", 464 | "zeroize", 465 | ] 466 | 467 | [[package]] 468 | name = "difflib" 469 | version = "0.4.0" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" 472 | 473 | [[package]] 474 | name = "diffy" 475 | version = "0.2.2" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "c27ec7cef89a63c063e06570bb861b7d35e406d6885551b346d77c459b34d3db" 478 | dependencies = [ 479 | "ansi_term", 480 | ] 481 | 482 | [[package]] 483 | name = "digest" 484 | version = "0.10.7" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 487 | dependencies = [ 488 | "block-buffer", 489 | "crypto-common", 490 | ] 491 | 492 | [[package]] 493 | name = "dirs" 494 | version = "1.0.5" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" 497 | dependencies = [ 498 | "libc", 499 | "redox_users", 500 | "winapi", 501 | ] 502 | 503 | [[package]] 504 | name = "doc-comment" 505 | version = "0.3.3" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 508 | 509 | [[package]] 510 | name = "ed25519" 511 | version = "2.2.3" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" 514 | dependencies = [ 515 | "pkcs8", 516 | "signature", 517 | ] 518 | 519 | [[package]] 520 | name = "ed25519-dalek" 521 | version = "2.1.1" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" 524 | dependencies = [ 525 | "curve25519-dalek", 526 | "ed25519", 527 | "rand_core", 528 | "serde", 529 | "sha2", 530 | "subtle", 531 | "zeroize", 532 | ] 533 | 534 | [[package]] 535 | name = "either" 536 | version = "1.13.0" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 539 | 540 | [[package]] 541 | name = "ever_abi" 542 | version = "2.7.2" 543 | source = "git+https://github.com/everx-labs/ever-abi.git?tag=2.7.2#70f946130a68db322fa7fe735c77e5998c4fefb4" 544 | dependencies = [ 545 | "anyhow", 546 | "byteorder", 547 | "chrono", 548 | "ever_block", 549 | "hex 0.3.2", 550 | "num-bigint", 551 | "num-traits", 552 | "serde", 553 | "serde_derive", 554 | "serde_json", 555 | "thiserror", 556 | ] 557 | 558 | [[package]] 559 | name = "ever_assembler" 560 | version = "1.6.14" 561 | source = "git+https://github.com/everx-labs/ever-assembler.git?tag=1.6.14#0569ad4c246813f3b3f2db27b427c67afd23e8e9" 562 | dependencies = [ 563 | "anyhow", 564 | "clap 4.5.16", 565 | "ever_block", 566 | "ever_vm", 567 | "hex 0.4.3", 568 | "log", 569 | "num", 570 | "num-traits", 571 | "serde", 572 | "serde_json", 573 | "thiserror", 574 | ] 575 | 576 | [[package]] 577 | name = "ever_block" 578 | version = "1.11.11" 579 | source = "git+https://github.com/everx-labs/ever-block.git?tag=1.11.11#5d617e2f0a8f7ec2b3e0aab9167280260a5ad7f2" 580 | dependencies = [ 581 | "aes-ctr", 582 | "anyhow", 583 | "base64", 584 | "blst", 585 | "crc", 586 | "curve25519-dalek", 587 | "ed25519", 588 | "ed25519-dalek", 589 | "getrandom 0.2.15", 590 | "hex 0.4.3", 591 | "lazy_static", 592 | "lockfree", 593 | "log", 594 | "num", 595 | "num-derive", 596 | "num-traits", 597 | "rand", 598 | "serde", 599 | "serde_json", 600 | "sha2", 601 | "smallvec", 602 | "thiserror", 603 | "x25519-dalek", 604 | ] 605 | 606 | [[package]] 607 | name = "ever_vm" 608 | version = "2.2.12" 609 | source = "git+https://github.com/everx-labs/ever-vm.git?tag=2.2.12#ebd07bab74de939cfc71b1f56aa314cb58695318" 610 | dependencies = [ 611 | "anyhow", 612 | "diffy", 613 | "ever_block", 614 | "hex 0.4.3", 615 | "lazy_static", 616 | "log", 617 | "num", 618 | "num-traits", 619 | "similar", 620 | "thiserror", 621 | "zstd", 622 | ] 623 | 624 | [[package]] 625 | name = "fiat-crypto" 626 | version = "0.2.9" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" 629 | 630 | [[package]] 631 | name = "float-cmp" 632 | version = "0.9.0" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" 635 | dependencies = [ 636 | "num-traits", 637 | ] 638 | 639 | [[package]] 640 | name = "generic-array" 641 | version = "0.14.7" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 644 | dependencies = [ 645 | "typenum", 646 | "version_check", 647 | ] 648 | 649 | [[package]] 650 | name = "getrandom" 651 | version = "0.1.16" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 654 | dependencies = [ 655 | "cfg-if", 656 | "libc", 657 | "wasi 0.9.0+wasi-snapshot-preview1", 658 | ] 659 | 660 | [[package]] 661 | name = "getrandom" 662 | version = "0.2.15" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 665 | dependencies = [ 666 | "cfg-if", 667 | "js-sys", 668 | "libc", 669 | "wasi 0.11.0+wasi-snapshot-preview1", 670 | "wasm-bindgen", 671 | ] 672 | 673 | [[package]] 674 | name = "glob" 675 | version = "0.3.1" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 678 | 679 | [[package]] 680 | name = "heck" 681 | version = "0.5.0" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 684 | 685 | [[package]] 686 | name = "hermit-abi" 687 | version = "0.1.19" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 690 | dependencies = [ 691 | "libc", 692 | ] 693 | 694 | [[package]] 695 | name = "hermit-abi" 696 | version = "0.3.9" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 699 | 700 | [[package]] 701 | name = "hex" 702 | version = "0.3.2" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 705 | 706 | [[package]] 707 | name = "hex" 708 | version = "0.4.3" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 711 | 712 | [[package]] 713 | name = "iana-time-zone" 714 | version = "0.1.60" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 717 | dependencies = [ 718 | "android_system_properties", 719 | "core-foundation-sys", 720 | "iana-time-zone-haiku", 721 | "js-sys", 722 | "wasm-bindgen", 723 | "windows-core", 724 | ] 725 | 726 | [[package]] 727 | name = "iana-time-zone-haiku" 728 | version = "0.1.2" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 731 | dependencies = [ 732 | "cc", 733 | ] 734 | 735 | [[package]] 736 | name = "is_terminal_polyfill" 737 | version = "1.70.1" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 740 | 741 | [[package]] 742 | name = "itoa" 743 | version = "1.0.11" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 746 | 747 | [[package]] 748 | name = "jobserver" 749 | version = "0.1.32" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 752 | dependencies = [ 753 | "libc", 754 | ] 755 | 756 | [[package]] 757 | name = "js-sys" 758 | version = "0.3.70" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" 761 | dependencies = [ 762 | "wasm-bindgen", 763 | ] 764 | 765 | [[package]] 766 | name = "lazy_static" 767 | version = "1.5.0" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 770 | 771 | [[package]] 772 | name = "libc" 773 | version = "0.2.156" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a" 776 | 777 | [[package]] 778 | name = "lockfree" 779 | version = "0.5.1" 780 | source = "git+https://github.com/everx-labs/lockfree.git#bfcb66587dc4ffed9e8e9248995ad2fe8dc3669e" 781 | dependencies = [ 782 | "owned-alloc", 783 | ] 784 | 785 | [[package]] 786 | name = "log" 787 | version = "0.4.22" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 790 | 791 | [[package]] 792 | name = "memchr" 793 | version = "2.7.4" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 796 | 797 | [[package]] 798 | name = "normalize-line-endings" 799 | version = "0.3.0" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" 802 | 803 | [[package]] 804 | name = "num" 805 | version = "0.4.3" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" 808 | dependencies = [ 809 | "num-bigint", 810 | "num-complex", 811 | "num-integer", 812 | "num-iter", 813 | "num-rational", 814 | "num-traits", 815 | ] 816 | 817 | [[package]] 818 | name = "num-bigint" 819 | version = "0.4.6" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 822 | dependencies = [ 823 | "num-integer", 824 | "num-traits", 825 | ] 826 | 827 | [[package]] 828 | name = "num-complex" 829 | version = "0.4.6" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" 832 | dependencies = [ 833 | "num-traits", 834 | ] 835 | 836 | [[package]] 837 | name = "num-derive" 838 | version = "0.4.2" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" 841 | dependencies = [ 842 | "proc-macro2", 843 | "quote", 844 | "syn", 845 | ] 846 | 847 | [[package]] 848 | name = "num-integer" 849 | version = "0.1.46" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 852 | dependencies = [ 853 | "num-traits", 854 | ] 855 | 856 | [[package]] 857 | name = "num-iter" 858 | version = "0.1.45" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 861 | dependencies = [ 862 | "autocfg", 863 | "num-integer", 864 | "num-traits", 865 | ] 866 | 867 | [[package]] 868 | name = "num-rational" 869 | version = "0.4.2" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" 872 | dependencies = [ 873 | "num-bigint", 874 | "num-integer", 875 | "num-traits", 876 | ] 877 | 878 | [[package]] 879 | name = "num-traits" 880 | version = "0.2.19" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 883 | dependencies = [ 884 | "autocfg", 885 | ] 886 | 887 | [[package]] 888 | name = "num_cpus" 889 | version = "1.16.0" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 892 | dependencies = [ 893 | "hermit-abi 0.3.9", 894 | "libc", 895 | ] 896 | 897 | [[package]] 898 | name = "once_cell" 899 | version = "1.19.0" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 902 | 903 | [[package]] 904 | name = "opaque-debug" 905 | version = "0.3.1" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 908 | 909 | [[package]] 910 | name = "owned-alloc" 911 | version = "0.2.0" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "30fceb411f9a12ff9222c5f824026be368ff15dc2f13468d850c7d3f502205d6" 914 | 915 | [[package]] 916 | name = "pkcs8" 917 | version = "0.10.2" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 920 | dependencies = [ 921 | "der", 922 | "spki", 923 | ] 924 | 925 | [[package]] 926 | name = "pkg-config" 927 | version = "0.3.30" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 930 | 931 | [[package]] 932 | name = "ppv-lite86" 933 | version = "0.2.20" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 936 | dependencies = [ 937 | "zerocopy", 938 | ] 939 | 940 | [[package]] 941 | name = "predicates" 942 | version = "3.1.2" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" 945 | dependencies = [ 946 | "anstyle", 947 | "difflib", 948 | "float-cmp", 949 | "normalize-line-endings", 950 | "predicates-core", 951 | "regex", 952 | ] 953 | 954 | [[package]] 955 | name = "predicates-core" 956 | version = "1.0.8" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" 959 | 960 | [[package]] 961 | name = "predicates-tree" 962 | version = "1.0.11" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" 965 | dependencies = [ 966 | "predicates-core", 967 | "termtree", 968 | ] 969 | 970 | [[package]] 971 | name = "proc-macro2" 972 | version = "1.0.86" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 975 | dependencies = [ 976 | "unicode-ident", 977 | ] 978 | 979 | [[package]] 980 | name = "quote" 981 | version = "1.0.36" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 984 | dependencies = [ 985 | "proc-macro2", 986 | ] 987 | 988 | [[package]] 989 | name = "rand" 990 | version = "0.8.5" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 993 | dependencies = [ 994 | "libc", 995 | "rand_chacha", 996 | "rand_core", 997 | ] 998 | 999 | [[package]] 1000 | name = "rand_chacha" 1001 | version = "0.3.1" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1004 | dependencies = [ 1005 | "ppv-lite86", 1006 | "rand_core", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "rand_core" 1011 | version = "0.6.4" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1014 | dependencies = [ 1015 | "getrandom 0.2.15", 1016 | ] 1017 | 1018 | [[package]] 1019 | name = "rayon" 1020 | version = "1.10.0" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 1023 | dependencies = [ 1024 | "either", 1025 | "rayon-core", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "rayon-core" 1030 | version = "1.12.1" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 1033 | dependencies = [ 1034 | "crossbeam-deque", 1035 | "crossbeam-utils", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "redox_syscall" 1040 | version = "0.1.57" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 1043 | 1044 | [[package]] 1045 | name = "redox_users" 1046 | version = "0.3.5" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" 1049 | dependencies = [ 1050 | "getrandom 0.1.16", 1051 | "redox_syscall", 1052 | "rust-argon2", 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "regex" 1057 | version = "1.10.6" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" 1060 | dependencies = [ 1061 | "aho-corasick", 1062 | "memchr", 1063 | "regex-automata", 1064 | "regex-syntax", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "regex-automata" 1069 | version = "0.4.7" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 1072 | dependencies = [ 1073 | "aho-corasick", 1074 | "memchr", 1075 | "regex-syntax", 1076 | ] 1077 | 1078 | [[package]] 1079 | name = "regex-syntax" 1080 | version = "0.8.4" 1081 | source = "registry+https://github.com/rust-lang/crates.io-index" 1082 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 1083 | 1084 | [[package]] 1085 | name = "rust-argon2" 1086 | version = "0.8.3" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" 1089 | dependencies = [ 1090 | "base64", 1091 | "blake2b_simd", 1092 | "constant_time_eq", 1093 | "crossbeam-utils", 1094 | ] 1095 | 1096 | [[package]] 1097 | name = "rustc_version" 1098 | version = "0.4.0" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1101 | dependencies = [ 1102 | "semver", 1103 | ] 1104 | 1105 | [[package]] 1106 | name = "ryu" 1107 | version = "1.0.18" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1110 | 1111 | [[package]] 1112 | name = "semver" 1113 | version = "1.0.23" 1114 | source = "registry+https://github.com/rust-lang/crates.io-index" 1115 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 1116 | 1117 | [[package]] 1118 | name = "serde" 1119 | version = "1.0.208" 1120 | source = "registry+https://github.com/rust-lang/crates.io-index" 1121 | checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" 1122 | dependencies = [ 1123 | "serde_derive", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "serde_derive" 1128 | version = "1.0.208" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" 1131 | dependencies = [ 1132 | "proc-macro2", 1133 | "quote", 1134 | "syn", 1135 | ] 1136 | 1137 | [[package]] 1138 | name = "serde_json" 1139 | version = "1.0.125" 1140 | source = "registry+https://github.com/rust-lang/crates.io-index" 1141 | checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" 1142 | dependencies = [ 1143 | "itoa", 1144 | "memchr", 1145 | "ryu", 1146 | "serde", 1147 | ] 1148 | 1149 | [[package]] 1150 | name = "sha2" 1151 | version = "0.10.8" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1154 | dependencies = [ 1155 | "cfg-if", 1156 | "cpufeatures", 1157 | "digest", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "shlex" 1162 | version = "1.3.0" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1165 | 1166 | [[package]] 1167 | name = "signature" 1168 | version = "2.2.0" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 1171 | dependencies = [ 1172 | "rand_core", 1173 | ] 1174 | 1175 | [[package]] 1176 | name = "similar" 1177 | version = "2.6.0" 1178 | source = "registry+https://github.com/rust-lang/crates.io-index" 1179 | checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" 1180 | dependencies = [ 1181 | "bstr", 1182 | ] 1183 | 1184 | [[package]] 1185 | name = "simplelog" 1186 | version = "0.6.0" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "aa9c948a5a26cd38340ddbeaa557a8c8a5ce4442408eb60453bee2bb3c84a3fb" 1189 | dependencies = [ 1190 | "chrono", 1191 | "log", 1192 | "term", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "smallvec" 1197 | version = "1.13.2" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1200 | 1201 | [[package]] 1202 | name = "spki" 1203 | version = "0.7.3" 1204 | source = "registry+https://github.com/rust-lang/crates.io-index" 1205 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 1206 | dependencies = [ 1207 | "base64ct", 1208 | "der", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "strsim" 1213 | version = "0.8.0" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1216 | 1217 | [[package]] 1218 | name = "strsim" 1219 | version = "0.11.1" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1222 | 1223 | [[package]] 1224 | name = "subtle" 1225 | version = "2.6.1" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1228 | 1229 | [[package]] 1230 | name = "syn" 1231 | version = "2.0.74" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" 1234 | dependencies = [ 1235 | "proc-macro2", 1236 | "quote", 1237 | "unicode-ident", 1238 | ] 1239 | 1240 | [[package]] 1241 | name = "term" 1242 | version = "0.5.2" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" 1245 | dependencies = [ 1246 | "byteorder", 1247 | "dirs", 1248 | "winapi", 1249 | ] 1250 | 1251 | [[package]] 1252 | name = "termtree" 1253 | version = "0.4.1" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" 1256 | 1257 | [[package]] 1258 | name = "textwrap" 1259 | version = "0.11.0" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1262 | dependencies = [ 1263 | "unicode-width", 1264 | ] 1265 | 1266 | [[package]] 1267 | name = "thiserror" 1268 | version = "1.0.63" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" 1271 | dependencies = [ 1272 | "thiserror-impl", 1273 | ] 1274 | 1275 | [[package]] 1276 | name = "thiserror-impl" 1277 | version = "1.0.63" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" 1280 | dependencies = [ 1281 | "proc-macro2", 1282 | "quote", 1283 | "syn", 1284 | ] 1285 | 1286 | [[package]] 1287 | name = "threadpool" 1288 | version = "1.8.1" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" 1291 | dependencies = [ 1292 | "num_cpus", 1293 | ] 1294 | 1295 | [[package]] 1296 | name = "tvm_linker" 1297 | version = "0.21.6" 1298 | dependencies = [ 1299 | "anyhow", 1300 | "assert_cmd", 1301 | "base64", 1302 | "clap 2.34.0", 1303 | "crc", 1304 | "ever_abi", 1305 | "ever_assembler", 1306 | "ever_block", 1307 | "ever_vm", 1308 | "hex 0.4.3", 1309 | "lazy_static", 1310 | "log", 1311 | "num", 1312 | "num-traits", 1313 | "predicates", 1314 | "rand", 1315 | "rayon", 1316 | "regex", 1317 | "serde", 1318 | "serde_json", 1319 | "sha2", 1320 | "similar", 1321 | "simplelog", 1322 | "thiserror", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "typenum" 1327 | version = "1.17.0" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1330 | 1331 | [[package]] 1332 | name = "unicode-ident" 1333 | version = "1.0.12" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1336 | 1337 | [[package]] 1338 | name = "unicode-width" 1339 | version = "0.1.13" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 1342 | 1343 | [[package]] 1344 | name = "utf8parse" 1345 | version = "0.2.2" 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" 1347 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1348 | 1349 | [[package]] 1350 | name = "vec_map" 1351 | version = "0.8.2" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1354 | 1355 | [[package]] 1356 | name = "version_check" 1357 | version = "0.9.5" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1360 | 1361 | [[package]] 1362 | name = "wait-timeout" 1363 | version = "0.2.0" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" 1366 | dependencies = [ 1367 | "libc", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "wasi" 1372 | version = "0.9.0+wasi-snapshot-preview1" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1375 | 1376 | [[package]] 1377 | name = "wasi" 1378 | version = "0.11.0+wasi-snapshot-preview1" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1381 | 1382 | [[package]] 1383 | name = "wasm-bindgen" 1384 | version = "0.2.93" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" 1387 | dependencies = [ 1388 | "cfg-if", 1389 | "once_cell", 1390 | "wasm-bindgen-macro", 1391 | ] 1392 | 1393 | [[package]] 1394 | name = "wasm-bindgen-backend" 1395 | version = "0.2.93" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" 1398 | dependencies = [ 1399 | "bumpalo", 1400 | "log", 1401 | "once_cell", 1402 | "proc-macro2", 1403 | "quote", 1404 | "syn", 1405 | "wasm-bindgen-shared", 1406 | ] 1407 | 1408 | [[package]] 1409 | name = "wasm-bindgen-macro" 1410 | version = "0.2.93" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" 1413 | dependencies = [ 1414 | "quote", 1415 | "wasm-bindgen-macro-support", 1416 | ] 1417 | 1418 | [[package]] 1419 | name = "wasm-bindgen-macro-support" 1420 | version = "0.2.93" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" 1423 | dependencies = [ 1424 | "proc-macro2", 1425 | "quote", 1426 | "syn", 1427 | "wasm-bindgen-backend", 1428 | "wasm-bindgen-shared", 1429 | ] 1430 | 1431 | [[package]] 1432 | name = "wasm-bindgen-shared" 1433 | version = "0.2.93" 1434 | source = "registry+https://github.com/rust-lang/crates.io-index" 1435 | checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" 1436 | 1437 | [[package]] 1438 | name = "winapi" 1439 | version = "0.3.9" 1440 | source = "registry+https://github.com/rust-lang/crates.io-index" 1441 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1442 | dependencies = [ 1443 | "winapi-i686-pc-windows-gnu", 1444 | "winapi-x86_64-pc-windows-gnu", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "winapi-i686-pc-windows-gnu" 1449 | version = "0.4.0" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1452 | 1453 | [[package]] 1454 | name = "winapi-x86_64-pc-windows-gnu" 1455 | version = "0.4.0" 1456 | source = "registry+https://github.com/rust-lang/crates.io-index" 1457 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1458 | 1459 | [[package]] 1460 | name = "windows-core" 1461 | version = "0.52.0" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 1464 | dependencies = [ 1465 | "windows-targets", 1466 | ] 1467 | 1468 | [[package]] 1469 | name = "windows-sys" 1470 | version = "0.52.0" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1473 | dependencies = [ 1474 | "windows-targets", 1475 | ] 1476 | 1477 | [[package]] 1478 | name = "windows-targets" 1479 | version = "0.52.6" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1482 | dependencies = [ 1483 | "windows_aarch64_gnullvm", 1484 | "windows_aarch64_msvc", 1485 | "windows_i686_gnu", 1486 | "windows_i686_gnullvm", 1487 | "windows_i686_msvc", 1488 | "windows_x86_64_gnu", 1489 | "windows_x86_64_gnullvm", 1490 | "windows_x86_64_msvc", 1491 | ] 1492 | 1493 | [[package]] 1494 | name = "windows_aarch64_gnullvm" 1495 | version = "0.52.6" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1498 | 1499 | [[package]] 1500 | name = "windows_aarch64_msvc" 1501 | version = "0.52.6" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1504 | 1505 | [[package]] 1506 | name = "windows_i686_gnu" 1507 | version = "0.52.6" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1510 | 1511 | [[package]] 1512 | name = "windows_i686_gnullvm" 1513 | version = "0.52.6" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1516 | 1517 | [[package]] 1518 | name = "windows_i686_msvc" 1519 | version = "0.52.6" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1522 | 1523 | [[package]] 1524 | name = "windows_x86_64_gnu" 1525 | version = "0.52.6" 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" 1527 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1528 | 1529 | [[package]] 1530 | name = "windows_x86_64_gnullvm" 1531 | version = "0.52.6" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1534 | 1535 | [[package]] 1536 | name = "windows_x86_64_msvc" 1537 | version = "0.52.6" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1540 | 1541 | [[package]] 1542 | name = "x25519-dalek" 1543 | version = "2.0.1" 1544 | source = "registry+https://github.com/rust-lang/crates.io-index" 1545 | checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" 1546 | dependencies = [ 1547 | "curve25519-dalek", 1548 | "rand_core", 1549 | "serde", 1550 | "zeroize", 1551 | ] 1552 | 1553 | [[package]] 1554 | name = "zerocopy" 1555 | version = "0.7.35" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1558 | dependencies = [ 1559 | "byteorder", 1560 | "zerocopy-derive", 1561 | ] 1562 | 1563 | [[package]] 1564 | name = "zerocopy-derive" 1565 | version = "0.7.35" 1566 | source = "registry+https://github.com/rust-lang/crates.io-index" 1567 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1568 | dependencies = [ 1569 | "proc-macro2", 1570 | "quote", 1571 | "syn", 1572 | ] 1573 | 1574 | [[package]] 1575 | name = "zeroize" 1576 | version = "1.8.1" 1577 | source = "registry+https://github.com/rust-lang/crates.io-index" 1578 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 1579 | dependencies = [ 1580 | "zeroize_derive", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "zeroize_derive" 1585 | version = "1.4.2" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 1588 | dependencies = [ 1589 | "proc-macro2", 1590 | "quote", 1591 | "syn", 1592 | ] 1593 | 1594 | [[package]] 1595 | name = "zstd" 1596 | version = "0.11.2+zstd.1.5.2" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" 1599 | dependencies = [ 1600 | "zstd-safe", 1601 | ] 1602 | 1603 | [[package]] 1604 | name = "zstd-safe" 1605 | version = "5.0.2+zstd.1.5.2" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" 1608 | dependencies = [ 1609 | "libc", 1610 | "zstd-sys", 1611 | ] 1612 | 1613 | [[package]] 1614 | name = "zstd-sys" 1615 | version = "2.0.13+zstd.1.5.6" 1616 | source = "registry+https://github.com/rust-lang/crates.io-index" 1617 | checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" 1618 | dependencies = [ 1619 | "cc", 1620 | "pkg-config", 1621 | ] 1622 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [ 'EverX Labs Ltd ' ] 3 | description = 'TVM Linker' 4 | edition = '2021' 5 | keywords = [ 'linker', 'TVM', 'everx-labs' ] 6 | license-file = 'LICENSE.md' 7 | name = 'tvm_linker' 8 | readme = 'README.md' 9 | repository = 'https://github.com/everx-labs/TVM-linker' 10 | version = '0.21.6' 11 | 12 | [[bin]] 13 | name = 'tvm_linker' 14 | path = 'src/main.rs' 15 | 16 | [dependencies] 17 | anyhow = '1.0' 18 | base64 = '0.13' 19 | clap = '2.33' 20 | crc = '3.0' 21 | hex = '0.4' 22 | lazy_static = '1.4' 23 | log = '0.4' 24 | num = '0.4' 25 | num-traits = '0.2' 26 | rand = '0.8' 27 | regex = '1' 28 | serde = { features = [ 'derive' ], version = '1.0' } 29 | serde_json = '1.0' 30 | sha2 = '0.10' 31 | simplelog = '0.6' 32 | thiserror = '1.0' 33 | ever_abi = { git = 'https://github.com/everx-labs/ever-abi.git', tag = '2.7.2' } 34 | ever_assembler = { features = [ 'gosh' ], git = 'https://github.com/everx-labs/ever-assembler.git', tag = '1.6.14' } 35 | ever_block = { features = [ 'gosh' ], git = 'https://github.com/everx-labs/ever-block.git', tag = '1.11.11' } 36 | ever_vm = { features = [ 'gosh' ], git = 'https://github.com/everx-labs/ever-vm.git', tag = '2.2.12' } 37 | 38 | [dev-dependencies] 39 | assert_cmd = '2.0.5' 40 | predicates = '3.0.3' 41 | rayon = '1.5.3' 42 | similar = '2.2.0' 43 | 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TVM linker 2 | 3 | This repository stores the source code for `tvm_linker` utility. It can immediately execute a smart 4 | contract by emulating the computing phase of transaction. 5 | 6 | ## Prerequisites 7 | 8 | - Latest version of Rust 9 | - Cargo tool 10 | [Get them here](https://doc.rust-lang.org/cargo/getting-started/installation.html) 11 | 12 | ## How to build 13 | 14 | ```bash 15 | $ cargo update && cargo build --release 16 | ``` 17 | 18 | ## How to use 19 | 20 | `tvm_linker` has several modes of work: 21 | 22 | * Decoding of `.boc` messages prepared externally. 23 | ```bash 24 | tvm_linker decode ... 25 | ``` 26 | * Preparing an external inbound messages in `.boc` format. 27 | ```bash 28 | tvm_linker message ... 29 | ``` 30 | * Emulating contract execution: 31 | 32 | Linker can emulate compute phase of blockchain transaction. It is useful for contract debugging. 33 | 34 | ```bash 35 | tvm_linker test ... 36 | ``` 37 | 38 | ### More Help 39 | Use `tvm_linker --help` for detailed description about all options, flags and subcommands. 40 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2024 EverX Labs Ltd. 3 | * 4 | * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use 5 | * this file except in compliance with the License. 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific EVERX DEV software governing permissions and 11 | * limitations under the License. 12 | */ 13 | use std::process::Command; 14 | 15 | fn from_utf8(data: Vec) -> String { 16 | String::from_utf8(data).unwrap_or_else(|_| String::from("Unknown")) 17 | } 18 | 19 | fn main() { 20 | let mut git_branch = String::from("Unknown"); 21 | let mut git_commit = String::from("Unknown"); 22 | let mut commit_date = String::from("Unknown"); 23 | let mut build_time = String::from("Unknown"); 24 | 25 | let branch = Command::new("git") 26 | .args(["rev-parse", "--abbrev-ref", "HEAD"]) 27 | .output(); 28 | if let Ok(branch) = branch { 29 | git_branch = from_utf8(branch.stdout); 30 | } 31 | 32 | let last = Command::new("git").args(["rev-parse", "HEAD"]).output(); 33 | if let Ok(last) = last { 34 | git_commit = from_utf8(last.stdout); 35 | } 36 | 37 | let time = Command::new("git") 38 | .args(["log", "-1", "--date=iso", "--pretty=format:%cd"]) 39 | .output(); 40 | if let Ok(time) = time { 41 | commit_date = from_utf8(time.stdout); 42 | } 43 | 44 | let b_time = Command::new("date").args(["+%Y-%m-%d %T %z"]).output(); 45 | if let Ok(b_time) = b_time { 46 | build_time = from_utf8(b_time.stdout); 47 | } 48 | 49 | println!("cargo:rustc-env=BUILD_GIT_BRANCH={}", git_branch); 50 | println!("cargo:rustc-env=BUILD_GIT_COMMIT={}", git_commit); 51 | println!("cargo:rustc-env=BUILD_GIT_DATE={}", commit_date); 52 | println!("cargo:rustc-env=BUILD_TIME={}", build_time); 53 | } 54 | -------------------------------------------------------------------------------- /src/abi.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2024 EverX Labs Ltd. 3 | * 4 | * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use 5 | * this file except in compliance with the License. 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific EVERX DEV software governing permissions and 11 | * limitations under the License. 12 | */ 13 | use anyhow::format_err; 14 | use ever_abi::{ 15 | json_abi::{decode_function_response, encode_function_call}, 16 | Contract, 17 | }; 18 | 19 | use crate::keyman::Keypair; 20 | use ever_block::{BuilderData, Result, SliceData}; 21 | 22 | pub fn build_abi_body( 23 | abi_file: &str, 24 | method: &str, 25 | params: &str, 26 | header: Option<&str>, 27 | keypair: Option, 28 | internal: bool, 29 | address: Option, 30 | ) -> Result { 31 | encode_function_call( 32 | &load_abi_json_string(abi_file)?, 33 | method, 34 | header, 35 | params, 36 | internal, 37 | keypair.map(|p| p.private).as_ref(), 38 | address.as_deref(), 39 | ) 40 | } 41 | 42 | pub fn load_abi_json_string(abi_file: &str) -> Result { 43 | std::fs::read_to_string(abi_file) 44 | .map_err(|e| format_err!("unable to read ABI file {}: {}", abi_file, e)) 45 | } 46 | 47 | pub fn load_abi_contract(abi_json: &str) -> Result { 48 | Contract::load(abi_json.as_bytes()) 49 | .map_err(|e| format_err!("cannot parse contract abi: {:?}", e)) 50 | } 51 | 52 | pub fn decode_body( 53 | abi_file: &str, 54 | method: &str, 55 | body: SliceData, 56 | internal: bool, 57 | ) -> Result { 58 | decode_function_response( 59 | &load_abi_json_string(abi_file)?, 60 | method, 61 | body, 62 | internal, 63 | false, 64 | ) 65 | } 66 | -------------------------------------------------------------------------------- /src/keyman.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2024 EverX Labs Ltd. 3 | * 4 | * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use 5 | * this file except in compliance with the License. 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific EVERX DEV software governing permissions and 11 | * limitations under the License. 12 | */ 13 | use anyhow::format_err; 14 | use ever_block::{ed25519_create_private_key, Ed25519PrivateKey, Ed25519PublicKey, Result}; 15 | use serde::Deserialize; 16 | 17 | pub struct Keypair { 18 | pub private: Ed25519PrivateKey, 19 | pub public: Ed25519PublicKey, 20 | } 21 | 22 | impl Keypair { 23 | pub fn from_file(filename: &str) -> Result { 24 | let keys_str = std::fs::read_to_string(filename) 25 | .map_err(|e| format_err!("failed to read the keypair file: {}", e))?; 26 | #[derive(Deserialize)] 27 | struct KeyPair { 28 | pub public: String, 29 | pub secret: String, 30 | } 31 | let keys: KeyPair = serde_json::from_str(&keys_str) 32 | .map_err(|e| format_err!("failed to load keypair: {}", e))?; 33 | let private = hex::decode(keys.secret) 34 | .map_err(|e| format_err!("failed to decode private key: {}", e))?; 35 | let public = hex::decode(keys.public) 36 | .map_err(|e| format_err!("failed to decode public key: {}", e))?; 37 | 38 | let public_bytes = public 39 | .try_into() 40 | .map_err(|v: Vec| format_err!("failed to get public bytes, bad len {}", v.len()))?; 41 | Ok(Self { 42 | private: ed25519_create_private_key(&private)?, 43 | public: Ed25519PublicKey::from_bytes(&public_bytes)?, 44 | }) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2024 EverX Labs Ltd. 3 | * 4 | * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use 5 | * this file except in compliance with the License. 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific EVERX DEV software governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | pub mod abi; 15 | pub mod keyman; 16 | pub mod printer; 17 | pub mod program; 18 | pub mod testcall; 19 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2024 EverX Labs Ltd. 3 | * 4 | * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use 5 | * this file except in compliance with the License. 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific EVERX DEV software governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | mod abi; 15 | mod keyman; 16 | mod printer; 17 | mod program; 18 | mod testcall; 19 | 20 | use anyhow::{bail, format_err}; 21 | use clap::{clap_app, ArgMatches}; 22 | use std::{env, fs::File, io::Write, str::FromStr}; 23 | 24 | use ever_block::{AccountId, BocWriter, Result, SliceData, Status, UInt256}; 25 | use ever_block::{ 26 | ConfigParams, Deserializable, ExternalInboundMessageHeader, InternalMessageHeader, Message, 27 | MsgAddressInt, MsgAddressIntOrNone, Serializable, StateInit, 28 | }; 29 | 30 | use abi::{build_abi_body, decode_body, load_abi_contract, load_abi_json_string}; 31 | use keyman::Keypair; 32 | use program::{get_now, load_from_file, save_to_file}; 33 | use testcall::{call_contract, MsgInfo, TestCallParams, TraceLevel}; 34 | 35 | const DEFAULT_CAPABILITIES: u64 = 0x880116ae; // Default capabilities on the main network 36 | 37 | fn main() -> std::result::Result<(), i32> { 38 | linker_main().map_err(|err_str| { 39 | println!("Error: {}", err_str); 40 | 1 41 | }) 42 | } 43 | 44 | fn linker_main() -> Status { 45 | let build_info = format!( 46 | "v{}\nBUILD_GIT_COMMIT: {}\nBUILD_GIT_DATE: {}\nBUILD_TIME: {}", 47 | env!("CARGO_PKG_VERSION"), 48 | env!("BUILD_GIT_COMMIT"), 49 | env!("BUILD_GIT_DATE"), 50 | env!("BUILD_TIME"), 51 | ); 52 | let matches = clap_app!(tvm_linker => 53 | (version: build_info.as_str()) 54 | (about: "Tool for executing TVM code") 55 | (@subcommand decode => 56 | (about: "Take apart a message boc or a tvc file") 57 | (version: build_info.as_str()) 58 | (@arg INPUT: +required +takes_value "BOC file") 59 | (@arg TVC: --tvc "BOC file is tvc file") 60 | ) 61 | (@subcommand test => 62 | (@setting AllowLeadingHyphen) 63 | (about: "Execute contract in test environment") 64 | (version: build_info.as_str()) 65 | (@arg SOURCE: -s --source +takes_value "Contract source file") 66 | (@arg BODY: --body +takes_value "Body for external inbound message (a bitstring like x09c_ or a hex string)") 67 | (@arg BODY_FROM_BOC: --("body-from-boc") +takes_value "Body from message boc file") 68 | (@arg SIGN: --sign +takes_value "Signs body with private key from defined file") 69 | (@arg TRACE: --trace "Prints last command name, stack and registers after each executed TVM command") 70 | (@arg TRACE_MIN: --("trace-minimal") "Prints minimal trace") 71 | (@arg DECODEC6: --("decode-c6") "Prints last command name, stack and registers after each executed TVM command") 72 | (@arg INTERNAL: --internal +takes_value "Emulates inbound internal message with value instead of external message") 73 | (@arg BOUNCED: --bounced requires[INTERNAL] "Emulates bounced message, can be used only with --internal option.") 74 | (@arg BALANCE: --balance +takes_value "Emulates supplied account balance") 75 | (@arg SRCADDR: --src +takes_value "Supplies message source address") 76 | (@arg NOW: --now +takes_value "Supplies transaction creation unixtime") 77 | (@arg TICKTOCK: --ticktock +takes_value conflicts_with[BODY] "Emulates ticktock transaction in masterchain, 0 for tick and -1 for tock") 78 | (@arg GASLIMIT: -l --("gas-limit") +takes_value "Defines gas limit for tvm execution") 79 | (@arg CONFIG: --config +takes_value "Imports config parameters from a config contract TVC") 80 | (@arg INPUT: +required +takes_value "TVM assembler source file or contract name if used with test subcommand") 81 | (@arg ADDRESS: --address +takes_value "Contract address, which can be obtained from the contract with `address(this)`. If not specified address can be obtained from the INPUT argument or set to zero.") 82 | (@arg DEBUG_MAP: -d --("debug-map") +takes_value "Supplies debug info json file") 83 | (@arg ABI_JSON: -a --("abi-json") +takes_value conflicts_with[BODY] "Supplies json file with contract ABI") 84 | (@arg ABI_METHOD: -m --("abi-method") +takes_value conflicts_with[BODY] "Supplies the name of the calling contract method") 85 | (@arg ABI_PARAMS: -p --("abi-params") +takes_value conflicts_with[BODY] "Supplies ABI arguments for the contract method (can be passed via filename). Can be not specified for empty parameters.") 86 | (@arg ABI_HEADER: -r --("abi-header") +takes_value conflicts_with[BODY] conflicts_with[INTERNAL] "Supplies ABI header") 87 | ) 88 | (@subcommand message => 89 | (@setting AllowNegativeNumbers) 90 | (about: "Generate inbound message for the blockchain") 91 | (version: build_info.as_str()) 92 | (@arg INIT: -i --init "Generates constructor message with code and data of the contract") 93 | (@arg DATA: -d --data +takes_value "Supplies body for the message in hex format (empty data by default)") 94 | (@arg INTERNAL: --internal +takes_value "Generates inbound internal message with provided value (instead of external message by default)") 95 | (@arg WORKCHAIN: -w --workchain +takes_value "Supplies workchain id for the contract address") 96 | (@arg ABI_JSON: -a --("abi-json") +takes_value conflicts_with[DATA] "Supplies json file with contract ABI") 97 | (@arg ABI_METHOD: -m --("abi-method") +takes_value conflicts_with[DATA] "Supplies the name of the calling contract method") 98 | (@arg ABI_PARAMS: -p --("abi-params") +takes_value conflicts_with[DATA] "Supplies ABI arguments for the contract method") 99 | (@arg ABI_HEADER: -r --("abi-header") +takes_value conflicts_with[DATA] "Supplies ABI header") 100 | (@arg SIGN: --setkey +takes_value "Loads existing keypair from the file") 101 | (@arg ADDRESS: --addr +takes_value "Optional destination address to support ABI 2.3") 102 | (@arg INPUT: +required +takes_value "TVM assembler source file or contract name") 103 | ) 104 | (@setting SubcommandRequired) 105 | ).get_matches(); 106 | 107 | //SUBCOMMAND TEST 108 | if let Some(test_matches) = matches.subcommand_matches("test") { 109 | return run_test_subcmd(test_matches); 110 | } 111 | 112 | //SUBCOMMAND DECODE 113 | if let Some(decode_matches) = matches.subcommand_matches("decode") { 114 | return decode_boc( 115 | decode_matches.value_of("INPUT").unwrap(), 116 | decode_matches.is_present("TVC"), 117 | ); 118 | } 119 | 120 | //SUBCOMMAND MESSAGE 121 | if let Some(msg_matches) = matches.subcommand_matches("message") { 122 | let mut suffix = String::new(); 123 | suffix += "-msg"; 124 | if msg_matches.is_present("INIT") { 125 | suffix += "-init"; 126 | } 127 | if msg_matches.is_present("DATA") || msg_matches.is_present("ABI_JSON") { 128 | suffix += "-body"; 129 | } 130 | suffix += ".boc"; 131 | 132 | let msg_body = match msg_matches.value_of("DATA") { 133 | Some(data) => { 134 | let buf = hex::decode(data) 135 | .map_err(|e| format_err!("data argument has invalid format: {}", e))?; 136 | let len = buf.len() * 8; 137 | let body = SliceData::from_raw(buf, len); 138 | Some(body) 139 | } 140 | None => build_body( 141 | msg_matches, 142 | msg_matches.value_of("ADDRESS").map(|s| s.to_string()), 143 | )?, 144 | }; 145 | 146 | return build_message( 147 | msg_matches.value_of("INPUT").unwrap(), 148 | msg_matches.value_of("WORKCHAIN"), 149 | msg_body, 150 | msg_matches.is_present("INIT"), 151 | &suffix, 152 | msg_matches.is_present("INTERNAL"), 153 | ); 154 | } 155 | 156 | unreachable!() 157 | } 158 | 159 | fn parse_now(now: Option<&str>) -> Result { 160 | let now = match now { 161 | Some(now_str) => now_str 162 | .parse::() 163 | .map_err(|e| format_err!("failed to parse \"now\" option: {}", e))?, 164 | None => get_now(), 165 | }; 166 | Ok(now) 167 | } 168 | 169 | fn parse_ticktock(ticktock: Option<&str>) -> Result> { 170 | let error = "invalid ticktock value: must be 0 for tick and -1 for tock."; 171 | if let Some(tt) = ticktock { 172 | let tt = tt 173 | .parse::() 174 | .map_err(|e| format_err!("{}: {}", error, e))?; 175 | if tt != 0 && tt != -1 { 176 | bail!(error) 177 | } else { 178 | Ok(Some(tt)) 179 | } 180 | } else { 181 | Ok(None) 182 | } 183 | } 184 | 185 | fn decode_hex_string(hex_str: String) -> Result<(Vec, usize)> { 186 | if hex_str.to_ascii_lowercase().starts_with('x') { 187 | let buf = SliceData::from_string(&hex_str[1..]) 188 | .map_err(|_| format_err!("body {} is invalid literal slice", hex_str))?; 189 | Ok((buf.get_bytestring(0), buf.remaining_bits())) 190 | } else { 191 | let buf = hex::decode(&hex_str) 192 | .map_err(|_| format_err!("body {} is invalid hex string", hex_str))?; 193 | let buf_bits = buf.len() * 8; 194 | Ok((buf, buf_bits)) 195 | } 196 | } 197 | 198 | fn decode_boc(filename: &str, is_tvc: bool) -> Status { 199 | let (mut root_slice, orig_bytes) = program::load_stateinit(filename)?; 200 | 201 | println!("Encoded: {}\n", hex::encode(orig_bytes)); 202 | if is_tvc { 203 | let state = StateInit::construct_from(&mut root_slice)?; 204 | println!("Decoded:\n{}", printer::state_init_printer(&state)); 205 | } else { 206 | let msg = Message::construct_from(&mut root_slice)?; 207 | println!("Decoded:\n{}", printer::msg_printer(&msg)?); 208 | } 209 | Ok(()) 210 | } 211 | 212 | fn run_test_subcmd(matches: &ArgMatches) -> Status { 213 | let input = matches.value_of("INPUT").unwrap(); 214 | let addr_from_input = if hex::decode(input).is_ok() { 215 | input.to_owned() 216 | } else { 217 | "0".repeat(64) 218 | }; 219 | let address = matches.value_of("ADDRESS").unwrap_or(&addr_from_input); 220 | let (body, sign) = match matches.value_of("BODY") { 221 | Some(hex_str) => { 222 | let (buf, buf_bits) = decode_hex_string(hex_str.to_string())?; 223 | let body = SliceData::from_raw(buf, buf_bits); 224 | (Some(body), Some(matches.value_of("SIGN"))) 225 | } 226 | None => (build_body(matches, Some(address.to_string()))?, None), 227 | }; 228 | 229 | let ticktock = parse_ticktock(matches.value_of("TICKTOCK"))?; 230 | let now = parse_now(matches.value_of("NOW"))?; 231 | 232 | let action_decoder = |body, is_internal| { 233 | let abi_file = matches.value_of("ABI_JSON"); 234 | let method = matches.value_of("ABI_METHOD"); 235 | if let Some(abi_file) = abi_file { 236 | if let Some(method) = method { 237 | let result = decode_body(abi_file, method, body, is_internal).unwrap_or_default(); 238 | println!("{}", result); 239 | } 240 | } 241 | }; 242 | 243 | let abi_json = matches.value_of("ABI_JSON"); 244 | 245 | let _abi_contract = match abi_json { 246 | Some(abi_file) => Some(load_abi_contract(&load_abi_json_string(abi_file)?)?), 247 | None => None, 248 | }; 249 | 250 | let debug_map_filename = matches.value_of("DEBUG_MAP").map(|s| s.to_string()).or({ 251 | let mut res = Some("debug_map.map.json".to_string()); 252 | if let Some(abi) = abi_json { 253 | let abi_root = abi.trim_end_matches(".abi.json"); 254 | for extension in [".dbg.json", ".debug.json", ".map.json"] { 255 | let dbg_path = format!("{abi_root}{extension}"); 256 | if std::path::Path::new(&dbg_path).exists() { 257 | res = Some(dbg_path); 258 | break; 259 | } 260 | } 261 | } 262 | res 263 | }); 264 | if let Some(map) = debug_map_filename.clone() { 265 | println!("DEBUG_MAP: {map}"); 266 | } 267 | println!("TEST STARTED"); 268 | println!("body = {:?}", body); 269 | 270 | let mut msg_info = MsgInfo { 271 | balance: matches.value_of("INTERNAL"), 272 | src: matches.value_of("SRCADDR"), 273 | now, 274 | bounced: matches.is_present("BOUNCED"), 275 | body, 276 | }; 277 | 278 | if let Some(filename) = matches.value_of("BODY_FROM_BOC") { 279 | let (mut root_slice, _) = program::load_stateinit(filename)?; 280 | let msg = Message::construct_from(&mut root_slice)?; 281 | msg_info.body = msg.body(); 282 | } 283 | 284 | let gas_limit = matches 285 | .value_of("GASLIMIT") 286 | .map(|v| v.parse::()) 287 | .transpose()?; 288 | 289 | let mut trace_level = TraceLevel::None; 290 | if matches.is_present("TRACE") { 291 | trace_level = TraceLevel::Full; 292 | } else if matches.is_present("TRACE_MIN") { 293 | trace_level = TraceLevel::Minimal; 294 | } 295 | 296 | let input = if input.ends_with(".tvc") { 297 | input.to_owned() 298 | } else { 299 | format!("{}.tvc", input) 300 | }; 301 | let addr = MsgAddressInt::from_str(address)?; 302 | let state_init = load_from_file(&input)?; 303 | let config_cell_opt = matches.value_of("CONFIG").and_then(testcall::load_config); 304 | 305 | let capabilities = match config_cell_opt { 306 | Some(ref config_cell) => { 307 | let config_params = ConfigParams::with_address_and_root( 308 | UInt256::from_str(&"5".repeat(64)).unwrap(), // -1:5555... 309 | config_cell.clone(), 310 | ); 311 | config_params.capabilities() 312 | } 313 | None => DEFAULT_CAPABILITIES, 314 | }; 315 | let (_, state_init, is_success) = call_contract( 316 | addr, 317 | state_init, 318 | TestCallParams { 319 | balance: matches.value_of("BALANCE"), 320 | msg_info, 321 | config: config_cell_opt, 322 | key_file: sign, 323 | ticktock, 324 | gas_limit, 325 | action_decoder: if matches.is_present("DECODEC6") { 326 | Some(action_decoder) 327 | } else { 328 | None 329 | }, 330 | trace_level, 331 | debug_info: testcall::load_debug_info(&debug_map_filename.unwrap_or("".to_string())), 332 | capabilities, 333 | }, 334 | )?; 335 | if is_success { 336 | save_to_file(state_init, Some(&input), 0, false)?; 337 | println!("Contract persistent data updated"); 338 | } 339 | 340 | println!("TEST COMPLETED"); 341 | Ok(()) 342 | } 343 | 344 | fn build_body(matches: &ArgMatches, address: Option) -> Result> { 345 | let mut mask = 0u8; 346 | let abi_file = matches.value_of("ABI_JSON").map(|m| { 347 | mask |= 1; 348 | m 349 | }); 350 | let method_name = matches.value_of("ABI_METHOD").map(|m| { 351 | mask |= 2; 352 | m 353 | }); 354 | let params = matches.value_of("ABI_PARAMS"); 355 | let header = matches.value_of("ABI_HEADER"); 356 | if mask == 0x3 { 357 | let key_file = matches 358 | .value_of("SIGN") 359 | .map(Keypair::from_file) 360 | .transpose()?; 361 | let params = params.map_or(Ok("{}".to_owned()), |params| { 362 | if params.find('{').is_none() { 363 | std::fs::read_to_string(params) 364 | .map_err(|e| format_err!("failed to load params from file: {}", e)) 365 | } else { 366 | Ok(params.to_owned()) 367 | } 368 | })?; 369 | let is_internal = matches.is_present("INTERNAL"); 370 | let body = build_abi_body( 371 | abi_file.unwrap(), 372 | method_name.unwrap(), 373 | ¶ms, 374 | header, 375 | key_file, 376 | is_internal, 377 | address, 378 | )?; 379 | let body = SliceData::load_builder(body)?; 380 | Ok(Some(body)) 381 | } else if mask == 0 { 382 | Ok(None) 383 | } else { 384 | bail!("All ABI parameters must be supplied: ABI_JSON, ABI_METHOD") 385 | } 386 | } 387 | 388 | fn build_message( 389 | address_str: &str, 390 | wc: Option<&str>, 391 | body: Option, 392 | pack_code: bool, 393 | suffix: &str, 394 | internal: bool, 395 | ) -> Status { 396 | let wc = match wc { 397 | Some(w) => w.parse::()?, 398 | None => -1, 399 | }; 400 | println!("contract address {}", address_str); 401 | let dest_address = MsgAddressInt::with_standart(None, wc, AccountId::from_str(address_str)?)?; 402 | 403 | let mut msg = if internal { 404 | let source_address = MsgAddressIntOrNone::Some(MsgAddressInt::with_standart( 405 | None, 406 | -1, 407 | AccountId::from_str("55".repeat(32).as_str())?, 408 | )?); 409 | Message::with_int_header(InternalMessageHeader { 410 | ihr_disabled: true, 411 | bounce: true, 412 | src: source_address, 413 | dst: dest_address, 414 | ..Default::default() 415 | }) 416 | } else { 417 | Message::with_ext_in_header(ExternalInboundMessageHeader { 418 | dst: dest_address, 419 | ..Default::default() 420 | }) 421 | }; 422 | if pack_code { 423 | msg.set_state_init(load_from_file(&format!("{}.tvc", address_str))?); 424 | } 425 | if let Some(body) = body { 426 | msg.set_body(body); 427 | } 428 | 429 | let root_cell = msg.serialize()?; 430 | let mut bytes = Vec::new(); 431 | BocWriter::with_root(&root_cell)?.write_ex(&mut bytes, false, true, None, Some(4))?; 432 | 433 | println!("Encoded msg: {}", hex::encode(&bytes)); 434 | 435 | let output_file_name = address_str.get(0..8).unwrap_or("00000000").to_string() + suffix; 436 | let mut f = File::create(&output_file_name)?; 437 | f.write_all(&bytes)?; 438 | 439 | println!("boc file created: {}", output_file_name); 440 | Ok(()) 441 | } 442 | -------------------------------------------------------------------------------- /src/printer.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2024 EverX Labs Ltd. 3 | * 4 | * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use 5 | * this file except in compliance with the License. 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific EVERX DEV software governing permissions and 11 | * limitations under the License. 12 | */ 13 | use anyhow::format_err; 14 | use ever_block::write_boc; 15 | use ever_block::*; 16 | use ever_block::{BuilderData, Cell, Result}; 17 | 18 | fn get_version(root: &Cell) -> Result { 19 | let cell1 = root 20 | .reference(0) 21 | .map_err(|e| format_err!("not found ({})", e))?; 22 | let cell2 = cell1 23 | .reference(1) 24 | .map_err(|e| format_err!("not found ({})", e))?; 25 | let bytes = cell2.data(); 26 | match String::from_utf8(bytes.to_vec()) { 27 | Ok(string) => { 28 | if string.is_empty() { 29 | Ok("".to_string()) 30 | } else { 31 | Ok(string) 32 | } 33 | } 34 | Err(e) => Err(format_err!("decoding failed ({})", e)), 35 | } 36 | } 37 | 38 | pub fn get_version_mycode_aware(root: Option<&Cell>) -> Result { 39 | let root = root.ok_or_else(|| format_err!("not found (empty root)"))?; 40 | match get_version(root) { 41 | Ok(res) => Ok(res), 42 | Err(_) => { 43 | let root = root.reference(1)?; 44 | get_version(&root) 45 | } 46 | } 47 | } 48 | 49 | pub fn state_init_printer(state: &StateInit) -> String { 50 | format!("StateInit\n split_depth: {}\n special: {}\n data: {}\n code: {}\n code_hash: {}\n data_hash: {}\n code_depth: {}\n data_depth: {}\n version: {}\n lib: {}\n", 51 | state.split_depth.as_ref().map_or("None".to_string(), |x| x.as_u32().to_string()), 52 | state.special.as_ref().map_or("None".to_string(), ToString::to_string), 53 | tree_of_cells_into_base64(state.data.as_ref()), 54 | tree_of_cells_into_base64(state.code.as_ref()), 55 | state.code.as_ref().map(|code| code.repr_hash().to_hex_string()).unwrap_or_else(|| "None".to_string()), 56 | state.data.as_ref().map(|code| code.repr_hash().to_hex_string()).unwrap_or_else(|| "None".to_string()), 57 | state.code.as_ref().map(|code| code.repr_depth().to_string()).unwrap_or_else(|| "None".to_string()), 58 | state.data.as_ref().map(|code| code.repr_depth().to_string()).unwrap_or_else(|| "None".to_string()), 59 | get_version_mycode_aware(state.code.as_ref()).unwrap_or_else(|_| "None".to_string()), 60 | tree_of_cells_into_base64(state.library.root()), 61 | ) 62 | } 63 | 64 | pub fn tree_of_cells_into_base64(root_cell: Option<&Cell>) -> String { 65 | match root_cell { 66 | Some(cell) => match write_boc(cell) { 67 | Ok(bytes) => base64::encode(bytes), 68 | Err(_) => "None".to_string(), 69 | }, 70 | None => "None".to_string(), 71 | } 72 | } 73 | 74 | pub fn msg_printer(msg: &Message) -> Result { 75 | let mut b = BuilderData::new(); 76 | msg.write_to(&mut b)?; 77 | let bytes = write_boc(&b.into_cell()?)?; 78 | Ok(format!( 79 | "message header\n{}init : {}\nbody : {}\nbody_hex: {}\nbody_base64: {}\nboc_base64: {}\n", 80 | print_msg_header(msg.header()), 81 | msg.state_init() 82 | .as_ref() 83 | .map(|x| { state_init_printer(x) }) 84 | .unwrap_or_else(|| "None".to_string()), 85 | match msg.body() { 86 | Some(slice) => format!("{:.2}", slice.into_cell()), 87 | None => "None".to_string(), 88 | }, 89 | msg.body() 90 | .map(|b| hex::encode(b.get_bytestring(0))) 91 | .unwrap_or_else(|| "None".to_string()), 92 | tree_of_cells_into_base64(msg.body().map(|slice| slice.into_cell()).as_ref(),), 93 | base64::encode(bytes), 94 | )) 95 | } 96 | 97 | fn print_msg_header(header: &CommonMsgInfo) -> String { 98 | match header { 99 | CommonMsgInfo::IntMsgInfo(header) => { 100 | format!(" ihr_disabled: {}\n", header.ihr_disabled) 101 | + &format!(" bounce : {}\n", header.bounce) 102 | + &format!(" bounced : {}\n", header.bounced) 103 | + &format!(" source : {}\n", &header.src) 104 | + &format!(" destination : {}\n", &header.dst) 105 | + &format!(" value : {}\n", print_cc(&header.value)) 106 | + &format!(" ihr_fee : {}\n", print_grams(&header.ihr_fee)) 107 | + &format!(" fwd_fee : {}\n", print_grams(&header.fwd_fee)) 108 | + &format!(" created_lt : {}\n", header.created_lt) 109 | + &format!(" created_at : {}\n", header.created_at) 110 | } 111 | CommonMsgInfo::ExtInMsgInfo(header) => { 112 | format!(" source : {}\n", &header.src) 113 | + &format!(" destination : {}\n", &header.dst) 114 | + &format!(" import_fee : {}\n", print_grams(&header.import_fee)) 115 | } 116 | CommonMsgInfo::ExtOutMsgInfo(header) => { 117 | format!(" source : {}\n", &header.src) 118 | + &format!(" destination : {}\n", &header.dst) 119 | + &format!(" created_lt : {}\n", header.created_lt) 120 | + &format!(" created_at : {}\n", header.created_at) 121 | } 122 | } 123 | } 124 | 125 | fn print_grams(grams: &Grams) -> String { 126 | grams.to_string() 127 | } 128 | 129 | fn print_cc(cc: &CurrencyCollection) -> String { 130 | let mut result = print_grams(&cc.grams); 131 | if !cc.other.is_empty() { 132 | result += " other: {"; 133 | cc.other 134 | .iterate_with_keys(|key: u32, value| { 135 | result += &format!(" \"{}\": \"{}\",", key, value); 136 | Ok(true) 137 | }) 138 | .ok(); 139 | result.pop(); // remove extra comma 140 | result += " }"; 141 | } 142 | result 143 | } 144 | 145 | #[test] 146 | fn check_output_for_money() { 147 | let mut cc = CurrencyCollection::with_grams(u64::MAX >> 8); 148 | assert_eq!(print_grams(&cc.grams), "72057594037927935"); 149 | assert_eq!(print_cc(&cc), "72057594037927935"); 150 | cc.set_other(12, 125).unwrap(); 151 | cc.set_other_ex(17, &VarUInteger32::from_two_u128(1, 1900).unwrap()) 152 | .unwrap(); 153 | cc.set_other_ex( 154 | u32::MAX, 155 | &VarUInteger32::from_two_u128(u128::MAX >> 8, u128::MAX).unwrap(), 156 | ) 157 | .unwrap(); 158 | assert_eq!(print_grams(&cc.grams), "72057594037927935"); 159 | assert_eq!( 160 | print_cc(&cc), 161 | r#"72057594037927935 other: { "12": "125", "17": "340282366920938463463374607431768213356", "4294967295": "452312848583266388373324160190187140051835877600158453279131187530910662655" }"# 162 | ); 163 | } 164 | -------------------------------------------------------------------------------- /src/program.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2024 EverX Labs Ltd. 3 | * 4 | * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use 5 | * this file except in compliance with the License. 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific EVERX DEV software governing permissions and 11 | * limitations under the License. 12 | */ 13 | use base64::encode; 14 | 15 | use std::fs::File; 16 | use std::io::{Read, Write}; 17 | 18 | use ever_block::*; 19 | use std::time::SystemTime; 20 | 21 | use ever_block::{read_boc, BuilderData, Cell, Result, SliceData}; 22 | 23 | const XMODEM: crc::Crc = crc::Crc::::new(&crc::CRC_16_XMODEM); 24 | 25 | pub fn save_to_file(state: StateInit, name: Option<&str>, wc: i8, silent: bool) -> Result { 26 | let buffer = state.write_to_bytes()?; 27 | 28 | let mut print_filename = false; 29 | let address = state.hash().unwrap(); 30 | let file_name = if let Some(name) = name { 31 | name.to_string() 32 | } else { 33 | print_filename = true; 34 | format!("{:x}.tvc", address) 35 | }; 36 | 37 | let mut file = File::create(&file_name)?; 38 | file.write_all(&buffer)?; 39 | 40 | if print_filename { 41 | if silent { 42 | println!("{{\n \"output_path\":\"{}\"\n}}", &file_name); 43 | } else { 44 | println!("Saved contract to file {}", &file_name); 45 | println!("testnet:"); 46 | println!( 47 | "Non-bounceable address (for init): {}", 48 | &calc_userfriendly_address(wc, address.as_slice(), false, true) 49 | ); 50 | println!( 51 | "Bounceable address (for later access): {}", 52 | &calc_userfriendly_address(wc, address.as_slice(), true, true) 53 | ); 54 | println!("mainnet:"); 55 | println!( 56 | "Non-bounceable address (for init): {}", 57 | &calc_userfriendly_address(wc, address.as_slice(), false, false) 58 | ); 59 | println!( 60 | "Bounceable address (for later access): {}", 61 | &calc_userfriendly_address(wc, address.as_slice(), true, false) 62 | ); 63 | } 64 | } 65 | Ok(file_name) 66 | } 67 | 68 | fn calc_userfriendly_address(wc: i8, addr: &[u8], bounce: bool, testnet: bool) -> String { 69 | let mut bytes: Vec = vec![]; 70 | bytes.push(if bounce { 0x11 } else { 0x51 } + if testnet { 0x80 } else { 0 }); 71 | bytes.push(wc as u8); 72 | bytes.extend_from_slice(addr); 73 | let crc = XMODEM.checksum(&bytes); 74 | bytes.extend_from_slice(&crc.to_be_bytes()); 75 | encode(&bytes) 76 | } 77 | 78 | pub fn load_from_file(contract_file: &str) -> Result { 79 | let mut cell = read_boc(std::fs::read(contract_file)?)?.roots.remove(0); 80 | // try appending a dummy library cell if there is no such cell in the tvc file 81 | if cell.references_count() == 2 { 82 | let mut adjusted_cell = BuilderData::from_cell(&cell)?; 83 | adjusted_cell.checked_append_reference(Cell::default())?; 84 | cell = adjusted_cell.into_cell()?; 85 | } 86 | StateInit::construct_from_cell(cell) 87 | } 88 | 89 | pub fn load_stateinit(file_name: &str) -> Result<(SliceData, Vec)> { 90 | let mut orig_bytes = Vec::new(); 91 | let mut f = File::open(file_name)?; 92 | f.read_to_end(&mut orig_bytes)?; 93 | 94 | let mut root = read_boc(orig_bytes.clone())?.roots.remove(0); 95 | if root.references_count() == 2 { 96 | // append empty library cell 97 | let mut adjusted_cell = BuilderData::from_cell(&root)?; 98 | adjusted_cell.checked_append_reference(Cell::default())?; 99 | root = adjusted_cell.into_cell()?; 100 | } 101 | Ok((SliceData::load_cell(root)?, orig_bytes)) 102 | } 103 | 104 | pub fn get_now() -> u32 { 105 | SystemTime::now() 106 | .duration_since(SystemTime::UNIX_EPOCH) 107 | .unwrap() 108 | .as_secs() as u32 109 | } 110 | 111 | #[cfg(test)] 112 | mod tests { 113 | use super::*; 114 | 115 | #[test] 116 | fn test_bouncable_address() { 117 | let addr = hex::decode("fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260") 118 | .unwrap(); 119 | let addr = calc_userfriendly_address(-1, &addr, true, true); 120 | assert_eq!(addr, "kf/8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15+KsQHFLbKSMiYIny"); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/testcall.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2024 EverX Labs Ltd. 3 | * 4 | * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use 5 | * this file except in compliance with the License. 6 | * 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific EVERX DEV software governing permissions and 11 | * limitations under the License. 12 | */ 13 | 14 | use std::{fs::File, str::FromStr, sync::Arc}; 15 | 16 | use anyhow::format_err; 17 | use ever_assembler::DbgInfo; 18 | use ever_block::{ 19 | ed25519_sign_with_secret, AccountId, BuilderData, Cell, HashmapE, Result, SliceData, Status, 20 | }; 21 | use ever_block::{ 22 | CurrencyCollection, Deserializable, ExternalInboundMessageHeader, Grams, InternalMessageHeader, 23 | Message, MsgAddressExt, MsgAddressInt, OutAction, OutActions, Serializable, StateInit, 24 | }; 25 | use ever_vm::{ 26 | error::tvm_exception, 27 | executor::{gas::gas_state::Gas, Engine, EngineTraceInfo, EngineTraceInfoType}, 28 | int, 29 | stack::{integer::IntegerData, savelist::SaveList, Stack, StackItem}, 30 | SmartContractInfo, 31 | }; 32 | use log::{log_enabled, Level::Error}; 33 | use serde_json::Value; 34 | use simplelog::{Config, LevelFilter, SimpleLogger}; 35 | 36 | use crate::keyman::Keypair; 37 | use crate::printer::msg_printer; 38 | use crate::program::{get_now, load_from_file}; 39 | 40 | const DEFAULT_ACCOUNT_BALANCE: &str = "100000000000"; 41 | 42 | fn create_external_inbound_msg( 43 | src: MsgAddressExt, 44 | dst: MsgAddressInt, 45 | body: Option, 46 | ) -> Message { 47 | let hdr = ExternalInboundMessageHeader { 48 | dst, 49 | src, 50 | import_fee: 0x1234u64.into(), 51 | }; 52 | let mut msg = Message::with_ext_in_header(hdr); 53 | if let Some(body) = body { 54 | msg.set_body(body); 55 | } 56 | msg 57 | } 58 | 59 | fn create_internal_msg( 60 | src_addr: MsgAddressInt, 61 | dst_addr: MsgAddressInt, 62 | value: CurrencyCollection, 63 | lt: u64, 64 | at: u32, 65 | body: Option, 66 | bounced: bool, 67 | ) -> Message { 68 | let mut hdr = InternalMessageHeader::with_addresses(src_addr, dst_addr, value); 69 | hdr.bounce = !bounced; 70 | hdr.bounced = bounced; 71 | hdr.ihr_disabled = true; 72 | hdr.ihr_fee = Grams::from(0u64); 73 | hdr.created_lt = lt; 74 | hdr.created_at = at.into(); 75 | let mut msg = Message::with_int_header(hdr); 76 | if let Some(body) = body { 77 | msg.set_body(body); 78 | } 79 | msg 80 | } 81 | 82 | fn sign_body(body: &mut SliceData, key_file: Option<&str>) -> Status { 83 | let mut signed_body = body.as_builder(); 84 | let mut sign_builder = BuilderData::new(); 85 | if let Some(f) = key_file { 86 | let pair = Keypair::from_file(f)?; 87 | let pub_key = pair.public.to_bytes(); 88 | let signature = 89 | ed25519_sign_with_secret(pair.private.as_bytes(), body.cell().repr_hash().as_slice())?; 90 | sign_builder.append_raw(&signature, signature.len() * 8)?; 91 | sign_builder.append_raw(&pub_key, pub_key.len() * 8)?; 92 | } 93 | signed_body.checked_prepend_reference(sign_builder.into_cell()?)?; 94 | *body = SliceData::load_cell(signed_body.into_cell()?)?; 95 | Ok(()) 96 | } 97 | 98 | fn initialize_registers( 99 | data: SliceData, 100 | mycode: Cell, 101 | myself: MsgAddressInt, 102 | unix_time: u32, 103 | balance: CurrencyCollection, 104 | config_params: Option, 105 | capabilities: u64, 106 | ) -> Result { 107 | let mut ctrls = SaveList::new(); 108 | let info = SmartContractInfo { 109 | capabilities, 110 | balance, 111 | myself: SliceData::load_cell(myself.serialize()?).unwrap(), 112 | mycode, 113 | unix_time, 114 | config_params, 115 | ..Default::default() 116 | }; 117 | // TODO info.set_init_code_hash() 118 | ctrls.put(4, &mut StackItem::Cell(data.into_cell()))?; 119 | ctrls.put(7, &mut info.into_temp_data_item())?; 120 | Ok(ctrls) 121 | } 122 | 123 | fn init_logger(debug: bool) -> Status { 124 | SimpleLogger::init( 125 | if debug { 126 | LevelFilter::Trace 127 | } else { 128 | LevelFilter::Info 129 | }, 130 | Config { 131 | time: None, 132 | level: None, 133 | target: None, 134 | location: None, 135 | time_format: None, 136 | ..Default::default() 137 | }, 138 | )?; 139 | Ok(()) 140 | } 141 | 142 | fn create_inbound_msg( 143 | selector: i32, 144 | msg_info: &MsgInfo, 145 | dst: AccountId, 146 | ) -> Result> { 147 | let (_, value) = decode_balance(msg_info.balance)?; 148 | Ok(match selector { 149 | 0 => { 150 | let src = match msg_info.src { 151 | Some(s) => MsgAddressInt::from_str(s)?, 152 | None => MsgAddressInt::with_standart(None, 0, [0u8; 32].into())?, 153 | }; 154 | Some(create_internal_msg( 155 | src, 156 | MsgAddressInt::with_standart(None, 0, dst)?, 157 | value, 158 | 1, 159 | get_now(), 160 | msg_info.body.clone(), 161 | msg_info.bounced, 162 | )) 163 | } 164 | -1 => { 165 | let src = match msg_info.src { 166 | Some(s) => MsgAddressExt::from_str(s)?, 167 | None => MsgAddressExt::with_extern(SliceData::from_raw(vec![0x55; 8], 64)) 168 | .map_err(|e| format_err!("Failed to create address: {}", e))?, 169 | }; 170 | Some(create_external_inbound_msg( 171 | src, 172 | MsgAddressInt::with_standart(None, 0, dst) 173 | .map_err(|e| format_err!("Failed to convert address: {}", e))?, 174 | msg_info.body.clone(), 175 | )) 176 | } 177 | _ => None, 178 | }) 179 | } 180 | 181 | fn decode_actions(actions: StackItem, state: &mut StateInit, action_decoder: F) -> Status 182 | where 183 | F: Fn(SliceData, bool), 184 | { 185 | if let StackItem::Cell(cell) = &actions { 186 | let actions: OutActions = OutActions::construct_from(&mut SliceData::load_cell_ref(cell)?)?; 187 | println!("Output actions:\n----------------"); 188 | for act in actions { 189 | match act { 190 | OutAction::SendMsg { mode: _, out_msg } => { 191 | println!("Action(SendMsg):\n{}", msg_printer(&out_msg)?); 192 | if let Some(b) = out_msg.body() { 193 | action_decoder(b, out_msg.is_internal()); 194 | } 195 | } 196 | OutAction::SetCode { new_code: code } => { 197 | println!("Action(SetCode)"); 198 | state.code = Some(code); 199 | } 200 | OutAction::ReserveCurrency { .. } => { 201 | println!("Action(ReserveCurrency)"); 202 | } 203 | OutAction::ChangeLibrary { .. } => { 204 | println!("Action(ChangeLibrary)"); 205 | } 206 | _ => println!("Action(Unknown)"), 207 | }; 208 | } 209 | } 210 | Ok(()) 211 | } 212 | 213 | pub fn load_code_and_data(state_init: &StateInit) -> (SliceData, SliceData) { 214 | let code: SliceData = 215 | SliceData::load_cell(state_init.code.clone().unwrap_or_default()).unwrap(); 216 | let data = SliceData::load_cell(state_init.data.clone().unwrap_or_default()).unwrap(); 217 | (code, data) 218 | } 219 | 220 | fn decode_balance(value: Option<&str>) -> Result<(u64, CurrencyCollection)> { 221 | let value = value.unwrap_or(DEFAULT_ACCOUNT_BALANCE); 222 | if let Ok(main) = value.parse::() { 223 | Ok((main, CurrencyCollection::with_grams(main))) 224 | } else { 225 | let err_msg = "invalid extra currencies"; 226 | let v: Value = 227 | serde_json::from_str(value).map_err(|e| format_err!("{}: {}", err_msg, e))?; 228 | 229 | let main = v 230 | .get("main") 231 | .and_then(|main| main.as_u64()) 232 | .ok_or_else(|| format_err!("invalid main currency"))?; 233 | 234 | let mut currencies = CurrencyCollection::with_grams(main); 235 | 236 | v.get("extra") 237 | .and_then(|extra| { 238 | extra.as_object().and_then(|extra| { 239 | for (i, val) in extra { 240 | let key = i.parse::().ok()?; 241 | let amount = val.as_u64()?; 242 | currencies 243 | .set_other(key, amount as u128) 244 | .map_err(|e| println!("Failed to update currencies: {}", e)) 245 | .unwrap_or_default(); 246 | } 247 | Some(()) 248 | }) 249 | }) 250 | .ok_or_else(|| format_err!("{}", err_msg))?; 251 | Ok((main, currencies)) 252 | } 253 | } 254 | 255 | pub struct MsgInfo<'a> { 256 | pub balance: Option<&'a str>, 257 | pub src: Option<&'a str>, 258 | pub now: u32, 259 | pub bounced: bool, 260 | pub body: Option, 261 | } 262 | 263 | pub fn load_debug_info(filename: &str) -> Option { 264 | File::open(filename) 265 | .ok() 266 | .and_then(|file| serde_json::from_reader(file).ok()) 267 | .flatten() 268 | } 269 | 270 | pub fn load_config(filename: &str) -> Option { 271 | let state = load_from_file(filename).unwrap_or_default(); 272 | let (_code, data) = load_code_and_data(&state); 273 | // config dictionary is located in the first reference of the storage root cell 274 | data.into_cell().reference(0).ok() 275 | } 276 | 277 | #[derive(PartialEq)] 278 | pub enum TraceLevel { 279 | Full, 280 | Minimal, 281 | None, 282 | } 283 | 284 | fn get_position(info: &EngineTraceInfo, debug_info: &Option) -> Option { 285 | if let Some(debug_info) = debug_info { 286 | let cell_hash = info.cmd_code.cell().repr_hash(); 287 | let offset = info.cmd_code.pos(); 288 | let position = match debug_info.get(&cell_hash) { 289 | Some(offset_map) => match offset_map.get(&offset) { 290 | Some(pos) => format!("{}:{}", pos.filename, pos.line), 291 | None => String::from("-:0 (offset not found)"), 292 | }, 293 | None => String::from("-:0 (cell hash not found)"), 294 | }; 295 | return Some(position); 296 | } 297 | None 298 | } 299 | 300 | fn trace_callback_minimal(_engine: &Engine, info: &EngineTraceInfo, debug_info: &Option) { 301 | print!( 302 | "{} {} {} {}", 303 | info.step, info.gas_used, info.gas_cmd, info.cmd_str 304 | ); 305 | let position = get_position(info, debug_info); 306 | if position.is_some() { 307 | print!(" {}", position.unwrap()); 308 | } 309 | println!(); 310 | } 311 | 312 | fn trace_callback( 313 | _engine: &Engine, 314 | info: &EngineTraceInfo, 315 | extended: bool, 316 | debug_info: &Option, 317 | ) { 318 | if info.info_type == EngineTraceInfoType::Dump { 319 | println!("{}", info.cmd_str); 320 | return; 321 | } 322 | println!("{}: {}", info.step, info.cmd_str); 323 | if extended { 324 | println!( 325 | "{} {}", 326 | info.cmd_code.remaining_bits(), 327 | info.cmd_code.to_hex_string() 328 | ); 329 | } 330 | println!("\nGas: {} ({})", info.gas_used, info.gas_cmd); 331 | let position = get_position(info, debug_info); 332 | if position.is_some() { 333 | println!("Position: {}", position.unwrap()); 334 | } 335 | println!("\n--- Stack trace ------------------------"); 336 | for item in info.stack.iter() { 337 | println!("{}", item); 338 | } 339 | println!("----------------------------------------\n"); 340 | } 341 | 342 | pub struct TestCallParams<'a, F: Fn(SliceData, bool)> { 343 | pub balance: Option<&'a str>, 344 | pub msg_info: MsgInfo<'a>, 345 | pub config: Option, 346 | pub key_file: Option>, 347 | pub ticktock: Option, 348 | pub gas_limit: Option, 349 | pub action_decoder: Option, 350 | pub trace_level: TraceLevel, 351 | pub debug_info: Option, 352 | pub capabilities: u64, 353 | } 354 | 355 | pub fn call_contract( 356 | addr: MsgAddressInt, 357 | state_init: StateInit, 358 | params: TestCallParams, 359 | ) -> Result<(i32, StateInit, bool)> 360 | where 361 | F: Fn(SliceData, bool), 362 | { 363 | let func_selector = match params.msg_info.balance { 364 | Some(_) => 0, 365 | None => { 366 | if params.ticktock.is_some() { 367 | -2 368 | } else { 369 | -1 370 | } 371 | } 372 | }; 373 | 374 | let msg = create_inbound_msg(func_selector, ¶ms.msg_info, addr.address())?; 375 | 376 | if !log_enabled!(Error) { 377 | init_logger(params.trace_level == TraceLevel::Full)?; 378 | } 379 | 380 | let mut state_init = state_init; 381 | let (code, data) = load_code_and_data(&state_init); 382 | 383 | let (smc_value, smc_balance) = decode_balance(params.balance)?; 384 | let registers = initialize_registers( 385 | data, 386 | code.clone().into_cell(), 387 | addr.clone(), 388 | params.msg_info.now, 389 | smc_balance, 390 | params.config, 391 | params.capabilities, 392 | )?; 393 | 394 | let mut stack = Stack::new(); 395 | if func_selector > -2 { 396 | let msg_cell = StackItem::Cell( 397 | msg.ok_or_else(|| format_err!("Failed to create message"))? 398 | .serialize()?, 399 | ); 400 | 401 | let mut body = params.msg_info.body.unwrap_or_default(); 402 | 403 | if func_selector == -1 { 404 | if let Some(key_file) = params.key_file { 405 | sign_body(&mut body, key_file)?; 406 | } 407 | } 408 | 409 | let msg_value = if func_selector == 0 { 410 | decode_balance(params.msg_info.balance)?.0 // for internal message 411 | } else { 412 | 0 // for external message 413 | }; 414 | 415 | stack 416 | .push(int!(smc_value)) // contract balance 417 | .push(int!(msg_value)) // msg value 418 | .push(msg_cell) // whole msg 419 | .push(StackItem::Slice(body)) // msg body 420 | .push(int!(func_selector)); //selector 421 | } else { 422 | let addr_val = addr.address().to_hex_string(); 423 | let addr_int = IntegerData::from_str_radix(&addr_val, 16)?; 424 | stack 425 | .push(int!(smc_value)) 426 | .push(StackItem::Integer(Arc::new(addr_int))) //contract address 427 | .push(int!(params.ticktock.unwrap())) //tick or tock 428 | .push(int!(func_selector)); 429 | } 430 | 431 | let gas = if let Some(gas_limit) = params.gas_limit { 432 | let mut tmp_gas = Gas::test(); 433 | tmp_gas.new_gas_limit(gas_limit); 434 | tmp_gas 435 | } else { 436 | Gas::test() 437 | }; 438 | 439 | let library_map = HashmapE::with_hashmap(256, state_init.library.root().cloned()); 440 | 441 | println!("Engine capabilities: {}", params.capabilities); 442 | let mut engine = Engine::with_capabilities(params.capabilities).setup_with_libraries( 443 | code, 444 | Some(registers), 445 | Some(stack), 446 | Some(gas), 447 | vec![library_map], 448 | ); 449 | engine.set_trace(0); 450 | let debug_info = params.debug_info; 451 | match params.trace_level { 452 | TraceLevel::Full => engine.set_trace_callback(move |engine, info| { 453 | trace_callback(engine, info, true, &debug_info); 454 | }), 455 | TraceLevel::Minimal => engine.set_trace_callback(move |engine, info| { 456 | trace_callback_minimal(engine, info, &debug_info); 457 | }), 458 | TraceLevel::None => {} 459 | } 460 | let exit_code = engine.execute().unwrap_or_else(|exc| match tvm_exception(exc) { 461 | Ok(exc) => { 462 | println!("Unhandled exception: {}", exc); 463 | exc.exception_or_custom_code() 464 | } 465 | _ => -1, 466 | }); 467 | 468 | let is_vm_success = engine.get_committed_state().is_committed(); 469 | println!("TVM terminated with exit code {}", exit_code); 470 | println!("Computing phase is success: {}", is_vm_success); 471 | println!("Gas used: {}", engine.get_gas().get_gas_used()); 472 | println!(); 473 | println!("{}", engine.dump_stack("Post-execution stack state", false)); 474 | println!("{}", engine.dump_ctrls(false)); 475 | 476 | if is_vm_success { 477 | if let Some(decoder) = params.action_decoder { 478 | decode_actions(engine.get_actions(), &mut state_init, decoder)?; 479 | } 480 | 481 | state_init.data = match engine.get_committed_state().get_root() { 482 | StackItem::Cell(root_cell) => Some(root_cell.clone()), 483 | _ => panic!("cannot get root data: c4 register is not a cell."), 484 | }; 485 | } 486 | 487 | Ok((exit_code, state_init, is_vm_success)) 488 | } 489 | 490 | #[cfg(test)] 491 | mod tests { 492 | use super::*; 493 | 494 | fn create_inbound_body(a: i32, b: i32, func_id: i32) -> Result { 495 | let mut builder = BuilderData::new(); 496 | let version: u8 = 0; 497 | version.write_to(&mut builder)?; 498 | func_id.write_to(&mut builder)?; 499 | a.write_to(&mut builder)?; 500 | b.write_to(&mut builder)?; 501 | builder.into_cell() 502 | } 503 | 504 | #[test] 505 | fn test_msg_print() { 506 | let msg = create_external_inbound_msg( 507 | MsgAddressExt::with_extern(SliceData::from_raw(vec![0x55; 8], 64)).unwrap(), 508 | MsgAddressInt::with_standart(None, 0, [0x11; 32].into()).unwrap(), 509 | Some(SliceData::load_cell(create_inbound_body(10, 20, 0x11223344).unwrap()).unwrap()), 510 | ); 511 | 512 | let _msg2 = create_internal_msg( 513 | MsgAddressInt::with_standart(None, 0, [0x11; 32].into()).unwrap(), 514 | MsgAddressInt::with_standart(None, 0, [0x22; 32].into()).unwrap(), 515 | CurrencyCollection::with_grams(12345678), 516 | 1, 517 | 2, 518 | None, 519 | false, 520 | ); 521 | 522 | println!( 523 | "SendMsg action:\n{}", 524 | msg_printer(&msg).unwrap_or("Undefined".to_string()) 525 | ); 526 | println!( 527 | "SendMsg action:\n{}", 528 | msg_printer(&msg).unwrap_or("Undefined".to_string()) 529 | ); 530 | } 531 | 532 | #[test] 533 | fn test_decode_balance() { 534 | let (main, balance) = 535 | decode_balance(Some(r#"{ "main": 100, "extra": {"0": 33, "50": 99} }"#)).unwrap(); 536 | assert_eq!(main, 100); 537 | let mut expected_balance = CurrencyCollection::with_grams(100); 538 | expected_balance.set_other(0, 33).unwrap(); 539 | expected_balance.set_other(50, 99).unwrap(); 540 | assert_eq!(balance, expected_balance); 541 | 542 | let (main, balance) = decode_balance(Some("101")).unwrap(); 543 | assert_eq!(main, 101); 544 | assert_eq!(balance, CurrencyCollection::with_grams(101)); 545 | } 546 | 547 | #[test] 548 | fn test_decode_balance_default() { 549 | let (main, balance) = decode_balance(None).unwrap(); 550 | let expected = DEFAULT_ACCOUNT_BALANCE.parse::().unwrap(); 551 | assert_eq!(main, expected); 552 | assert_eq!(balance, CurrencyCollection::with_grams(expected)); 553 | } 554 | 555 | #[test] 556 | fn test_decode_balance_invalid() { 557 | let err = decode_balance(Some(r#"{ "main": 100 }"#)); 558 | assert!(err.is_err()); 559 | 560 | let err = decode_balance(Some(r#"{ "main": qwe }"#)); 561 | assert!(err.is_err()); 562 | 563 | let err = decode_balance(Some(r#"{ "main": 0, extra: {"dd": 10} }"#)); 564 | assert!(err.is_err()); 565 | 566 | let err = decode_balance(Some(r#"{ "main": 0, extra: {"0": qwe} }"#)); 567 | assert!(err.is_err()); 568 | } 569 | } 570 | --------------------------------------------------------------------------------