diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82aece6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/target/ +.soroban +.env \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..11fdd29 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1749 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" + +[[package]] +name = "async-trait" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base32" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + +[[package]] +name = "cc" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "serde", + "time 0.1.45", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "chrono-tz" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crate-git-revision" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f998aef136a4e7833b0e4f0fc0939a59c40140b28e0ffbf524ad84fb2cc568c8" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cxx" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "darling" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dyn-fmt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a0836c9bd73a9d3ca55b0effc5b1eedf96dd13ef994389bcac6d4d33c46188" + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "erased-serde" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ca605381c017ec7a5fef5e548f1cfaa419ed0f6df6367339300db74c92aa7d" +dependencies = [ + "serde", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", + "serde", +] + +[[package]] +name = "indexmap-nostd" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jwt-compact" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bcc576baa96136028d34d45ab5c840d146235a4c37c87d96237d05fea222194" +dependencies = [ + "anyhow", + "base64ct", + "chrono", + "hmac", + "rand_core 0.6.4", + "serde", + "serde_cbor", + "serde_json", + "sha2 0.10.6", + "smallvec", + "subtle", + "zeroize", +] + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "matchit" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9376a4f0340565ad675d11fc1419227faf5f60cd7ac9cb2e7185a471f30af833" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.30.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "phf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +dependencies = [ + "siphasher", + "uncased", +] + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "scratch" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap", + "serde", + "serde_json", + "serde_with_macros", + "time 0.3.17", +] + +[[package]] +name = "serde_with_macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.9.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "soroban-asteroids-wrangler" +version = "0.0.0" +dependencies = [ + "base64 0.21.0", + "cfg-if 0.1.10", + "chrono", + "console_error_panic_hook", + "ed25519-dalek", + "erased-serde", + "hex", + "jwt-compact", + "serde", + "serde_json", + "serde_yaml", + "sha2 0.10.6", + "soroban-env-host", + "soroban-ledger-snapshot", + "soroban-spec", + "stellar-strkey", + "thiserror", + "time 0.1.45", + "wasmparser 0.90.0", + "worker", +] + +[[package]] +name = "soroban-env-common" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28be0b49003d163d32164528aa37e6c45f0af24e2dfc27a1beb2832e0893d56b" +dependencies = [ + "crate-git-revision", + "serde", + "soroban-env-macros", + "soroban-wasmi", + "static_assertions", + "stellar-xdr", +] + +[[package]] +name = "soroban-env-host" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c687a3a9a772816ed604ef2551e8377071cec343729ffe0b43dae13ae1280fdf" +dependencies = [ + "backtrace", + "curve25519-dalek", + "dyn-fmt", + "ed25519-dalek", + "hex", + "log", + "num-derive", + "num-integer", + "num-traits", + "sha2 0.10.6", + "soroban-env-common", + "soroban-native-sdk-macros", + "soroban-wasmi", + "static_assertions", + "tinyvec", +] + +[[package]] +name = "soroban-env-macros" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f8a0b12e9345e0527c2fa82a32869080b02b3d320f25693fb7a040956bac67" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "serde", + "serde_json", + "stellar-xdr", + "syn", + "thiserror", +] + +[[package]] +name = "soroban-ledger-snapshot" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb84883d0beae1ed63812d51ad15a9b2d0a88e884f72ee8f519645ce507e3de4" +dependencies = [ + "serde", + "serde_json", + "soroban-env-host", + "thiserror", +] + +[[package]] +name = "soroban-native-sdk-macros" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6ec8239376e09d710f4dd79448dc07b27111a49e264386c5d12cbdc43951cb" +dependencies = [ + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "soroban-spec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8861bfce88ccfc4694f2ad6774f4ff929f8cc61d8b2ed5c5f4e9fa98a375aa60" +dependencies = [ + "base64 0.13.1", + "darling", + "itertools", + "prettyplease", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha2 0.10.6", + "stellar-xdr", + "syn", + "thiserror", + "wasmparser 0.88.0", +] + +[[package]] +name = "soroban-wasmi" +version = "0.16.0-soroban2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc5dca8b60607a73948635d1b47f01986ca5b5a18c1a7ec22f6fda8a400dd360" +dependencies = [ + "soroban-wasmi_core", + "spin", + "wasmparser-nostd", +] + +[[package]] +name = "soroban-wasmi_core" +version = "0.16.0-soroban2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58caebfe0ad5e6d35c72f4894188d2ef9d6b01a6b67dadda2baf5700a322e453" +dependencies = [ + "downcast-rs", + "libm", + "memory_units", + "num-rational", + "num-traits", +] + +[[package]] +name = "spin" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stellar-strkey" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0689070126ca7f2effc2c5726584446db52190f0cef043c02eb4040a711c11" +dependencies = [ + "base32", + "thiserror", +] + +[[package]] +name = "stellar-xdr" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940dc58ca70e647b0b2517461beb3476fbffa5dc78d10f5c53645da8503c765c" +dependencies = [ + "base64 0.13.1", + "crate-git-revision", + "hex", + "serde", + "serde_with", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uncased" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if 1.0.0", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "wasm-streams" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.88.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8cf7dd82407fe68161bedcd57fde15596f32ebf6e9b3bdbf3ae1da20e38e5e" +dependencies = [ + "indexmap", +] + +[[package]] +name = "wasmparser" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62c8d843f4423efee314dc75a1049886deba3214f7e7f9ff0e4e58b4d618581" +dependencies = [ + "indexmap", +] + +[[package]] +name = "wasmparser-nostd" +version = "0.90.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a94fbf4c521b038f41382df2056cf47099d3b7a0faa5a6e46f7771fd7c84a6" +dependencies = [ + "indexmap-nostd", +] + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "worker" +version = "0.0.12" +source = "git+https://github.com/FlareLine/workers-rs.git?rev=c725fcb#c725fcb3e02dd1410a692fc27368683a50f7b0ff" +dependencies = [ + "async-trait", + "chrono", + "chrono-tz", + "futures-channel", + "futures-util", + "http", + "js-sys", + "matchit", + "pin-project", + "serde", + "serde-wasm-bindgen", + "serde_json", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "worker-kv", + "worker-macros", + "worker-sys", +] + +[[package]] +name = "worker-kv" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "682cbd728f179cc810b2ab77a2534da817b973e190ab184ab8efe1058b0dba84" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "worker-macros" +version = "0.0.6" +source = "git+https://github.com/FlareLine/workers-rs.git?rev=c725fcb#c725fcb3e02dd1410a692fc27368683a50f7b0ff" +dependencies = [ + "async-trait", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-macro-support", + "worker-sys", +] + +[[package]] +name = "worker-sys" +version = "0.0.6" +source = "git+https://github.com/FlareLine/workers-rs.git?rev=c725fcb#c725fcb3e02dd1410a692fc27368683a50f7b0ff" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b24dc5a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,41 @@ +[workspace] +resolver = "2" + +members = [ + "wrangler", +] + +[profile.release-with-logs] +inherits = "release" +debug-assertions = true + +[profile.release] +opt-level = "z" +overflow-checks = true +debug = 0 +strip = "symbols" +debug-assertions = false +panic = "abort" +codegen-units = 1 +lto = true + +[workspace.dependencies] +rand = { version = "0.8.5", default-features = false, features = ["small_rng"] } + +[workspace.dependencies.stellar-xdr] +version = "0.0.14" + +[workspace.dependencies.soroban-env-host] +version = "0.0.14" + +[workspace.dependencies.soroban-spec] +version = "0.6.0" + +[workspace.dependencies.soroban-sdk] +version = "0.6.0" + +[workspace.dependencies.soroban-ledger-snapshot] +version = "0.6.0" + +[workspace.dependencies.stellar-strkey] +version = "0.0.7" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8de6d88 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 Stellar Development Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..141c8ab --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +all: clean build + +install_wasm_opt: + cargo install wasm-opt + +build: install_worker_build + cd wrangler; worker-build --release + +install_worker_build: +# this version has a bug fix we require https://github.com/cloudflare/workers-rs/issues/255 + cargo install --git https://github.com/Smephite/workers-rs.git + +local: build + cd wrangler; wrangler dev --local + +dev: build + cd wrangler; wrangler dev + +clean: + cargo clean + +fmt: + cargo fmt --all \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7e621b4 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Fast, Cheap & Out of Control diff --git a/game_engine.wasm b/game_engine.wasm new file mode 100644 index 0000000..6a70354 Binary files /dev/null and b/game_engine.wasm differ diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..e340b76 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "stable" +targets = ["wasm32-unknown-unknown"] +components = ["rustc", "cargo", "rustfmt", "clippy", "rust-src"] diff --git a/wrangler/.dev.vars b/wrangler/.dev.vars new file mode 100644 index 0000000..e70b06d --- /dev/null +++ b/wrangler/.dev.vars @@ -0,0 +1,3 @@ +JWT_SECRET=FCA00C_JWT +ENVIRONMENT=local +ASTEROIDS_SEED=8891 \ No newline at end of file diff --git a/wrangler/.gitignore b/wrangler/.gitignore new file mode 100644 index 0000000..1d223ce --- /dev/null +++ b/wrangler/.gitignore @@ -0,0 +1,7 @@ +/target +**/*.rs.bk +wasm-pack.log +build/ +dist/ +node_module/ +*.db diff --git a/wrangler/Cargo.toml b/wrangler/Cargo.toml new file mode 100644 index 0000000..2e5ecb7 --- /dev/null +++ b/wrangler/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "soroban-asteroids-wrangler" +version = "0.0.0" +license-file = "../LICENSE" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["console_error_panic_hook"] + +[dependencies] +cfg-if = "0.1.2" +serde_json = "1.0.67" +serde = "1.0.152" +serde_yaml = "0.9.17" +jwt-compact = "0.6.0" +time = "0.1.45" +erased-serde = "0.3.24" +chrono = "0.4.23" +base64 = "0.21.0" +worker = { git = "https://github.com/FlareLine/workers-rs.git", rev = 'c725fcb', features = ['d1'] } + +ed25519-dalek = "1.0.1" +wasmparser = "0.90.0" +hex = "0.4.3" +sha2 = "0.10.6" +thiserror = "1.0.31" + +soroban-env-host = { workspace = true, features = ["vm", "serde", "hostfn_log_fmt_values"]} +soroban-spec = { workspace = true } +soroban-ledger-snapshot = { workspace = true } +stellar-strkey = { workspace = true } + +# The `console_error_panic_hook` crate provides better debugging of panics by +# logging them with `console.error`. This is great for development, but requires +# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for +# code size when deploying. +console_error_panic_hook = { version = "0.1.1", optional = true } \ No newline at end of file diff --git a/wrangler/LICENSE b/wrangler/LICENSE new file mode 100644 index 0000000..8de6d88 --- /dev/null +++ b/wrangler/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2023 Stellar Development Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/wrangler/README.md b/wrangler/README.md new file mode 100644 index 0000000..98cda56 --- /dev/null +++ b/wrangler/README.md @@ -0,0 +1,236 @@ +# FCA00C Wrangler +This wrangler will host the backend for the FCA00C challenges. +It exposes endpoints where users can submit solutions, get personal stats and the global leaderboard. + +When a user submits a solution a local `soroban-host-env` is spun up in which the uploaded WASM is sandboxed and executed. + +## Running locally +As the wrangler is written in rust we need to have the rust toolchain as well as cargo installed. + +The wrangler utilizes a `build.rs` to automatically source all required dependency which are given as `WASM` and includes them as handy constants in the +`fca00c:embedded:contracts` package. +It will also embed all html files given in `html/` as `fc00c:embedded:html`. + +The wrangler depends on the different dependencies being located in the `{parent}/target/wasm32-unknown-unknown` directory, it is necessary to firstly compile +all required depenencies (e.g. `soroban-asteroids-game-engine`). +To do this automatically run `make all` in `{parent}`. + +To compile the rust code into a wrangler readable format we need to have `worker-build` installed. +The instlalation of this binary is already included in the `make all` script. +Alternativy we could do this manually using `cargo install worker-build`. + +NOTE: We are actually using a modifiled version as this bug is annoying https://github.com/cloudflare/workers-rs/pull/256 +So just use the Makefile... + +After we set up everything (by just running `make all`) we are able to deploy the wrangler using the default `wrangler` cli when located in the `{parent}/wrangler` subdirectory: + +``` +wrangler dev --local # Run locally with _everything_ local. (miniflare) +wrangler dev # Run with online dev D1 and KV +``` + +Note: It seems than when running using the `--local` flag no data is retained between calls, thus endpoints like the leaderboard will always appear empty. + +## API Endpoints + +In general: + +TaksID: +| ID | Name | +|----|-----------| +| 0 | Asteroids | + +BucketID: + +| ID | Description | +|----|---------------------------------------| +| 0 | Fastest Submission | +| 1 | Lowest WASM size (smallest) | +| 2 | Lowest Resources [CPU/MEM] (cheapest) | + +All endpoints return either `200`, `400`, `401`, `404`, `419`, or `500`. +If the result is not `200`: the field `message` will contain further information. + +### POST `/submit?task=` +This endpoint requires authorization. + +The parameter `task` is as defined above. + +The body of this request must contain the soroban contract to be submitted in WASM format. +The body is to be submitted as binary blob. + +If successful (200): +```json +{ + "message": "Successfully completed challenge.", + "status": 200, + "opt": { + "improvement": [ + false, + true, + false + ], + "live": [ + true, + true, + true + ], + "submission": { + "mem": 33006915, + "cpu": 605964886, + "size": 4786, + "submission_time": 1675978724893, + "interface_version": 27 + } +} +``` + +The `opt.submission` object contains the raw information about the submission. + +The `opt.live` field shows if the submission is eligible for potential rewards during the live quest for each bucket. + +The `opt.improvement` contains information if the solution submitted was an improvement compared to a user's previous submission. +The array index corresponds to the bucket id. +A users initial submission will always return `[false, false, false]` (i.e. the initial submission is not an improvement). + +If already submitted solution recently (429): +```json +{ + "message": "User has already submitted a solution to this task in the last 60 seconds", + "status": 419, + "opt": 54 +} +``` +The `opt` field shows how many seconds need to pass until the user may submit a new solution to said (task, bucket) tuple. + +The `opt` map contains the raw data used to evaluate the submission. +`submission_time` is given as UNIX-millis. +Other parameters are given as returned by the soroban environment. + +### GET `/leaderboard?task=&bucket=&limit=&live=` +The parameters `live` and `limit` are all optional. +If not specified `limit` will default to `50`. +If not specified `live` will default to `false` + +Authentication is optional and will allow to determine if a leaderboard entry belongs to the authenticated user. + +`task`, `bucket` and `live` are used to filter the leaderboard results. + +`task` and `bucket` are as defined above. +`live` will filter for submission done during the 'live' phase of the task. + + +The result will be of the form `[LeaderboardEntry]` (`Vec`). + +`LeaderboardEntry` consists of: + +| Field | Type | Description | +|-------------------|----------------|-----------------------------------------------------------------------------| +| bucket_id | int | As defined above | +| task_id | int | As defined above | +| CPU | int | CPU metric as returned by soroban | +| MEM | int | CPU metric as returned by soroban | +| SIZE | int | WASM size in bytes | +| submission_date | int | date submitted in UNIX-millis | +| interface_version | int | soroban version submission was made with | +| rank | int | Rank of submission in given bucket; Starting at 1 | +| display | string \| null | Displayname of user if set; `null` if anonymous | +| anon_index | int \| null | Unique identifier to each anonymous account `null` if `display` is set | +| profile_url | string \| null | Profile URL of user if set; `null` if none | +| live | bool | `true` if submitted while quest was live | +| improved | bool | `true` if this was at least the 2nd submission, improving the initial one | +| me | bool | `true` auth header was set and this entry belongs to the authenticated user | + + +Note: The array index of any given entry in any given task/bucket entry does not necessarily correspond to their rank! (If user is authenticated but not ranked within `limit` they will appear in the array at index `limit+1` but their `rank` may be different.) + +```json +[ + { + "bucket_id": 0, + "task_id": 0, + "CPU": 611943909, + "MEM": 39894755, + "SIZE": 4786, + "submission_date": 1675177622546, + "interface_version": 27, + "rank": 1, + "anon_index": 5, + "display": null, + "profile_url": null, + "live": true, + "improved": false, + "me" : false + }, + { + "bucket_id": 0, + "task_id": 0, + "CPU": 1090785050, + "MEM": 66043230, + "SIZE": 5044, + "submission_date": 1675380354090, + "interface_version": 27, + "rank": 2, + "anon_index": 6, + "display": null, + "profile_url": null, + "live": true, + "improved": false, + "me": true + }, + { + "bucket_id": 0, + "task_id": 0, + "CPU": 393119176, + "MEM": 15825415, + "SIZE": 806, + "submission_date": 1675391611277, + "interface_version": 27, + "rank": 3, + "anon_index": 7, + "display": "Hello world", + "profile_url": "https://stellar.org", + "live": true, + "improved": false, + "me": false + } +] +``` + +### GET `/personal?task=&bucket=&live=` +Required authorization. + +`live` is optional and used to filter the leaderboard results. If not specified no filtering will occur. + +`task` and `bucket` are as defined above. +`live` will filter for submission done during the 'live' phase of the task. + +This endpoint will return only the personal positions in the leaderboard. + +The structure of the result will be a single `LeaderboardEntry` as defined above. +```json +{ + "bucket_id": 0, + "task_id": 0, + "CPU": 1090785050, + "MEM": 66043230, + "SIZE": 5044, + "submission_date": 1675380354090, + "interface_version": 27, + "rank": 2, + "anon_index": 0, + "display": null, + "profile_url": null, + "live": true, + "improved": false, + "me" : true +} +``` +NOTE: In the `/personal` endpoint `me` will always be true. + +## Structure +The `lib.rs` is the handler of the incoming worker request and delegates it to the coresponding function in `fca00c:router`. +If the function is `submit` it will take the given taksID and look up the verify function to execute within the `fca00c:mod.rs` +Tasks are registered modually such that the package `fca00c:tasks:` will include all checks required for each task. +A new task may be registered by implementing the trait `fca00c:tasks:Task` for any struct (typically just a `pub struct TaskName;`). +To register a task add it to the `setup` function in `fca00c:tasks:mod.rs`. diff --git a/wrangler/build.rs b/wrangler/build.rs new file mode 100644 index 0000000..3aa64b9 --- /dev/null +++ b/wrangler/build.rs @@ -0,0 +1,66 @@ +use std::{ + env, + fs::{self, OpenOptions}, + io::Write, + path::Path, +}; + +const WASM_PATH: &str = "../"; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + delete_old(); + + embedd_contract("ASTEROIDS_ENGINE", "game_engine.wasm"); +} + +fn delete_old() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + let contracts_path = Path::new(&out_dir).join("embedded_contracts.rs"); + let html_path = Path::new(&out_dir).join("embedded_html.rs"); + let _ = fs::remove_file(contracts_path); + let _ = fs::remove_file(html_path); +} + +fn embedd_contract(var_name: &str, wasm_file_name: &str) { + let wasm_path = Path::new(&WASM_PATH).join(wasm_file_name); + + println!("cargo:rerun-if-changed={wasm_path:?}"); + + let out_dir = env::var_os("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("embedded_contracts.rs"); + + let raw_wasm = fs::read(&wasm_path); + + if let Err(e) = raw_wasm { + eprintln!("Error reading WASM file {wasm_path:?}! {e:?}"); + } else if let Ok(wasm) = raw_wasm { + let wasm_as_string = wasm + .clone() + .into_iter() + .map(|i| format!("0x{i:X},")) + .collect::(); + + let new_line = format!( + "pub const {} : [u8; {}] = [{}];", + var_name, + wasm.len(), + wasm_as_string + ); + + //mkdirs + if !dest_path.exists() { + let _ = fs::write(&dest_path, ""); + } + + let mut file = OpenOptions::new() + .write(true) + .append(true) + .open(&dest_path) + .unwrap(); + if let Err(e) = writeln!(file, "{new_line}") { + eprintln!("Failed to embed {wasm_file_name} from wasm! {e:?}"); + } + } +} diff --git a/wrangler/src/fca00c/embedded.rs b/wrangler/src/fca00c/embedded.rs new file mode 100644 index 0000000..ad191df --- /dev/null +++ b/wrangler/src/fca00c/embedded.rs @@ -0,0 +1,4 @@ +// The content of these two mods is created on compile time (build.rs) +pub mod contracts { + include!(concat!(env!("OUT_DIR"), "/embedded_contracts.rs")); +} diff --git a/wrangler/src/fca00c/mod.rs b/wrangler/src/fca00c/mod.rs new file mode 100644 index 0000000..c78ca9f --- /dev/null +++ b/wrangler/src/fca00c/mod.rs @@ -0,0 +1,28 @@ +use std::collections::HashMap; + +use self::tasks::Task; + +pub mod embedded; +pub mod routes; + +pub mod response; +pub mod tasks; +#[derive(Default, Clone)] +pub struct TaskRegistry<'a> { + map: HashMap, + pub debug: bool, +} + +impl<'a> TaskRegistry<'a> { + pub fn register_task(&mut self, task_id: u64, task: &'a dyn Task) { + self.map.insert(task_id, task); + } + + pub fn get_task(&self, task_id: &u64) -> Option<&dyn Task> { + self.map.get(task_id).copied() + } +} + +pub fn setup(reg: &mut TaskRegistry) { + tasks::setup(reg); +} diff --git a/wrangler/src/fca00c/output.rs b/wrangler/src/fca00c/output.rs new file mode 100644 index 0000000..78cc888 --- /dev/null +++ b/wrangler/src/fca00c/output.rs @@ -0,0 +1,42 @@ +use serde::Serialize; + +pub type BasicJsonResponse = JsonResponse; + +#[derive(Debug, Serialize)] +pub struct JsonResponse +where + T: Serialize, + K: Serialize, +{ + message: T, + status: u16, + opt: Option, +} + +impl JsonResponse { + pub fn new(message: T, status: u16) -> Self { + Self { + message, + status, + opt: None, + } + } + + pub fn with_opt(mut self, opt: K) -> Self { + self.opt = Some(opt); + self + } +} + +impl From> for worker::Result { + fn from(value: JsonResponse) -> Self { + Ok(worker::Response::from_json(&value)?.with_status(value.status)) + } +} + +impl TryFrom> for worker::Response { + type Error = worker::Error; + fn try_from(value: JsonResponse) -> Result { + Ok(worker::Response::from_json(&value)?.with_status(value.status)) + } +} diff --git a/wrangler/src/fca00c/response.rs b/wrangler/src/fca00c/response.rs new file mode 100644 index 0000000..78cc888 --- /dev/null +++ b/wrangler/src/fca00c/response.rs @@ -0,0 +1,42 @@ +use serde::Serialize; + +pub type BasicJsonResponse = JsonResponse; + +#[derive(Debug, Serialize)] +pub struct JsonResponse +where + T: Serialize, + K: Serialize, +{ + message: T, + status: u16, + opt: Option, +} + +impl JsonResponse { + pub fn new(message: T, status: u16) -> Self { + Self { + message, + status, + opt: None, + } + } + + pub fn with_opt(mut self, opt: K) -> Self { + self.opt = Some(opt); + self + } +} + +impl From> for worker::Result { + fn from(value: JsonResponse) -> Self { + Ok(worker::Response::from_json(&value)?.with_status(value.status)) + } +} + +impl TryFrom> for worker::Response { + type Error = worker::Error; + fn try_from(value: JsonResponse) -> Result { + Ok(worker::Response::from_json(&value)?.with_status(value.status)) + } +} diff --git a/wrangler/src/fca00c/routes/mod.rs b/wrangler/src/fca00c/routes/mod.rs new file mode 100644 index 0000000..ebe0c42 --- /dev/null +++ b/wrangler/src/fca00c/routes/mod.rs @@ -0,0 +1 @@ +pub mod submit; \ No newline at end of file diff --git a/wrangler/src/fca00c/routes/submit.rs b/wrangler/src/fca00c/routes/submit.rs new file mode 100644 index 0000000..08c4d3c --- /dev/null +++ b/wrangler/src/fca00c/routes/submit.rs @@ -0,0 +1,78 @@ +use std::collections::HashMap; + +use crate::{ + fca00c::{ + response::{BasicJsonResponse, JsonResponse}, + tasks::TaskResult, + TaskRegistry, + }, + utils::Flatten, +}; +use serde::Serialize; +use worker::{Request, Response, RouteContext}; + +pub async fn handle( + mut req: Request, + ctx: RouteContext>, +) -> Result { + // extract task + let get_query: HashMap<_, _> = req.url()?.query_pairs().into_owned().collect(); + + let task = get_query + .get("task") + .and_then(|b| b.parse::().flatten()); + + if task.is_none() { + return BasicJsonResponse::new("No integer value specified for `task`", 400).into(); + } + + let task = task.unwrap(); + let task_impl = ctx.data.get_task(&task); + + let incoming_raw = req.bytes().await; + + if incoming_raw.is_err() { + return BasicJsonResponse::new("Error reading submitted data in body", 400).into(); + }; + + let data = incoming_raw.unwrap(); + + // validate WASM magic word + if data.len() <= 4 + || !(data[0] == 0x00 && data[1] == 0x61 && data[2] == 0x73 && data[3] == 0x6d) + { + return BasicJsonResponse::new("Submitted data does not contain valid WASM code", 400) + .into(); + } + + // validate task + let task_impl = task_impl.unwrap(); + + let result = task_impl.solve(&data, &req, &ctx); + + if let Err(err) = result { + return err; + } + + let result = result.unwrap(); + + if let Some(result) = result { + #[derive(Serialize)] + struct Resp { + submission: TaskResult, + } + + // task completed sucessfully + return JsonResponse::new("Successfully completed challenge", 200) + .with_opt(Resp { + submission: result, + }) + .into(); + } + + BasicJsonResponse::new( + "Successfully completed challenge. Data was not stored", + 200, + ) + .into() +} diff --git a/wrangler/src/fca00c/tasks/asteroids.rs b/wrangler/src/fca00c/tasks/asteroids.rs new file mode 100644 index 0000000..02e875e --- /dev/null +++ b/wrangler/src/fca00c/tasks/asteroids.rs @@ -0,0 +1,174 @@ +use soroban_env_host::{ + budget::Budget, + xdr::{ScVal, WriteXdr}, +}; +use worker::{Request, Response, RouteContext}; + +use crate::{ + fca00c::{ + embedded::contracts, + response::{BasicJsonResponse, JsonResponse}, + TaskRegistry, + }, + soroban::{ + helpers::{contract_id, ScValHelper}, + soroban_env_utils, soroban_vm, + }, +}; + +use super::TaskResult; +use base64::Engine as _; + +pub struct Asteroids; + +impl super::Task for Asteroids { + fn solve( + &self, + raw_wasm: &[u8], + _: &Request, + ctx: &RouteContext>, + ) -> Result, Result> { + let exec_time = chrono::Utc::now().timestamp_millis(); + let engine_id = contract_id!(0); + + let mut state = soroban_env_utils::empty_ledger_snapshot(); + let deploy_engine_result = + soroban_vm::deploy(&contracts::ASTEROIDS_ENGINE, &engine_id, &mut state); + + if deploy_engine_result.is_err() { + return Err(BasicJsonResponse::new("Error deploying game engine contract", 500).into()); + } + + let seed = ctx + .env + .var("ASTEROIDS_SEED") + .map(|b| b.to_string().parse::().ok()) + .unwrap_or(None); + + if seed.is_none() { + return Err(BasicJsonResponse::new( + "Failed to initialize game engine contract: No or invalid seed was set!", + 500, + ) + .into()); + } + + // engine.rs is defines init(..) as: + // move_step: u32, + // laser_range: u32, + // seed: u64, + // view_range: u32, + // fuel: (u32, u32, u32, u32), + // asteroid_reward: u32, + // asteroid_density: u32, + // pod_density: u32, + + let engine_init_args: Vec = vec![ + 1u32.into(), + 3u32.into(), + seed.into(), + 16u32.into(), + // the unwrap() here is not nice but it _should_ work + // tuples are stored as ScVecs + ScValHelper::try_from(vec![50u32, 5u32, 2u32, 1u32]) + .unwrap() + .into(), + 1u32.into(), + 6u32.into(), + 2u32.into(), + ]; + + let engine_init_result = + soroban_vm::invoke(&engine_id, "init", &engine_init_args, &mut state); + + if let Err(e) = engine_init_result { + return Err(JsonResponse::new("Failed to initialize game engine", 500) + .with_opt(e.to_string()) + .into()); + } + + let solution_id = contract_id!(1); + + let solution_deploy_result = soroban_vm::deploy(raw_wasm, &solution_id, &mut state); + + if let Err(e) = solution_deploy_result { + return Err(JsonResponse::new("Failed to deploy user contract", 500) + .with_opt(e.to_string()) + .into()); + } + + let cpu_limit: u64 = ctx + .env + .var("SOROBAN_CPU_BUDGET") + .map(|b| b.to_string().parse::().ok()) + .unwrap_or(None) + .unwrap_or(u64::MAX); + + let advanced_budget = Budget::default(); + advanced_budget.reset_limits(cpu_limit, u64::MAX); + //advanced_budget.reset_unlimited(); + + let solution_solve_result = soroban_vm::invoke_with_budget( + &solution_id, + "solve", + &[ScValHelper::from(engine_id).into()], + &mut state, + Some(advanced_budget), + ); + + if let Err(e) = solution_solve_result { + let msg = e.to_string(); + + if msg.contains("LimitExceeded") { + // over the budgt + return Err(BasicJsonResponse::new("User contract exceeded budget", 400).into()); + } + + // This error is most likely the users fault... + return Err( + JsonResponse::new("Failed to call solve on user contract", 400) + .with_opt(e.to_string()) + .into(), + ); + } + let (_user_solve_result, (_user_solve_storage, user_solve_budget, _user_solve_events)) = + solution_solve_result.unwrap(); + + let points_req = soroban_vm::invoke(&engine_id, "p_points", &[], &mut state).unwrap(); + let fuel_req = soroban_vm::invoke(&engine_id, "p_fuel", &[], &mut state).unwrap(); + let pos_req = soroban_vm::invoke(&engine_id, "p_pos", &[], &mut state).unwrap(); + + let cpu_count = user_solve_budget.get_cpu_insns_count(); + let mem_count = user_solve_budget.get_mem_bytes_count(); + + if let ScVal::U32(i) = points_req.0 { + if i < 100u32 { + return Err(BasicJsonResponse::new( + "User did not solve challenge! (points!=100)", + 400, + ) + .into()); + } + } else { + return Err(BasicJsonResponse::new("Unable to parse final score!", 500).into()); + } + + let mut results = vec![]; + + for val in vec![_user_solve_result, points_req.0, fuel_req.0, pos_req.0] { + let mut buf = Vec::new(); + let _ = val.write_xdr(&mut buf); + results.push(base64::engine::general_purpose::STANDARD.encode(&buf)); + } + + Ok(Some(TaskResult { + mem: mem_count, + cpu: cpu_count, + size: raw_wasm.len() as u64, + submission_time: exec_time, + result_xdr: results, + opt: vec![], + interface_version: soroban_env_host::meta::INTERFACE_VERSION, // TODO, + })) + } +} diff --git a/wrangler/src/fca00c/tasks/mod.rs b/wrangler/src/fca00c/tasks/mod.rs new file mode 100644 index 0000000..aaf30bc --- /dev/null +++ b/wrangler/src/fca00c/tasks/mod.rs @@ -0,0 +1,35 @@ +pub mod asteroids; + +use serde::{Deserialize, Serialize}; +use worker::{Request, Response, RouteContext}; + +use self::asteroids::Asteroids; + +use super::TaskRegistry; + +pub fn setup(reg: &mut TaskRegistry) { + // register future tasks here! + reg.register_task(0, &Asteroids); +} + +pub trait Task { + fn solve( + &self, + raw_wasm: &[u8], + req: &Request, + ctx: &RouteContext>, + ) -> Result, Result>; +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +pub struct TaskResult { + pub mem: u64, + pub cpu: u64, + pub size: u64, + pub submission_time: i64, + pub interface_version: u64, + #[serde(skip)] + pub result_xdr: Vec, + #[serde(skip)] + pub opt: Vec, +} diff --git a/wrangler/src/lib.rs b/wrangler/src/lib.rs new file mode 100644 index 0000000..e63b89d --- /dev/null +++ b/wrangler/src/lib.rs @@ -0,0 +1,49 @@ +use fca00c::TaskRegistry; +use worker::{console_log, event, Cors, Date, Env, Method, Request, Response, Result, Router}; + +mod fca00c; +mod soroban; +mod utils; + +fn log_request(req: &Request) { + console_log!( + "{} - [{}], located at: {:?}, within: {}", + Date::now().to_string(), + req.path(), + req.cf().coordinates().unwrap_or_default(), + req.cf().region().unwrap_or_else(|| "unknown region".into()) + ); +} + +#[event(fetch, respond_with_errors)] +pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result { + let mut task_reg = TaskRegistry::default(); + + fca00c::setup(&mut task_reg); + + task_reg.debug = matches!( + env.var("ENVIRONMENT")?.to_string().as_str(), + "local" | "dev" + ); + + log_request(&req); + + // Optionally, get more helpful error messages written to the console in the case of a panic. + utils::set_panic_hook(); + + let mut router = Router::with_data(task_reg.clone()); + router = router + .options("/submit", |_req, _ctx| Response::empty()) + .post_async("/submit", fca00c::routes::submit::handle); + + let cors = Cors::new() + .with_allowed_headers(["*"]) + .with_origins(["*"]) + .with_max_age(86400) + .with_methods([Method::Get, Method::Post, Method::Options]); + + router + .run(req, env) + .await + .and_then(|success| success.with_cors(&cors)) +} diff --git a/wrangler/src/soroban/helpers.rs b/wrangler/src/soroban/helpers.rs new file mode 100644 index 0000000..d7846ea --- /dev/null +++ b/wrangler/src/soroban/helpers.rs @@ -0,0 +1,87 @@ +use soroban_env_host::xdr::{BytesM, Error, ScObject, ScVal, ScVec}; + +// create [u8; 32] from single u64, first 24 entires will be zero. +macro_rules! contract_id { + ($num:expr) => { + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + (($num as u64) >> (8 * 7) & 0xff) as u8, + (($num as u64) >> (8 * 6) & 0xff) as u8, + (($num as u64) >> (8 * 5) & 0xff) as u8, + (($num as u64) >> (8 * 4) & 0xff) as u8, + (($num as u64) >> (8 * 3) & 0xff) as u8, + (($num as u64) >> (8 * 2) & 0xff) as u8, + (($num as u64) >> (8 * 1) & 0xff) as u8, + (($num as u64) >> (8 * 0) & 0xff) as u8, + ] + }; +} + +pub(crate) use contract_id; + +pub struct ScValHelper(ScVal); + +impl From for ScValHelper { + fn from(value: ScVal) -> Self { + ScValHelper(value) + } +} + +impl From for ScVal { + fn from(value: ScValHelper) -> Self { + value.0 + } +} + +// BytesN<32> + +impl From<[u8; 32]> for ScValHelper { + fn from(value: [u8; 32]) -> Self { + ScVal::Object(Some(ScObject::Bytes( + BytesM::try_from(value.to_vec()).unwrap(), + ))) + .into() + } +} + +impl TryFrom> for ScValHelper +where + T: Into + Clone, +{ + type Error = soroban_env_host::xdr::Error; + fn try_from(value: Vec) -> Result + where + T: Into + Clone, + { + let v = value + .iter() + .map(move |b| b.to_owned().into()) + .collect::>(); + Ok(ScValHelper(ScVal::Object(Some(ScObject::Vec( + ScVec::try_from(v)?, + ))))) + } +} diff --git a/wrangler/src/soroban/mod.rs b/wrangler/src/soroban/mod.rs new file mode 100644 index 0000000..5ca6b1d --- /dev/null +++ b/wrangler/src/soroban/mod.rs @@ -0,0 +1,3 @@ +pub mod helpers; +pub mod soroban_env_utils; +pub mod soroban_vm; diff --git a/wrangler/src/soroban/soroban_env_utils.rs b/wrangler/src/soroban/soroban_env_utils.rs new file mode 100644 index 0000000..a1df6a8 --- /dev/null +++ b/wrangler/src/soroban/soroban_env_utils.rs @@ -0,0 +1,306 @@ +// https://github.com/stellar/soroban-tools/blob/baa984478214a32b714a2206fed500cb91e0209b/cmd/soroban-cli/src/utils.rs +#![allow(dead_code)] +use std::{io::ErrorKind, path::Path}; + +use ed25519_dalek::Signer; +use hex::FromHexError; +use sha2::{Digest, Sha256}; +use soroban_env_host::{ + budget::Budget, + storage::{AccessType, Footprint, Storage}, + xdr::{ + AccountEntry, AccountEntryExt, AccountId, ContractCodeEntry, ContractDataEntry, + DecoratedSignature, Error as XdrError, ExtensionPoint, Hash, InstallContractCodeArgs, + LedgerEntry, LedgerEntryData, LedgerEntryExt, LedgerFootprint, LedgerKey, + LedgerKeyContractCode, LedgerKeyContractData, ScContractCode, ScObject, ScSpecEntry, + ScStatic, ScVal, SequenceNumber, Signature, SignatureHint, StringM, Thresholds, + Transaction, TransactionEnvelope, TransactionSignaturePayload, + TransactionSignaturePayloadTaggedTransaction, TransactionV1Envelope, VecM, WriteXdr, + }, +}; +use soroban_ledger_snapshot::LedgerSnapshot; +use soroban_spec::read::FromWasmError; +use stellar_strkey::ed25519::PrivateKey; + +pub static SANDBOX_NETWORK_PASSPHRASE: &str = "Local Sandbox Stellar Network ; September 2022"; + +pub fn empty_ledger_snapshot() -> LedgerSnapshot { + LedgerSnapshot { + ..Default::default() + } +} + +/// # Errors +/// +/// Might return an error +pub fn contract_hash(contract: &[u8]) -> Result { + let args_xdr = InstallContractCodeArgs { + code: contract.try_into()?, + } + .to_xdr()?; + Ok(Hash(Sha256::digest(args_xdr).into())) +} + +/// # Errors +/// +/// Might return an error +pub fn ledger_snapshot_read_or_default( + p: impl AsRef, +) -> Result { + match LedgerSnapshot::read_file(p) { + Ok(snapshot) => Ok(snapshot), + Err(soroban_ledger_snapshot::Error::Io(e)) if e.kind() == ErrorKind::NotFound => { + Ok(LedgerSnapshot { + ..Default::default() + }) + } + Err(e) => Err(e), + } +} + +/// # Errors +/// +/// Might return an error +pub fn add_contract_code_to_ledger_entries( + entries: &mut Vec<(Box, Box)>, + contract: Vec, +) -> Result { + // Install the code + let hash = contract_hash(contract.as_slice())?; + let code_key = LedgerKey::ContractCode(LedgerKeyContractCode { hash: hash.clone() }); + let code_entry = LedgerEntry { + last_modified_ledger_seq: 0, + data: LedgerEntryData::ContractCode(ContractCodeEntry { + code: contract.try_into()?, + ext: ExtensionPoint::V0, + hash: hash.clone(), + }), + ext: LedgerEntryExt::V0, + }; + for (k, e) in entries.iter_mut() { + if **k == code_key { + **e = code_entry; + return Ok(hash); + } + } + entries.push((Box::new(code_key), Box::new(code_entry))); + Ok(hash) +} + +pub fn add_contract_to_ledger_entries( + entries: &mut Vec<(Box, Box)>, + contract_id: [u8; 32], + wasm_hash: [u8; 32], +) { + // Create the contract + let contract_key = LedgerKey::ContractData(LedgerKeyContractData { + contract_id: contract_id.into(), + key: ScVal::Static(ScStatic::LedgerKeyContractCode), + }); + + let contract_entry = LedgerEntry { + last_modified_ledger_seq: 0, + data: LedgerEntryData::ContractData(ContractDataEntry { + contract_id: contract_id.into(), + key: ScVal::Static(ScStatic::LedgerKeyContractCode), + val: ScVal::Object(Some(ScObject::ContractCode(ScContractCode::WasmRef(Hash( + wasm_hash, + ))))), + }), + ext: LedgerEntryExt::V0, + }; + for (k, e) in entries.iter_mut() { + if **k == contract_key { + **e = contract_entry; + return; + } + } + entries.push((Box::new(contract_key), Box::new(contract_entry))); +} + +/// # Errors +/// +/// Might return an error +pub fn padded_hex_from_str(s: &String, n: usize) -> Result, FromHexError> { + let mut decoded = vec![0u8; n]; + let padded = format!("{s:0>width$}", width = n * 2); + hex::decode_to_slice(padded, &mut decoded)?; + Ok(decoded) +} + +/// # Errors +/// +/// Might return an error +pub fn transaction_hash(tx: &Transaction, network_passphrase: &str) -> Result<[u8; 32], XdrError> { + let signature_payload = TransactionSignaturePayload { + network_id: Hash(Sha256::digest(network_passphrase).into()), + tagged_transaction: TransactionSignaturePayloadTaggedTransaction::Tx(tx.clone()), + }; + Ok(Sha256::digest(signature_payload.to_xdr()?).into()) +} + +/// # Errors +/// +/// Might return an error +pub fn sign_transaction( + key: &ed25519_dalek::Keypair, + tx: &Transaction, + network_passphrase: &str, +) -> Result { + let tx_hash = transaction_hash(tx, network_passphrase)?; + let tx_signature = key.sign(&tx_hash); + + let decorated_signature = DecoratedSignature { + hint: SignatureHint(key.public.to_bytes()[28..].try_into()?), + signature: Signature(tx_signature.to_bytes().try_into()?), + }; + + Ok(TransactionEnvelope::Tx(TransactionV1Envelope { + tx: tx.clone(), + signatures: vec![decorated_signature].try_into()?, + })) +} + +/// # Errors +/// +/// Might return an error +pub fn id_from_str(contract_id: &String) -> Result<[u8; N], FromHexError> { + padded_hex_from_str(contract_id, N)? + .try_into() + .map_err(|_| FromHexError::InvalidStringLength) +} + +/// # Errors +/// +/// Might return an error +pub fn get_contract_spec_from_storage( + storage: &mut Storage, + contract_id: [u8; 32], +) -> Result, FromWasmError> { + let key = LedgerKey::ContractData(LedgerKeyContractData { + contract_id: contract_id.into(), + key: ScVal::Static(ScStatic::LedgerKeyContractCode), + }); + if let Ok(LedgerEntry { + data: + LedgerEntryData::ContractData(ContractDataEntry { + val: ScVal::Object(Some(ScObject::ContractCode(c))), + .. + }), + .. + }) = storage.get(&key, &Budget::default()) + { + match c { + ScContractCode::Token => unimplemented!(), + ScContractCode::WasmRef(hash) => { + if let Ok(LedgerEntry { + data: LedgerEntryData::ContractCode(ContractCodeEntry { code, .. }), + .. + }) = storage.get( + &LedgerKey::ContractCode(LedgerKeyContractCode { hash }), + &Budget::default(), + ) { + soroban_spec::read::from_wasm(&code) + } else { + Err(FromWasmError::NotFound) + } + } + } + } else { + Err(FromWasmError::NotFound) + } +} + +/// # Errors +/// +/// Might return an error +pub fn vec_to_hash(res: &ScVal) -> Result { + if let ScVal::Object(Some(ScObject::Bytes(res_hash))) = &res { + let mut hash_bytes: [u8; 32] = [0; 32]; + for (i, b) in res_hash.iter().enumerate() { + hash_bytes[i] = *b; + } + Ok(hex::encode(hash_bytes)) + } else { + Err(XdrError::Invalid) + } +} + +/// # Panics +/// +/// May panic +#[must_use] +pub fn create_ledger_footprint(footprint: &Footprint) -> LedgerFootprint { + let mut read_only: Vec = vec![]; + let mut read_write: Vec = vec![]; + let Footprint(m) = footprint; + for (k, v) in m { + let dest = match v { + AccessType::ReadOnly => &mut read_only, + AccessType::ReadWrite => &mut read_write, + }; + dest.push((**k).clone()); + } + LedgerFootprint { + read_only: read_only.try_into().unwrap(), + read_write: read_write.try_into().unwrap(), + } +} + +#[must_use] +pub fn default_account_ledger_entry(account_id: AccountId) -> LedgerEntry { + // TODO: Consider moving the definition of a default account ledger entry to + // a location shared by the SDK and CLI. The SDK currently defines the same + // value (see URL below). There's some benefit in only defining this once to + // prevent the two from diverging, which would cause inconsistent test + // behavior between the SDK and CLI. A good home for this is unclear at this + // time. + // https://github.com/stellar/rs-soroban-sdk/blob/b6f9a2c7ec54d2d5b5a1e02d1e38ae3158c22e78/soroban-sdk/src/accounts.rs#L470-L483. + LedgerEntry { + data: LedgerEntryData::Account(AccountEntry { + account_id, + balance: 0, + flags: 0, + home_domain: StringM::default(), + inflation_dest: None, + num_sub_entries: 0, + seq_num: SequenceNumber(0), + thresholds: Thresholds([1; 4]), + signers: VecM::default(), + ext: AccountEntryExt::V0, + }), + last_modified_ledger_seq: 0, + ext: LedgerEntryExt::V0, + } +} + +/// # Errors +/// May not find a config dir +pub fn find_config_dir(mut pwd: std::path::PathBuf) -> std::io::Result { + let soroban_dir = |p: &std::path::Path| p.join(".soroban"); + while !soroban_dir(&pwd).exists() { + if !pwd.pop() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "soroban directory not found", + )); + } + } + Ok(soroban_dir(&pwd)) +} + +pub(crate) fn into_key_pair( + key: &PrivateKey, +) -> Result { + let secret = ed25519_dalek::SecretKey::from_bytes(&key.0)?; + let public = (&secret).into(); + Ok(ed25519_dalek::Keypair { secret, public }) +} + +/// Used in tests +#[allow(unused)] +pub(crate) fn parse_secret_key( + s: &str, +) -> Result { + into_key_pair(&PrivateKey::from_string(s).unwrap()) +} diff --git a/wrangler/src/soroban/soroban_vm.rs b/wrangler/src/soroban/soroban_vm.rs new file mode 100644 index 0000000..4956247 --- /dev/null +++ b/wrangler/src/soroban/soroban_vm.rs @@ -0,0 +1,146 @@ +use std::rc::Rc; + +use soroban_env_host::{ + budget::Budget, + events::Events, + storage::Storage, + xdr::{ + AccountEntry, AccountEntryExt, AccountId, HostFunction, LedgerEntry, LedgerEntryData, + LedgerEntryExt, LedgerKey, LedgerKeyAccount, PublicKey, ScHostStorageErrorCode, ScObject, + ScStatus, ScVal, ScVec, SequenceNumber, StringM, Thresholds, Uint256, VecM, + }, + Host, HostError, +}; + +use super::soroban_env_utils; + +pub fn deploy( + src: &[u8], + contract_id: &[u8; 32], + state: &mut soroban_ledger_snapshot::LedgerSnapshot, +) -> Result<(), soroban_env_host::xdr::Error> { + let wasm_hash = soroban_env_utils::add_contract_code_to_ledger_entries( + &mut state.ledger_entries, + src.to_vec(), + )? + .0; + + soroban_env_utils::add_contract_to_ledger_entries( + &mut state.ledger_entries, + *contract_id, + wasm_hash, + ); + + Ok(()) +} + +pub fn invoke( + contract_id: &[u8; 32], + fn_name: &str, + args: &[ScVal], + state: &mut soroban_ledger_snapshot::LedgerSnapshot, +) -> Result<(ScVal, (Storage, Budget, Events)), Error> { + invoke_with_budget(contract_id, fn_name, args, state, None) +} + +pub fn invoke_with_budget( + contract_id: &[u8; 32], + fn_name: &str, + args: &[ScVal], + state: &mut soroban_ledger_snapshot::LedgerSnapshot, + budget: Option, +) -> Result<(ScVal, (Storage, Budget, Events)), Error> { + let budget = if let Some(b) = budget { + b + } else { + Budget::default() + }; + + // Create source account, adding it to the ledger if not already present. + let source_account = AccountId(PublicKey::PublicKeyTypeEd25519(Uint256( + stellar_strkey::ed25519::PublicKey::from_string( + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + ) + .unwrap() + .0, + ))); + let source_account_ledger_key = LedgerKey::Account(LedgerKeyAccount { + account_id: source_account.clone(), + }); + if !state + .ledger_entries + .iter() + .any(|(k, _)| **k == source_account_ledger_key) + { + state.ledger_entries.push(( + Box::new(source_account_ledger_key), + Box::new(default_account_ledger_entry(source_account.clone())), + )); + } + + let snap = Rc::new(state.clone()); + let storage = Storage::with_recording_footprint(snap); + + let h = Host::with_storage_and_budget(storage, budget); + h.set_source_account(source_account); + + let mut ledger_info = state.ledger_info(); + ledger_info.sequence_number += 1; + ledger_info.timestamp += 5; + h.set_ledger_info(ledger_info); + + let mut complete_args = vec![ + ScVal::Object(Some(ScObject::Bytes(contract_id.try_into().unwrap()))), + ScVal::Symbol(fn_name.try_into().unwrap()), + ]; + + complete_args.append(&mut args.to_vec()); + + //todo add arguments + + let host_function_params: ScVec = complete_args.try_into().unwrap(); + + let res = h.invoke_function(HostFunction::InvokeContract(host_function_params))?; + + state.update(&h); + + let (storage, budget, events) = h.try_finish().map_err(|_h| { + HostError::from(ScStatus::HostStorageError( + ScHostStorageErrorCode::UnknownError, + )) + })?; + + Ok((res, (storage, budget, events))) +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Host(#[from] HostError), +} + +pub fn default_account_ledger_entry(account_id: AccountId) -> LedgerEntry { + // TODO: Consider moving the definition of a default account ledger entry to + // a location shared by the SDK and CLI. The SDK currently defines the same + // value (see URL below). There's some benefit in only defining this once to + // prevent the two from diverging, which would cause inconsistent test + // behavior between the SDK and CLI. A good home for this is unclear at this + // time. + // https://github.com/stellar/rs-soroban-sdk/blob/b6f9a2c7ec54d2d5b5a1e02d1e38ae3158c22e78/soroban-sdk/src/accounts.rs#L470-L483. + LedgerEntry { + data: LedgerEntryData::Account(AccountEntry { + account_id, + balance: 0, + flags: 0, + home_domain: StringM::default(), + inflation_dest: None, + num_sub_entries: 0, + seq_num: SequenceNumber(0), + thresholds: Thresholds([1; 4]), + signers: VecM::default(), + ext: AccountEntryExt::V0, + }), + last_modified_ledger_seq: 0, + ext: LedgerEntryExt::V0, + } +} diff --git a/wrangler/src/utils.rs b/wrangler/src/utils.rs new file mode 100644 index 0000000..2e1c309 --- /dev/null +++ b/wrangler/src/utils.rs @@ -0,0 +1,25 @@ +use cfg_if::cfg_if; + +cfg_if! { + // https://github.com/rustwasm/console_error_panic_hook#readme + if #[cfg(feature = "console_error_panic_hook")] { + extern crate console_error_panic_hook; + pub use self::console_error_panic_hook::set_once as set_panic_hook; + } else { + #[inline] + pub fn set_panic_hook() {} + } +} + +pub trait Flatten { + fn flatten(self) -> Option; +} + +impl Flatten for Result { + fn flatten(self) -> Option { + match self { + Err(_) => None, + Ok(v) => Some(v), + } + } +} diff --git a/wrangler/wrangler.toml b/wrangler/wrangler.toml new file mode 100644 index 0000000..77a2b9e --- /dev/null +++ b/wrangler/wrangler.toml @@ -0,0 +1,15 @@ +workers_dev = true +compatibility_date = "2023-02-02" +account_id = "ba55b7ae9acfb3ed152103e3497c0752" +usage_model = "unbound" + +main = "build/worker/shim.mjs" +rules = [{ globs=["**/*.wasm"], type = "CompiledWasm", fallthrough = false }] +build = { command = "worker-build --release" } + +# Staging environment as default +name = "fca00c-dev" + +vars = { ENVIRONMENT = "dev", ASTEROIDS_SEED="8891", SOROBAN_CPU_BUDGET="16000000000" } +# Necessary secrets are: +# - JWT_SECRET \ No newline at end of file