From 6f6aefddef2c1f2fafde9a070669a25aaf494e14 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Wed, 17 Jan 2024 07:56:17 +0530 Subject: [PATCH 01/21] handle execution based on deposit and store info regarding billing --- Cargo.lock | 2305 +++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + src/contract_abi.json | 0 src/handler.rs | 29 +- src/main.rs | 9 +- src/model.rs | 4 + src/tests.rs | 5 +- src/workerd.rs | 46 +- 8 files changed, 2297 insertions(+), 102 deletions(-) create mode 100644 src/contract_abi.json diff --git a/Cargo.lock b/Cargo.lock index 77bc384..6f724c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "actix-codec" version = "0.5.1" @@ -30,7 +40,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash", - "base64", + "base64 0.21.4", "bitflags 2.4.1", "brotli", "bytes", @@ -55,7 +65,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", - "zstd", + "zstd 0.12.4", ] [[package]] @@ -65,7 +75,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -178,7 +188,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -196,6 +206,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.3" @@ -267,7 +288,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -277,7 +298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -286,6 +307,55 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -313,6 +383,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[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.4" @@ -325,6 +401,27 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -337,6 +434,18 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -367,17 +476,42 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2", + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] [[package]] name = "bytestring" @@ -388,6 +522,59 @@ dependencies = [ "bytes", ] +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.83" @@ -404,6 +591,25 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "num-traits", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.4.8" @@ -435,7 +641,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -444,18 +650,89 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest", + "hmac", + "k256", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.4", + "bech32", + "bs58", + "digest", + "generic-array", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2", + "sha3", + "thiserror", +] + [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "const-hex" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.4.0" @@ -507,6 +784,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crunchy" version = "0.2.2" @@ -535,6 +837,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "data-encoding" version = "2.5.0" @@ -573,6 +884,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.10.7" @@ -585,6 +902,54 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + [[package]] name = "ecdsa" version = "0.16.9" @@ -599,6 +964,12 @@ dependencies = [ "spki", ] +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "elliptic-curve" version = "0.13.8" @@ -618,6 +989,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + [[package]] name = "encoding_rs" version = "0.8.33" @@ -627,6 +1007,30 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b" +dependencies = [ + "base64 0.21.4", + "bytes", + "hex", + "k256", + "log", + "rand", + "rlp", + "serde", + "sha3", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.5" @@ -634,12 +1038,340 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] -name = "fastrand" -version = "2.0.1" +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5344eea9b20effb5efeaad29418215c4d27017639fd1f908260f59cbbd226e" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf35eb7d2e2092ad41f584951e08ec7c077b142dba29c4f1b8f52d2efddc49c" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0111ead599d17a7bff6985fd5756f39ca7033edc79a31b23026a8d5d64fa95cd" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbdfb952aafd385b31d316ed80d7b76215ce09743c172966d840e96924427e0c" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "ethers-etherscan", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "reqwest", + "serde", + "serde_json", + "syn 2.0.48", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7465c814a2ecd0de0442160da13584205d1cdc08f4717a6511cad455bd5d7dc4" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.48", +] + +[[package]] +name = "ethers-core" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918b1a9ba585ea61022647def2f27c29ba19f6d2a4a4c8f68a9ae97fd5769737" +dependencies = [ + "arrayvec", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array", + "k256", + "num_enum", + "once_cell", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.48", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "facabf8551b4d1a3c08cb935e7fca187804b6c2525cc0dafb8e5a6dd453a24de" +dependencies = [ + "chrono", + "ethers-core", + "reqwest", + "semver", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681ece6eb1d10f7cf4f873059a77c04ff1de4f35c63dd7bccde8f438374fcb93" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25d6c0c9455d93d4990c06e049abf9b30daf148cf461ee939c11d88907c60816" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.4", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb1b714e227bbd2d8c53528adb580b203009728b17d0d0e4119353aa9bc5532" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand", + "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2e46e3ec8ef0c986145901fa9864205dc4dcee701f9846be2d56112d34bdea" +dependencies = [ + "cfg-if", + "const-hex", + "dirs", + "dunce", + "ethers-core", + "glob", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver", + "serde", + "serde_json", + "solang-parser", + "svm-rs", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi", +] + +[[package]] +name = "eyre" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" @@ -653,6 +1385,24 @@ dependencies = [ "subtle", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -693,6 +1443,37 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -700,6 +1481,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -708,6 +1490,44 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "futures-sink" version = "0.3.28" @@ -720,16 +1540,41 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + [[package]] name = "futures-util" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", ] [[package]] @@ -760,6 +1605,24 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "group" version = "0.13.0" @@ -783,7 +1646,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -796,6 +1659,21 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + [[package]] name = "heck" version = "0.4.1" @@ -823,6 +1701,15 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "0.2.9" @@ -882,42 +1769,128 @@ dependencies = [ ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", + "autocfg", + "hashbrown 0.12.3", ] [[package]] -name = "idna" -version = "0.4.0" +name = "indexmap" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "equivalent", + "hashbrown 0.14.3", ] [[package]] -name = "if_chain" -version = "1.0.2" +name = "inout" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] [[package]] -name = "indexmap" -version = "1.9.3" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "autocfg", - "hashbrown", + "cfg-if", ] [[package]] @@ -926,6 +1899,35 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -950,6 +1952,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.4", + "pem", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "k256" version = "0.13.2" @@ -964,6 +1980,43 @@ dependencies = [ "signature", ] +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools 0.10.5", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.7.5", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" + [[package]] name = "language-tags" version = "0.3.2" @@ -982,6 +2035,23 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "linux-raw-sys" version = "0.4.10" @@ -1021,6 +2091,16 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.6.4" @@ -1051,7 +2131,7 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1072,6 +2152,43 @@ dependencies = [ "tempfile", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[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-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -1082,6 +2199,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.0.0", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "object" version = "0.32.1" @@ -1097,6 +2235,31 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "openssl" version = "0.10.57" @@ -1120,7 +2283,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -1151,6 +2314,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "oyster-serverless" version = "0.1.0" @@ -1159,6 +2328,7 @@ dependencies = [ "anyhow", "clap", "data-encoding", + "ethers", "hex", "k256", "openssl", @@ -1172,6 +2342,32 @@ dependencies = [ "validator", ] +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1186,26 +2382,165 @@ dependencies = [ name = "parking_lot_core" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.1.0", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "smallvec", - "windows-targets", + "siphasher", ] [[package]] -name = "paste" -version = "1.0.14" +name = "pin-project" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] [[package]] -name = "percent-encoding" -version = "2.3.0" +name = "pin-project-internal" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] [[package]] name = "pin-project-lite" @@ -1247,6 +2582,64 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +dependencies = [ + "proc-macro2", + "syn 2.0.48", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" +dependencies = [ + "toml_edit 0.21.0", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1273,22 +2666,44 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.4.1", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "unarray", +] + [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -1319,6 +2734,35 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -1337,6 +2781,17 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.10.2" @@ -1346,7 +2801,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax", + "regex-syntax 0.8.2", ] [[package]] @@ -1357,9 +2812,15 @@ checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.2", ] +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + [[package]] name = "regex-syntax" version = "0.8.2" @@ -1372,7 +2833,7 @@ version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64", + "base64 0.21.4", "bytes", "encoding_rs", "futures-core", @@ -1381,6 +2842,7 @@ dependencies = [ "http", "http-body", "hyper", + "hyper-rustls", "hyper-tls", "ipnet", "js-sys", @@ -1390,17 +2852,21 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "winreg", ] @@ -1414,12 +2880,78 @@ dependencies = [ "subtle", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1439,22 +2971,101 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.4", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "schannel" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1463,6 +3074,28 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + [[package]] name = "sec1" version = "0.7.3" @@ -1505,25 +3138,40 @@ name = "semver" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -1537,6 +3185,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1571,6 +3228,16 @@ dependencies = [ "digest", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -1590,6 +3257,24 @@ dependencies = [ "rand_core", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -1622,17 +3307,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "solang-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" +dependencies = [ + "itertools 0.11.0", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", ] [[package]] -name = "spki" -version = "0.7.3" +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ - "base64ct", - "der", + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", ] [[package]] @@ -1641,12 +3371,54 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + [[package]] name = "subtle" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "svm-rs" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20689c7d03b6461b502d0b95d6c24874c7d24dea2688af80486a130a06af3b07" +dependencies = [ + "dirs", + "fs2", + "hex", + "once_cell", + "reqwest", + "semver", + "serde", + "serde_json", + "sha2", + "thiserror", + "url", + "zip", +] + [[package]] name = "syn" version = "1.0.109" @@ -1660,9 +3432,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -1690,6 +3462,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.8.0" @@ -1700,7 +3478,18 @@ dependencies = [ "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", ] [[package]] @@ -1720,7 +3509,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -1792,7 +3581,7 @@ dependencies = [ "signal-hook-registry", "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1803,7 +3592,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", ] [[package]] @@ -1816,6 +3605,31 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots", +] + [[package]] name = "tokio-util" version = "0.7.9" @@ -1830,6 +3644,62 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.21.0", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -1844,9 +3714,21 @@ checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -1856,18 +3738,66 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "try-lock" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "rustls", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -1889,6 +3819,24 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.4.1" @@ -1900,12 +3848,28 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + [[package]] name = "validator" version = "0.16.1" @@ -1960,6 +3924,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1996,7 +3970,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -2030,7 +4004,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2051,6 +4025,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" + [[package]] name = "winapi" version = "0.3.9" @@ -2067,6 +4047,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2079,7 +4068,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -2088,13 +4086,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -2103,42 +4116,93 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -2146,22 +4210,95 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2 0.11.0", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "zstd" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" dependencies = [ - "zstd-safe", + "zstd-safe 6.0.6", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 14714b1..9cfa08c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ reqwest = { version = "0.11.9", features = ["json"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0.50" +ethers = "2.0.11" tiny-keccak = { version = "2.0.2", features = ["keccak"] } tokio = { version = "1.16.1", features = ["full"] } validator = { version = "0.16", features = ["derive"] } diff --git a/src/contract_abi.json b/src/contract_abi.json new file mode 100644 index 0000000..e69de29 diff --git a/src/handler.rs b/src/handler.rs index 24b7c2e..17db8fe 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -3,10 +3,10 @@ use crate::{cgroups, model::AppState, workerd}; use actix_web::http::{header, StatusCode}; use actix_web::{web, HttpRequest, HttpResponse, Responder}; use anyhow::{anyhow, Context}; +use tiny_keccak::Hasher; use std::io::{BufRead, BufReader}; use std::sync::atomic::Ordering; -use std::time::Duration; -// use std::time::Instant; +use std::time::{Duration, Instant}; use tokio::time::timeout; pub async fn serverless( @@ -72,6 +72,7 @@ pub async fn serverless( use workerd::ServerlessError::*; return match err { CalldataRetrieve(_) + | TxDepositNotEnough | TxNotFound | InvalidTxToType | InvalidTxToValue(_, _) @@ -91,7 +92,7 @@ pub async fn serverless( }; } - // let execution_timer_start = Instant::now(); + let execution_timer_start = Instant::now(); // reserve cgroup let cgroup = appstate.cgroups.lock().unwrap().reserve(); @@ -262,14 +263,22 @@ pub async fn serverless( anyhow!(err).context("failed to get a response") )); } - let response = response.unwrap(); + let (response, hash) = response.unwrap(); + + let execution_timer_end = Instant::now(); + let execution_time = execution_timer_end + .duration_since(execution_timer_start) + .as_millis(); + + let execution_cost = 1 + 2*execution_time; // TODO: FIX THE VALUE OF FIXED COST AND CONVERSION RATE + let mut map_guard = appstate.service_costs.lock().unwrap(); + let fee = map_guard.entry(tx_hash.to_string()).or_insert(0); + *fee += execution_cost as u64; + drop(map_guard); - // let execution_timer_end = Instant::now(); - // let execution_time = execution_timer_end - // .duration_since(execution_timer_start) - // .as_millis() - // .to_string(); - // println!("Execution time: {}ms", execution_time); + let mut hasher_guard = appstate.hasher.lock().unwrap(); + hasher_guard.update(&hash); + drop(hasher_guard); return response; } diff --git a/src/main.rs b/src/main.rs index 275d133..dd7dcd6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ +use std::collections::HashMap; use actix_web::{web, App, HttpServer}; use anyhow::{anyhow, Context}; use clap::Parser; +use tiny_keccak::Keccak; use tokio::fs; use serverless::cgroups::Cgroups; @@ -33,6 +35,9 @@ struct Args { )] contract: String, + #[clap(long, value_parser)] + operator: String, + #[clap(long, value_parser)] signer: String, } @@ -72,7 +77,9 @@ async fn main() -> anyhow::Result<()> { runtime_path: cli.runtime_path, rpc: cli.rpc, contract: cli.contract, - signer, + signer: signer, + service_costs: HashMap::new().into(), + hasher: Keccak::v256().into(), }); let server = HttpServer::new(move || { diff --git a/src/model.rs b/src/model.rs index d1ee9bc..f364f89 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,5 +1,7 @@ use crate::cgroups::Cgroups; use std::sync::{atomic::AtomicBool, Mutex}; +use std::collections::HashMap; +use tiny_keccak::Keccak; pub struct AppState { pub cgroups: Mutex, @@ -11,4 +13,6 @@ pub struct AppState { pub rpc: String, pub contract: String, pub signer: k256::ecdsa::SigningKey, + pub service_costs: Mutex>, + pub hasher: Mutex, } diff --git a/src/tests.rs b/src/tests.rs index e92f9fa..f99b873 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -15,7 +15,8 @@ pub mod serverlesstest { http, test, web, App, }; use serde_json::json; - use std::sync::atomic::AtomicBool; + use tiny_keccak::Keccak; + use std::{sync::atomic::AtomicBool, collections::HashMap}; fn new_app() -> App< impl ServiceFactory< @@ -34,6 +35,8 @@ pub mod serverlesstest { rpc: "https://sepolia-rollup.arbitrum.io/rpc".to_owned(), contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), + service_costs: HashMap::new().into(), + hasher: Keccak::v256().into(), })) .default_service(web::to(handler::serverless)) } diff --git a/src/workerd.rs b/src/workerd.rs index 110189f..a47e28e 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -1,3 +1,4 @@ +use std::io::Read; use std::process::Child; use std::time::{Duration, Instant}; @@ -8,10 +9,13 @@ use k256::elliptic_curve::generic_array::sequence::Lengthen; use reqwest::Client; use serde_json::{json, Value}; use tiny_keccak::{Hasher, Keccak}; -use tokio::fs::File; -use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; use tokio::time::sleep; +use ethers::prelude::*; +use ethers::core::abi::Abi; +use tokio::io::AsyncWriteExt; +use std::{convert::TryFrom, sync::Arc}; +use std::fs::File; use crate::cgroups::{Cgroups, CgroupsError}; @@ -19,6 +23,10 @@ use crate::cgroups::{Cgroups, CgroupsError}; pub enum ServerlessError { #[error("failed to retrieve calldata")] CalldataRetrieve(#[from] reqwest::Error), + #[error("failed to retrieve tx deposit")] + TxDepositNotFound, + #[error("tx deposit not enough")] + TxDepositNotEnough, #[error("tx not found")] TxNotFound, #[error("to field of transaction is not an address")] @@ -45,6 +53,22 @@ pub enum ServerlessError { BadPort(#[source] std::num::ParseIntError), } +async fn get_current_deposit( + tx_hash: &str, + rpc: &str, + contract: &str, +) -> Result { + let abi_file_path = "src/contract_abi.json"; // TODO: NEED THE ABI FILE + let mut abi_json = String::new(); + let mut file = File::open(abi_file_path)?; + file.read_to_string(&mut abi_json)?; + let abi = serde_json::from_str::(&abi_json)?; + let provider = Provider::::try_from(rpc)?; + let contract = Contract::new(contract.parse::
()?, abi, Arc::new(provider)); + let current_deposit: U256 = contract.method::<_, U256>("getDeposit", tx_hash.parse::
()?)?.call().await?; // TODO: NEED THE FUNCTION DEFINITION + Ok(current_deposit) +} + async fn get_transaction_data(tx_hash: &str, rpc: &str) -> Result { let client = Client::new(); let method = "eth_getTransactionByHash"; @@ -71,6 +95,15 @@ pub async fn create_code_file( rpc: &str, contract: &str, ) -> Result<(), ServerlessError> { + let tx_deposit = match get_current_deposit(tx_hash, rpc, contract).await { + Ok(deposit_val) => Ok(deposit_val), + _ => Err(ServerlessError::TxDepositNotFound), + }?; + + if tx_deposit <= U256::from(200) { // TODO: FIX THE FIXED MINIMUM VALUE + return Err(ServerlessError::TxDepositNotEnough); + } + // get tx data let mut tx_data = match get_transaction_data(tx_hash, rpc).await?["result"].take() { Value::Null => Err(ServerlessError::TxNotFound), @@ -106,7 +139,7 @@ pub async fn create_code_file( // write calldata to file let mut file = - File::create(workerd_runtime_path.to_owned() + "/" + tx_hash + "-" + slug + ".js") + tokio::fs::File::create(workerd_runtime_path.to_owned() + "/" + tx_hash + "-" + slug + ".js") .await .map_err(ServerlessError::CodeFileCreate)?; file.write_all(calldata.as_slice()) @@ -139,7 +172,7 @@ const oysterWorker :Workerd.Worker = ( ); let mut file = - File::create(workerd_runtime_path.to_owned() + "/" + tx_hash + "-" + slug + ".capnp") + tokio::fs::File::create(workerd_runtime_path.to_owned() + "/" + tx_hash + "-" + slug + ".capnp") .await .map_err(ServerlessError::ConfigFileCreate)?; file.write_all(capnp_data.as_bytes()) @@ -211,7 +244,8 @@ pub async fn get_workerd_response( body: actix_web::web::Bytes, signer: &k256::ecdsa::SigningKey, host_header: &str, -) -> Result { + +) -> Result<(HttpResponse, [u8; 32]), anyhow::Error> { let mut hasher = Keccak::v256(); hasher.update(b"|oyster-serverless-hasher|"); @@ -274,5 +308,5 @@ pub async fn get_workerd_response( actix_resp.insert_header(("X-Oyster-Timestamp", timestamp.to_string())); actix_resp.insert_header(("X-Oyster-Signature", hex::encode(signature.as_slice()))); - Ok(actix_resp.body(response_body)) + Ok((actix_resp.body(response_body), hash)) } From bab98e6b2311be014f2cd018b64bd0240ec235fa Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Thu, 18 Jan 2024 16:23:05 +0530 Subject: [PATCH 02/21] add billing scheduler --- src/billing_job.rs | 46 +++++++++++++++++++++++++++++++++++++++++++ src/contract_abi.json | 44 +++++++++++++++++++++++++++++++++++++++++ src/handler.rs | 2 +- src/lib.rs | 1 + src/main.rs | 21 +++++++++++++++++++- src/model.rs | 3 ++- src/tests.rs | 1 + src/workerd.rs | 6 +++--- 8 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 src/billing_job.rs diff --git a/src/billing_job.rs b/src/billing_job.rs new file mode 100644 index 0000000..5aaabcc --- /dev/null +++ b/src/billing_job.rs @@ -0,0 +1,46 @@ +use std::io::Read; +use std::sync::Arc; +use std::time::Duration; + +use actix_web::web; +use tiny_keccak::{Hasher, Keccak}; +use crate::model::AppState; +use ethers::prelude::*; +use ethers::core::abi::Abi; +use k256::elliptic_curve::generic_array::sequence::Lengthen; + +pub async fn billing_scheduler(appstate: web::Data,) -> Result { + let abi_file_path = "src/contract_abi.json"; + let mut abi_json = String::new(); + let mut file = std::fs::File::open(abi_file_path)?; + file.read_to_string(&mut abi_json)?; + let abi = serde_json::from_str::(&abi_json)?; + + let provider = Provider::::try_from(&appstate.rpc)?.interval(Duration::from_millis(1000)); + let wallet: LocalWallet = appstate.operator_key.parse()?; + + let client = SignerMiddleware::new(provider, wallet); + let contract = Contract::new(appstate.contract.as_str().parse::
()?, abi, Arc::new(client)); + + let mut tx_hashes = Vec::new(); + let mut amounts = Vec::new(); + for (key, value) in appstate.service_costs.lock().unwrap().iter() { + tx_hashes.push(key.to_owned()); + amounts.push(value.to_owned()); + } + + let mut hash = [0u8; 32]; + let hasher = appstate.hasher.lock().unwrap().clone(); + hasher.finalize(&mut hash); + let (rs, v) = appstate.signer.sign_prehash_recoverable(&hash)?; + let signature = rs.to_bytes().append(27 + v.to_byte()); + + let tx = contract.method::<_, H256>("settle", (tx_hashes, amounts, hex::encode(signature.as_slice())))?; + let pending_tx = tx.send().await?; + let receipt = pending_tx.confirmations(7).await?; + + appstate.service_costs.lock().unwrap().clear(); + appstate.hasher.lock().unwrap().clone_from(&Keccak::v256()); + + Ok(receipt.unwrap().transaction_hash.to_string()) +} \ No newline at end of file diff --git a/src/contract_abi.json b/src/contract_abi.json index e69de29..b1692ba 100644 --- a/src/contract_abi.json +++ b/src/contract_abi.json @@ -0,0 +1,44 @@ +[ + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_txhash", + "type": "bytes32" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32[]", + "name": "_txhashes", + "type": "bytes32[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "settle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/src/handler.rs b/src/handler.rs index 17db8fe..a3d5350 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -273,7 +273,7 @@ pub async fn serverless( let execution_cost = 1 + 2*execution_time; // TODO: FIX THE VALUE OF FIXED COST AND CONVERSION RATE let mut map_guard = appstate.service_costs.lock().unwrap(); let fee = map_guard.entry(tx_hash.to_string()).or_insert(0); - *fee += execution_cost as u64; + *fee += execution_cost; drop(map_guard); let mut hasher_guard = appstate.hasher.lock().unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 7f54573..c10d052 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,4 @@ pub mod handler; pub mod model; mod tests; pub mod workerd; +pub mod billing_job; diff --git a/src/main.rs b/src/main.rs index dd7dcd6..b4fb6f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,15 @@ use std::collections::HashMap; +use std::time::Duration; use actix_web::{web, App, HttpServer}; use anyhow::{anyhow, Context}; use clap::Parser; +use serverless::billing_job; use tiny_keccak::Keccak; use tokio::fs; use serverless::cgroups::Cgroups; use serverless::model::AppState; +use tokio::time::interval; /// Simple program to greet a person #[derive(Parser, Debug)] @@ -36,7 +39,7 @@ struct Args { contract: String, #[clap(long, value_parser)] - operator: String, + operator_key: String, #[clap(long, value_parser)] signer: String, @@ -78,9 +81,11 @@ async fn main() -> anyhow::Result<()> { rpc: cli.rpc, contract: cli.contract, signer: signer, + operator_key: cli.operator_key, service_costs: HashMap::new().into(), hasher: Keccak::v256().into(), }); + let app_data_clone = app_data.clone(); let server = HttpServer::new(move || { App::new() @@ -95,5 +100,19 @@ async fn main() -> anyhow::Result<()> { server.await?; + tokio::spawn(async move { + let mut interval = interval(Duration::from_secs(600)); // TODO: FIX THE REGULAR INTERVAL + loop { + interval.tick().await; + + if !app_data_clone.service_costs.lock().unwrap().is_empty() { + match billing_job::billing_scheduler(app_data_clone.clone()).await { + Ok(tx_hash) => println!("Transaction sent for billing: {}", tx_hash), + Err(err) => println!("Error while sending billing transaction: {:?}", err), + } + } + } + }); + Ok(()) } diff --git a/src/model.rs b/src/model.rs index f364f89..2e32d9d 100644 --- a/src/model.rs +++ b/src/model.rs @@ -13,6 +13,7 @@ pub struct AppState { pub rpc: String, pub contract: String, pub signer: k256::ecdsa::SigningKey, - pub service_costs: Mutex>, + pub operator_key: String, + pub service_costs: Mutex>, pub hasher: Mutex, } diff --git a/src/tests.rs b/src/tests.rs index f99b873..7b9d159 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -35,6 +35,7 @@ pub mod serverlesstest { rpc: "https://sepolia-rollup.arbitrum.io/rpc".to_owned(), contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), + operator_key: String::new(), service_costs: HashMap::new().into(), hasher: Keccak::v256().into(), })) diff --git a/src/workerd.rs b/src/workerd.rs index a47e28e..5ea27e2 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -58,14 +58,14 @@ async fn get_current_deposit( rpc: &str, contract: &str, ) -> Result { - let abi_file_path = "src/contract_abi.json"; // TODO: NEED THE ABI FILE + let abi_file_path = "src/contract_abi.json"; let mut abi_json = String::new(); let mut file = File::open(abi_file_path)?; file.read_to_string(&mut abi_json)?; let abi = serde_json::from_str::(&abi_json)?; - let provider = Provider::::try_from(rpc)?; + let provider = Provider::::try_from(rpc)?.interval(Duration::from_millis(1000)); let contract = Contract::new(contract.parse::
()?, abi, Arc::new(provider)); - let current_deposit: U256 = contract.method::<_, U256>("getDeposit", tx_hash.parse::
()?)?.call().await?; // TODO: NEED THE FUNCTION DEFINITION + let current_deposit: U256 = contract.method::<_, U256>("balanceOf", tx_hash.to_string())?.call().await?; Ok(current_deposit) } From 2f2fd1ef78b47fcaa411809ec829a3ca97100e55 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Wed, 24 Jan 2024 04:08:37 +0530 Subject: [PATCH 03/21] resolve comments and refactor --- src/billing_job.rs | 40 ++++++++++++++++++++-------------------- src/handler.rs | 23 ++++++++++------------- src/main.rs | 12 +++++++++--- src/model.rs | 5 ++++- src/tests.rs | 11 +++++++++-- src/workerd.rs | 28 +++++++++++++--------------- 6 files changed, 65 insertions(+), 54 deletions(-) diff --git a/src/billing_job.rs b/src/billing_job.rs index 5aaabcc..45ae2cc 100644 --- a/src/billing_job.rs +++ b/src/billing_job.rs @@ -1,46 +1,46 @@ -use std::io::Read; use std::sync::Arc; use std::time::Duration; use actix_web::web; +use anyhow::{anyhow, Context}; use tiny_keccak::{Hasher, Keccak}; use crate::model::AppState; use ethers::prelude::*; -use ethers::core::abi::Abi; use k256::elliptic_curve::generic_array::sequence::Lengthen; pub async fn billing_scheduler(appstate: web::Data,) -> Result { - let abi_file_path = "src/contract_abi.json"; - let mut abi_json = String::new(); - let mut file = std::fs::File::open(abi_file_path)?; - file.read_to_string(&mut abi_json)?; - let abi = serde_json::from_str::(&abi_json)?; - - let provider = Provider::::try_from(&appstate.rpc)?.interval(Duration::from_millis(1000)); - let wallet: LocalWallet = appstate.operator_key.parse()?; + let provider = Provider::::try_from(&appstate.rpc) + .context("Unable to connect to the RPC")? + .interval(Duration::from_millis(1000)); + let wallet: LocalWallet = appstate.operator_key.parse().context("Unable to parse operator private key")?; let client = SignerMiddleware::new(provider, wallet); - let contract = Contract::new(appstate.contract.as_str().parse::
()?, abi, Arc::new(client)); + let contract = Contract::new(appstate.contract.as_str() + .parse::
() + .context("Unable to parse contract address")?, + appstate.abi.clone(), + Arc::new(client)); + let mut map_gaurd = appstate.service_costs.lock().await; let mut tx_hashes = Vec::new(); let mut amounts = Vec::new(); - for (key, value) in appstate.service_costs.lock().unwrap().iter() { + for (key, value) in map_gaurd.clone().iter() { tx_hashes.push(key.to_owned()); amounts.push(value.to_owned()); } let mut hash = [0u8; 32]; - let hasher = appstate.hasher.lock().unwrap().clone(); - hasher.finalize(&mut hash); - let (rs, v) = appstate.signer.sign_prehash_recoverable(&hash)?; - let signature = rs.to_bytes().append(27 + v.to_byte()); + let mut hasher_gaurd = appstate.hasher.lock().await; + hasher_gaurd.clone().finalize(&mut hash); + let (rs, v) = appstate.signer.sign_prehash_recoverable(&hash).context("failed to sign requests")?; + let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); - let tx = contract.method::<_, H256>("settle", (tx_hashes, amounts, hex::encode(signature.as_slice())))?; + let tx = contract.method::<_, H256>("settle", (tx_hashes, amounts, signature)).context("failed to build transaction request for billing")?; let pending_tx = tx.send().await?; let receipt = pending_tx.confirmations(7).await?; - appstate.service_costs.lock().unwrap().clear(); - appstate.hasher.lock().unwrap().clone_from(&Keccak::v256()); + map_gaurd.clear(); + hasher_gaurd.clone_from(&Keccak::v256()); - Ok(receipt.unwrap().transaction_hash.to_string()) + Ok(receipt.ok_or(anyhow!("Failed to parse transaction receipt!"))?.transaction_hash.to_string()) } \ No newline at end of file diff --git a/src/handler.rs b/src/handler.rs index a3d5350..c31f6d8 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -66,6 +66,7 @@ pub async fn serverless( workerd_runtime_path, &appstate.rpc, &appstate.contract, + &appstate.abi, ) .await { @@ -95,7 +96,7 @@ pub async fn serverless( let execution_timer_start = Instant::now(); // reserve cgroup - let cgroup = appstate.cgroups.lock().unwrap().reserve(); + let cgroup = appstate.cgroups.lock().await.reserve(); if let Err(err) = cgroup { // cleanup workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) @@ -122,7 +123,7 @@ pub async fn serverless( let port = workerd::get_port(&cgroup); if let Err(err) = port { // cleanup - appstate.cgroups.lock().unwrap().release(cgroup); + appstate.cgroups.lock().await.release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -146,7 +147,7 @@ pub async fn serverless( // create config file if let Err(err) = workerd::create_config_file(tx_hash, slug, workerd_runtime_path, port).await { // cleanup - appstate.cgroups.lock().unwrap().release(cgroup); + appstate.cgroups.lock().await.release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -182,7 +183,7 @@ pub async fn serverless( .await .context("CRITICAL: failed to clean up config file") .unwrap_or_else(|err| println!("{err:?}")); - appstate.cgroups.lock().unwrap().release(cgroup); + appstate.cgroups.lock().await.release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -208,7 +209,7 @@ pub async fn serverless( .await .context("CRITICAL: failed to clean up config file") .unwrap_or_else(|err| println!("{err:?}")); - appstate.cgroups.lock().unwrap().release(cgroup); + appstate.cgroups.lock().await.release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -245,7 +246,7 @@ pub async fn serverless( .await .context("CRITICAL: failed to clean up config file") .unwrap_or_else(|err| println!("{err:?}")); - appstate.cgroups.lock().unwrap().release(cgroup); + appstate.cgroups.lock().await.release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -264,21 +265,17 @@ pub async fn serverless( )); } let (response, hash) = response.unwrap(); + appstate.hasher.lock().await.update(&hash); let execution_timer_end = Instant::now(); let execution_time = execution_timer_end .duration_since(execution_timer_start) .as_millis(); - + let execution_cost = 1 + 2*execution_time; // TODO: FIX THE VALUE OF FIXED COST AND CONVERSION RATE - let mut map_guard = appstate.service_costs.lock().unwrap(); + let mut map_guard = appstate.service_costs.lock().await; let fee = map_guard.entry(tx_hash.to_string()).or_insert(0); *fee += execution_cost; - drop(map_guard); - - let mut hasher_guard = appstate.hasher.lock().unwrap(); - hasher_guard.update(&hash); - drop(hasher_guard); return response; } diff --git a/src/main.rs b/src/main.rs index b4fb6f7..b52ae46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,15 @@ use std::collections::HashMap; -use std::time::Duration; use actix_web::{web, App, HttpServer}; use anyhow::{anyhow, Context}; use clap::Parser; +use ethers::abi::Abi; use serverless::billing_job; use tiny_keccak::Keccak; use tokio::fs; use serverless::cgroups::Cgroups; use serverless::model::AppState; -use tokio::time::interval; +use tokio::time::{interval, Duration}; /// Simple program to greet a person #[derive(Parser, Debug)] @@ -73,6 +73,11 @@ async fn main() -> anyhow::Result<()> { .as_slice(), ) .context("invalid signer key")?; + + let abi_json = fs::read_to_string("src/contract_abi.json") + .await + .context("failed to read contract ABI")?; + let abi = serde_json::from_str::(&abi_json).context("failed to deserialize ABI")?; let app_data = web::Data::new(AppState { cgroups: cgroups.into(), @@ -81,6 +86,7 @@ async fn main() -> anyhow::Result<()> { rpc: cli.rpc, contract: cli.contract, signer: signer, + abi: abi, operator_key: cli.operator_key, service_costs: HashMap::new().into(), hasher: Keccak::v256().into(), @@ -105,7 +111,7 @@ async fn main() -> anyhow::Result<()> { loop { interval.tick().await; - if !app_data_clone.service_costs.lock().unwrap().is_empty() { + if !app_data_clone.service_costs.lock().await.is_empty() { match billing_job::billing_scheduler(app_data_clone.clone()).await { Ok(tx_hash) => println!("Transaction sent for billing: {}", tx_hash), Err(err) => println!("Error while sending billing transaction: {:?}", err), diff --git a/src/model.rs b/src/model.rs index 2e32d9d..2e4cdcf 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,5 +1,7 @@ use crate::cgroups::Cgroups; -use std::sync::{atomic::AtomicBool, Mutex}; +use std::sync::atomic::AtomicBool; +use ethers::abi::Abi; +use tokio::sync::Mutex; use std::collections::HashMap; use tiny_keccak::Keccak; @@ -13,6 +15,7 @@ pub struct AppState { pub rpc: String, pub contract: String, pub signer: k256::ecdsa::SigningKey, + pub abi: Abi, pub operator_key: String, pub service_costs: Mutex>, pub hasher: Mutex, diff --git a/src/tests.rs b/src/tests.rs index 7b9d159..531dbfa 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -14,9 +14,10 @@ pub mod serverlesstest { error::Error, http, test, web, App, }; + use ethers::abi::Abi; use serde_json::json; use tiny_keccak::Keccak; - use std::{sync::atomic::AtomicBool, collections::HashMap}; + use std::{collections::HashMap, io::Read, sync::atomic::AtomicBool}; fn new_app() -> App< impl ServiceFactory< @@ -26,7 +27,12 @@ pub mod serverlesstest { InitError = (), Error = Error, >, - > { + > { + let mut abi_json = String::new(); + let mut file = std::fs::File::open("src/contract_abi.json").unwrap(); + file.read_to_string(&mut abi_json).unwrap(); + let abi = serde_json::from_str::(&abi_json).unwrap(); + App::new() .app_data(web::Data::new(AppState { cgroups: Cgroups::new().unwrap().into(), @@ -34,6 +40,7 @@ pub mod serverlesstest { runtime_path: "./runtime/".to_owned(), rpc: "https://sepolia-rollup.arbitrum.io/rpc".to_owned(), contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), + abi: abi, signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), operator_key: String::new(), service_costs: HashMap::new().into(), diff --git a/src/workerd.rs b/src/workerd.rs index 5ea27e2..5ccb6d6 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -1,4 +1,3 @@ -use std::io::Read; use std::process::Child; use std::time::{Duration, Instant}; @@ -15,7 +14,6 @@ use ethers::prelude::*; use ethers::core::abi::Abi; use tokio::io::AsyncWriteExt; use std::{convert::TryFrom, sync::Arc}; -use std::fs::File; use crate::cgroups::{Cgroups, CgroupsError}; @@ -56,17 +54,17 @@ pub enum ServerlessError { async fn get_current_deposit( tx_hash: &str, rpc: &str, - contract: &str, + contract_add: &str, + abi: &Abi, ) -> Result { - let abi_file_path = "src/contract_abi.json"; - let mut abi_json = String::new(); - let mut file = File::open(abi_file_path)?; - file.read_to_string(&mut abi_json)?; - let abi = serde_json::from_str::(&abi_json)?; let provider = Provider::::try_from(rpc)?.interval(Duration::from_millis(1000)); - let contract = Contract::new(contract.parse::
()?, abi, Arc::new(provider)); - let current_deposit: U256 = contract.method::<_, U256>("balanceOf", tx_hash.to_string())?.call().await?; - Ok(current_deposit) + let contract = Contract::new( + contract_add.parse::
()?, + abi.clone(), + Arc::new(provider)); + Ok(contract.method::<_, U256>("balanceOf", tx_hash.to_string())? + .call() + .await?) } async fn get_transaction_data(tx_hash: &str, rpc: &str) -> Result { @@ -94,11 +92,11 @@ pub async fn create_code_file( workerd_runtime_path: &str, rpc: &str, contract: &str, + abi: &Abi, ) -> Result<(), ServerlessError> { - let tx_deposit = match get_current_deposit(tx_hash, rpc, contract).await { - Ok(deposit_val) => Ok(deposit_val), - _ => Err(ServerlessError::TxDepositNotFound), - }?; + let tx_deposit = get_current_deposit(tx_hash, rpc, contract, abi) + .await + .map_err(|err| ServerlessError::TxDepositNotFound)?; if tx_deposit <= U256::from(200) { // TODO: FIX THE FIXED MINIMUM VALUE return Err(ServerlessError::TxDepositNotEnough); From d8ecd7fcb30304b4d4a49a87e1da7754ba41225f Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Sun, 28 Jan 2024 21:42:26 +0530 Subject: [PATCH 04/21] comments resolve and additional refactoring --- Cargo.toml | 2 +- src/billing_job.rs | 56 +++++++++++++++++++++++++++++++++------------- src/cgroups.rs | 2 +- src/handler.rs | 12 +++++----- src/model.rs | 2 +- src/workerd.rs | 24 ++++++++++++-------- 6 files changed, 64 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9cfa08c..1e90ba7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ actix-web = "4" anyhow = "1.0.75" clap = { version = "4.4.7", features = ["derive"] } data-encoding = "2.5.0" +ethers = "2.0.11" hex = "0.4.3" k256 = { version = "0.13.2", features = ["ecdsa", "ecdsa-core"] } openssl = { version = "0.10", features = ["vendored"] } @@ -28,7 +29,6 @@ reqwest = { version = "0.11.9", features = ["json"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0.50" -ethers = "2.0.11" tiny-keccak = { version = "2.0.2", features = ["keccak"] } tokio = { version = "1.16.1", features = ["full"] } validator = { version = "0.16", features = ["derive"] } diff --git a/src/billing_job.rs b/src/billing_job.rs index 45ae2cc..6161ce0 100644 --- a/src/billing_job.rs +++ b/src/billing_job.rs @@ -10,37 +10,61 @@ use k256::elliptic_curve::generic_array::sequence::Lengthen; pub async fn billing_scheduler(appstate: web::Data,) -> Result { let provider = Provider::::try_from(&appstate.rpc) - .context("Unable to connect to the RPC")? - .interval(Duration::from_millis(1000)); - let wallet: LocalWallet = appstate.operator_key.parse().context("Unable to parse operator private key")?; + .context("Unable to connect to the RPC")? + .interval(Duration::from_millis(1000)); + let wallet: LocalWallet = appstate.operator_key + .parse() + .context("Unable to parse operator private key")?; let client = SignerMiddleware::new(provider, wallet); - let contract = Contract::new(appstate.contract.as_str() - .parse::
() - .context("Unable to parse contract address")?, - appstate.abi.clone(), - Arc::new(client)); + let contract = Contract::new( + appstate.contract.as_str() + .parse::
() + .context("Unable to parse contract address")?, + appstate.abi.to_owned(), + Arc::new(client)); let mut map_gaurd = appstate.service_costs.lock().await; let mut tx_hashes = Vec::new(); let mut amounts = Vec::new(); for (key, value) in map_gaurd.clone().iter() { - tx_hashes.push(key.to_owned()); - amounts.push(value.to_owned()); + let mut bytes32_tx_hash = [0u8; 32]; + hex::decode_to_slice(&key[2..], &mut bytes32_tx_hash).context("failed to decode tx hash to bytes")?; + tx_hashes.push(bytes32_tx_hash); + + amounts.push(U256::from(value.to_owned())); } let mut hash = [0u8; 32]; let mut hasher_gaurd = appstate.hasher.lock().await; hasher_gaurd.clone().finalize(&mut hash); - let (rs, v) = appstate.signer.sign_prehash_recoverable(&hash).context("failed to sign requests")?; - let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); + let (rs, v) = appstate.signer + .sign_prehash_recoverable(&hash) + .context("failed to sign requests")?; + let signature = hex::encode(rs + .to_bytes() + .append(27 + v.to_byte()) + .as_slice()); - let tx = contract.method::<_, H256>("settle", (tx_hashes, amounts, signature)).context("failed to build transaction request for billing")?; - let pending_tx = tx.send().await?; - let receipt = pending_tx.confirmations(7).await?; + let tx = contract.method::<_, H256>( + "settle", + (tx_hashes, amounts, signature.as_bytes().to_vec())) + .context("failed to build transaction request for billing")?; + let pending_tx = tx + .send() + .await + .context("Error while sending the billing transaction")?; + let receipt = pending_tx + .confirmations(7) + .await + .context("failed to receive confirmation for billing")?; + let tx_hash = receipt + .ok_or(anyhow!("Failed to parse transaction receipt!"))? + .transaction_hash + .to_string(); map_gaurd.clear(); hasher_gaurd.clone_from(&Keccak::v256()); - Ok(receipt.ok_or(anyhow!("Failed to parse transaction receipt!"))?.transaction_hash.to_string()) + Ok(tx_hash) } \ No newline at end of file diff --git a/src/cgroups.rs b/src/cgroups.rs index a0d37ae..e83626f 100644 --- a/src/cgroups.rs +++ b/src/cgroups.rs @@ -54,7 +54,7 @@ impl Cgroups { } fn get_cgroups() -> Result, std::io::Error> { - Ok(fs::read_dir("/sys/fs/cgroup/memory")? + Ok(fs::read_dir("/sys/fs/cgroup")? .filter_map(|dir| { dir.ok().and_then(|dir| { dir.path().file_name().and_then(|name| { diff --git a/src/handler.rs b/src/handler.rs index c31f6d8..d177d07 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -96,7 +96,7 @@ pub async fn serverless( let execution_timer_start = Instant::now(); // reserve cgroup - let cgroup = appstate.cgroups.lock().await.reserve(); + let cgroup = appstate.cgroups.lock().unwrap().reserve(); if let Err(err) = cgroup { // cleanup workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) @@ -123,7 +123,7 @@ pub async fn serverless( let port = workerd::get_port(&cgroup); if let Err(err) = port { // cleanup - appstate.cgroups.lock().await.release(cgroup); + appstate.cgroups.lock().unwrap().release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -147,7 +147,7 @@ pub async fn serverless( // create config file if let Err(err) = workerd::create_config_file(tx_hash, slug, workerd_runtime_path, port).await { // cleanup - appstate.cgroups.lock().await.release(cgroup); + appstate.cgroups.lock().unwrap().release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -183,7 +183,7 @@ pub async fn serverless( .await .context("CRITICAL: failed to clean up config file") .unwrap_or_else(|err| println!("{err:?}")); - appstate.cgroups.lock().await.release(cgroup); + appstate.cgroups.lock().unwrap().release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -209,7 +209,7 @@ pub async fn serverless( .await .context("CRITICAL: failed to clean up config file") .unwrap_or_else(|err| println!("{err:?}")); - appstate.cgroups.lock().await.release(cgroup); + appstate.cgroups.lock().unwrap().release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") @@ -246,7 +246,7 @@ pub async fn serverless( .await .context("CRITICAL: failed to clean up config file") .unwrap_or_else(|err| println!("{err:?}")); - appstate.cgroups.lock().await.release(cgroup); + appstate.cgroups.lock().unwrap().release(cgroup); workerd::cleanup_code_file(tx_hash, slug, workerd_runtime_path) .await .context("CRITICAL: failed to clean up code file") diff --git a/src/model.rs b/src/model.rs index 2e4cdcf..da19ef1 100644 --- a/src/model.rs +++ b/src/model.rs @@ -6,7 +6,7 @@ use std::collections::HashMap; use tiny_keccak::Keccak; pub struct AppState { - pub cgroups: Mutex, + pub cgroups: std::sync::Mutex, // IMPORTANT: we use Relaxed ordering here since we do not need to synchronize any memory // not even with reads/writes to the same atomic (we just serve a few more requests at worst) // be very careful adding more operations associated with the draining state diff --git a/src/workerd.rs b/src/workerd.rs index 5ccb6d6..7325181 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -57,14 +57,20 @@ async fn get_current_deposit( contract_add: &str, abi: &Abi, ) -> Result { - let provider = Provider::::try_from(rpc)?.interval(Duration::from_millis(1000)); + let provider = Provider::::try_from(rpc)? + .interval(Duration::from_millis(1000)); let contract = Contract::new( - contract_add.parse::
()?, - abi.clone(), - Arc::new(provider)); - Ok(contract.method::<_, U256>("balanceOf", tx_hash.to_string())? - .call() - .await?) + contract_add.parse::
()?, + abi.to_owned(), + Arc::new(provider)); + + let mut arg = [0u8; 32]; + hex::decode_to_slice(&tx_hash[2..], &mut arg)?; + + let req = contract.method::<_, U256>("balanceOf", arg)?; + let deposit = req.call().await?; + + Ok(deposit) } async fn get_transaction_data(tx_hash: &str, rpc: &str) -> Result { @@ -95,8 +101,8 @@ pub async fn create_code_file( abi: &Abi, ) -> Result<(), ServerlessError> { let tx_deposit = get_current_deposit(tx_hash, rpc, contract, abi) - .await - .map_err(|err| ServerlessError::TxDepositNotFound)?; + .await + .map_err(|_| ServerlessError::TxDepositNotFound)?; if tx_deposit <= U256::from(200) { // TODO: FIX THE FIXED MINIMUM VALUE return Err(ServerlessError::TxDepositNotEnough); From b67ca15de940241eb16f5fe7143b3bb8ed120a43 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Mon, 29 Jan 2024 03:39:19 +0530 Subject: [PATCH 05/21] minor updates --- Cargo.lock | 33 ++++++++++++++++----------------- Cargo.toml | 2 +- src/billing_job.rs | 33 ++++++++++++++++++--------------- src/cgroups.rs | 2 +- src/handler.rs | 21 ++++++++++++--------- src/lib.rs | 2 +- src/main.rs | 38 +++++++++++++++++++++----------------- src/model.rs | 14 ++++++++------ src/tests.rs | 10 +++++----- src/workerd.rs | 31 ++++++++++++++++--------------- 10 files changed, 99 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f724c4..6c0bd61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,9 +31,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.4.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" +checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f" dependencies = [ "actix-codec", "actix-rt", @@ -65,7 +65,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", - "zstd 0.12.4", + "zstd 0.13.0", ] [[package]] @@ -141,9 +141,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.4.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" +checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b" dependencies = [ "actix-codec", "actix-http", @@ -2262,9 +2262,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -2303,9 +2303,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" dependencies = [ "cc", "libc", @@ -2829,9 +2829,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "base64 0.21.4", "bytes", @@ -4284,11 +4284,11 @@ dependencies = [ [[package]] name = "zstd" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" dependencies = [ - "zstd-safe 6.0.6", + "zstd-safe 7.0.0", ] [[package]] @@ -4303,11 +4303,10 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "6.0.6" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" dependencies = [ - "libc", "zstd-sys", ] diff --git a/Cargo.toml b/Cargo.toml index 1e90ba7..e8b9a18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ data-encoding = "2.5.0" ethers = "2.0.11" hex = "0.4.3" k256 = { version = "0.13.2", features = ["ecdsa", "ecdsa-core"] } -openssl = { version = "0.10", features = ["vendored"] } +openssl = { version = "0.10.60", features = ["vendored"] } rand = "0.8.5" reqwest = { version = "0.11.9", features = ["json"] } serde = { version = "1.0", features = ["derive"] } diff --git a/src/billing_job.rs b/src/billing_job.rs index 6161ce0..bb560bb 100644 --- a/src/billing_job.rs +++ b/src/billing_job.rs @@ -1,18 +1,19 @@ use std::sync::Arc; use std::time::Duration; -use actix_web::web; -use anyhow::{anyhow, Context}; -use tiny_keccak::{Hasher, Keccak}; use crate::model::AppState; + +use actix_web::web::Data; +use anyhow::{anyhow, Context, Error}; use ethers::prelude::*; use k256::elliptic_curve::generic_array::sequence::Lengthen; +use tiny_keccak::{Hasher, Keccak}; -pub async fn billing_scheduler(appstate: web::Data,) -> Result { +pub async fn billing_scheduler(appstate: Data,) -> Result { let provider = Provider::::try_from(&appstate.rpc) .context("Unable to connect to the RPC")? .interval(Duration::from_millis(1000)); - let wallet: LocalWallet = appstate.operator_key + let wallet: LocalWallet = appstate.operator_wallet_key .parse() .context("Unable to parse operator private key")?; @@ -24,19 +25,20 @@ pub async fn billing_scheduler(appstate: web::Data,) -> Result,) -> Result( + let tx_request = contract.method::<_, H256>( "settle", (tx_hashes, amounts, signature.as_bytes().to_vec())) .context("failed to build transaction request for billing")?; - let pending_tx = tx + let pending_tx = tx_request .send() .await .context("Error while sending the billing transaction")?; - let receipt = pending_tx + + let tx_receipt = pending_tx .confirmations(7) .await .context("failed to receive confirmation for billing")?; - let tx_hash = receipt + let tx_hash = tx_receipt .ok_or(anyhow!("Failed to parse transaction receipt!"))? .transaction_hash .to_string(); - map_gaurd.clear(); + costs_gaurd.clear(); hasher_gaurd.clone_from(&Keccak::v256()); Ok(tx_hash) diff --git a/src/cgroups.rs b/src/cgroups.rs index e83626f..a0d37ae 100644 --- a/src/cgroups.rs +++ b/src/cgroups.rs @@ -54,7 +54,7 @@ impl Cgroups { } fn get_cgroups() -> Result, std::io::Error> { - Ok(fs::read_dir("/sys/fs/cgroup")? + Ok(fs::read_dir("/sys/fs/cgroup/memory")? .filter_map(|dir| { dir.ok().and_then(|dir| { dir.path().file_name().and_then(|name| { diff --git a/src/handler.rs b/src/handler.rs index d177d07..3fce1e3 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,12 +1,13 @@ +use std::io::{BufRead, BufReader}; +use std::sync::atomic::Ordering; +use std::time::{Duration, Instant}; + use crate::{cgroups, model::AppState, workerd}; use actix_web::http::{header, StatusCode}; -use actix_web::{web, HttpRequest, HttpResponse, Responder}; +use actix_web::{HttpRequest, HttpResponse, Responder, web}; use anyhow::{anyhow, Context}; use tiny_keccak::Hasher; -use std::io::{BufRead, BufReader}; -use std::sync::atomic::Ordering; -use std::time::{Duration, Instant}; use tokio::time::timeout; pub async fn serverless( @@ -265,17 +266,19 @@ pub async fn serverless( )); } let (response, hash) = response.unwrap(); - appstate.hasher.lock().await.update(&hash); let execution_timer_end = Instant::now(); let execution_time = execution_timer_end .duration_since(execution_timer_start) .as_millis(); - let execution_cost = 1 + 2*execution_time; // TODO: FIX THE VALUE OF FIXED COST AND CONVERSION RATE - let mut map_guard = appstate.service_costs.lock().await; - let fee = map_guard.entry(tx_hash.to_string()).or_insert(0); - *fee += execution_cost; + // TODO: FIX THE VALUE OF FIXED COST AND CONVERSION RATE + let execution_cost = 1 + 2*execution_time; + let mut costs_guard = appstate.execution_costs.lock().await; + let amount = costs_guard.entry(tx_hash.to_string()).or_insert(0); + *amount += execution_cost; + appstate.billing_hasher.lock().await.update(&hash); + return response; } diff --git a/src/lib.rs b/src/lib.rs index c10d052..b53d19a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ +pub mod billing_job; pub mod cgroups; pub mod handler; pub mod model; mod tests; pub mod workerd; -pub mod billing_job; diff --git a/src/main.rs b/src/main.rs index b52ae46..028e0c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,16 @@ use std::collections::HashMap; -use actix_web::{web, App, HttpServer}; + +use serverless::billing_job::billing_scheduler; +use serverless::cgroups::Cgroups; +use serverless::model::AppState; + +use actix_web::{App, HttpServer, web}; use anyhow::{anyhow, Context}; use clap::Parser; use ethers::abi::Abi; -use serverless::billing_job; use tiny_keccak::Keccak; use tokio::fs; - -use serverless::cgroups::Cgroups; -use serverless::model::AppState; -use tokio::time::{interval, Duration}; +use tokio::time::{Duration, interval}; /// Simple program to greet a person #[derive(Parser, Debug)] @@ -39,7 +40,7 @@ struct Args { contract: String, #[clap(long, value_parser)] - operator_key: String, + operator_wallet_key: String, #[clap(long, value_parser)] signer: String, @@ -74,10 +75,11 @@ async fn main() -> anyhow::Result<()> { ) .context("invalid signer key")?; - let abi_json = fs::read_to_string("src/contract_abi.json") - .await - .context("failed to read contract ABI")?; - let abi = serde_json::from_str::(&abi_json).context("failed to deserialize ABI")?; + let abi_json_string = fs::read_to_string("src/contract_abi.json") + .await + .context("failed to read contract ABI")?; + let abi = serde_json::from_str::(&abi_json_string) + .context("failed to deserialize ABI")?; let app_data = web::Data::new(AppState { cgroups: cgroups.into(), @@ -87,9 +89,9 @@ async fn main() -> anyhow::Result<()> { contract: cli.contract, signer: signer, abi: abi, - operator_key: cli.operator_key, - service_costs: HashMap::new().into(), - hasher: Keccak::v256().into(), + operator_wallet_key: cli.operator_wallet_key, + execution_costs: HashMap::new().into(), + billing_hasher: Keccak::v256().into(), }); let app_data_clone = app_data.clone(); @@ -107,12 +109,14 @@ async fn main() -> anyhow::Result<()> { server.await?; tokio::spawn(async move { - let mut interval = interval(Duration::from_secs(600)); // TODO: FIX THE REGULAR INTERVAL + // TODO: FIX THE REGULAR INTERVAL + let mut interval = interval(Duration::from_secs(600)); loop { interval.tick().await; - if !app_data_clone.service_costs.lock().await.is_empty() { - match billing_job::billing_scheduler(app_data_clone.clone()).await { + if !app_data_clone.execution_costs.lock().await.is_empty() { + + match billing_scheduler(app_data_clone.clone()).await { Ok(tx_hash) => println!("Transaction sent for billing: {}", tx_hash), Err(err) => println!("Error while sending billing transaction: {:?}", err), } diff --git a/src/model.rs b/src/model.rs index da19ef1..374607b 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,9 +1,11 @@ -use crate::cgroups::Cgroups; use std::sync::atomic::AtomicBool; -use ethers::abi::Abi; -use tokio::sync::Mutex; use std::collections::HashMap; + +use crate::cgroups::Cgroups; + +use ethers::abi::Abi; use tiny_keccak::Keccak; +use tokio::sync::Mutex; pub struct AppState { pub cgroups: std::sync::Mutex, @@ -16,7 +18,7 @@ pub struct AppState { pub contract: String, pub signer: k256::ecdsa::SigningKey, pub abi: Abi, - pub operator_key: String, - pub service_costs: Mutex>, - pub hasher: Mutex, + pub operator_wallet_key: String, + pub execution_costs: Mutex>, + pub billing_hasher: Mutex, } diff --git a/src/tests.rs b/src/tests.rs index 531dbfa..47b33cd 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -5,6 +5,7 @@ #[cfg(test)] pub mod serverlesstest { + use std::{collections::HashMap, fs::File, io::Read, sync::atomic::AtomicBool}; use crate::cgroups::Cgroups; use crate::handler; use crate::model::AppState; @@ -17,7 +18,6 @@ pub mod serverlesstest { use ethers::abi::Abi; use serde_json::json; use tiny_keccak::Keccak; - use std::{collections::HashMap, io::Read, sync::atomic::AtomicBool}; fn new_app() -> App< impl ServiceFactory< @@ -29,7 +29,7 @@ pub mod serverlesstest { >, > { let mut abi_json = String::new(); - let mut file = std::fs::File::open("src/contract_abi.json").unwrap(); + let mut file = File::open("src/contract_abi.json").unwrap(); file.read_to_string(&mut abi_json).unwrap(); let abi = serde_json::from_str::(&abi_json).unwrap(); @@ -42,9 +42,9 @@ pub mod serverlesstest { contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), abi: abi, signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), - operator_key: String::new(), - service_costs: HashMap::new().into(), - hasher: Keccak::v256().into(), + operator_wallet_key: String::new(), //TODO: ADD A WALLET KEY FOR RUNNING TESTS + execution_costs: HashMap::new().into(), + billing_hasher: Keccak::v256().into(), })) .default_service(web::to(handler::serverless)) } diff --git a/src/workerd.rs b/src/workerd.rs index 7325181..6801297 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -1,21 +1,22 @@ +use std::{convert::TryFrom, sync::Arc}; use std::process::Child; use std::time::{Duration, Instant}; -use thiserror::Error; +use crate::cgroups::{Cgroups, CgroupsError}; use actix_web::{HttpRequest, HttpResponse}; +use anyhow::Error; +use ethers::core::abi::Abi; +use ethers::prelude::*; use k256::elliptic_curve::generic_array::sequence::Lengthen; use reqwest::Client; use serde_json::{json, Value}; +use thiserror::Error; use tiny_keccak::{Hasher, Keccak}; +use tokio::fs::File; +use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; use tokio::time::sleep; -use ethers::prelude::*; -use ethers::core::abi::Abi; -use tokio::io::AsyncWriteExt; -use std::{convert::TryFrom, sync::Arc}; - -use crate::cgroups::{Cgroups, CgroupsError}; #[derive(Error, Debug)] pub enum ServerlessError { @@ -56,7 +57,7 @@ async fn get_current_deposit( rpc: &str, contract_add: &str, abi: &Abi, -) -> Result { +) -> Result { let provider = Provider::::try_from(rpc)? .interval(Duration::from_millis(1000)); let contract = Contract::new( @@ -64,10 +65,10 @@ async fn get_current_deposit( abi.to_owned(), Arc::new(provider)); - let mut arg = [0u8; 32]; - hex::decode_to_slice(&tx_hash[2..], &mut arg)?; + let mut bytes32_tx_hash = [0u8; 32]; + hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?; - let req = contract.method::<_, U256>("balanceOf", arg)?; + let req = contract.method::<_, U256>("balanceOf", bytes32_tx_hash)?; let deposit = req.call().await?; Ok(deposit) @@ -103,8 +104,8 @@ pub async fn create_code_file( let tx_deposit = get_current_deposit(tx_hash, rpc, contract, abi) .await .map_err(|_| ServerlessError::TxDepositNotFound)?; - - if tx_deposit <= U256::from(200) { // TODO: FIX THE FIXED MINIMUM VALUE + // TODO: FIX THE FIXED MINIMUM VALUE + if tx_deposit <= U256::from(200) { return Err(ServerlessError::TxDepositNotEnough); } @@ -143,7 +144,7 @@ pub async fn create_code_file( // write calldata to file let mut file = - tokio::fs::File::create(workerd_runtime_path.to_owned() + "/" + tx_hash + "-" + slug + ".js") + File::create(workerd_runtime_path.to_owned() + "/" + tx_hash + "-" + slug + ".js") .await .map_err(ServerlessError::CodeFileCreate)?; file.write_all(calldata.as_slice()) @@ -176,7 +177,7 @@ const oysterWorker :Workerd.Worker = ( ); let mut file = - tokio::fs::File::create(workerd_runtime_path.to_owned() + "/" + tx_hash + "-" + slug + ".capnp") + File::create(workerd_runtime_path.to_owned() + "/" + tx_hash + "-" + slug + ".capnp") .await .map_err(ServerlessError::ConfigFileCreate)?; file.write_all(capnp_data.as_bytes()) From a2959804bfe893f377963d27916f7c1b4016af26 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Mon, 29 Jan 2024 19:22:17 +0530 Subject: [PATCH 06/21] minor fixes --- src/billing_job.rs | 12 ++++++------ src/handler.rs | 3 ++- src/main.rs | 4 ++++ src/model.rs | 1 + src/tests.rs | 1 + src/workerd.rs | 24 +++++++++++++----------- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/billing_job.rs b/src/billing_job.rs index bb560bb..7c12e1f 100644 --- a/src/billing_job.rs +++ b/src/billing_job.rs @@ -5,7 +5,7 @@ use crate::model::AppState; use actix_web::web::Data; use anyhow::{anyhow, Context, Error}; -use ethers::prelude::*; +use ethers::{abi::Token, prelude::*}; use k256::elliptic_curve::generic_array::sequence::Lengthen; use tiny_keccak::{Hasher, Keccak}; @@ -19,9 +19,9 @@ pub async fn billing_scheduler(appstate: Data,) -> Result() - .context("Unable to parse contract address")?, + appstate.billing_contract.as_str() + .parse::
() + .context("Unable to parse contract address")?, appstate.abi.to_owned(), Arc::new(client)); @@ -50,13 +50,13 @@ pub async fn billing_scheduler(appstate: Data,) -> Result( "settle", - (tx_hashes, amounts, signature.as_bytes().to_vec())) + (tx_hashes, amounts, Token::Bytes(signature.into_bytes()))) .context("failed to build transaction request for billing")?; let pending_tx = tx_request .send() .await .context("Error while sending the billing transaction")?; - + let tx_receipt = pending_tx .confirmations(7) .await diff --git a/src/handler.rs b/src/handler.rs index 3fce1e3..1ab93e3 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -67,6 +67,7 @@ pub async fn serverless( workerd_runtime_path, &appstate.rpc, &appstate.contract, + &appstate.billing_contract, &appstate.abi, ) .await @@ -279,6 +280,6 @@ pub async fn serverless( *amount += execution_cost; appstate.billing_hasher.lock().await.update(&hash); - + return response; } diff --git a/src/main.rs b/src/main.rs index 028e0c7..a5424a4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,9 @@ struct Args { )] contract: String, + #[clap(long, value_parser)] + billing_contract: String, + #[clap(long, value_parser)] operator_wallet_key: String, @@ -87,6 +90,7 @@ async fn main() -> anyhow::Result<()> { runtime_path: cli.runtime_path, rpc: cli.rpc, contract: cli.contract, + billing_contract: cli.billing_contract, signer: signer, abi: abi, operator_wallet_key: cli.operator_wallet_key, diff --git a/src/model.rs b/src/model.rs index 374607b..3198e99 100644 --- a/src/model.rs +++ b/src/model.rs @@ -16,6 +16,7 @@ pub struct AppState { pub runtime_path: String, pub rpc: String, pub contract: String, + pub billing_contract: String, pub signer: k256::ecdsa::SigningKey, pub abi: Abi, pub operator_wallet_key: String, diff --git a/src/tests.rs b/src/tests.rs index 47b33cd..20debe4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -40,6 +40,7 @@ pub mod serverlesstest { runtime_path: "./runtime/".to_owned(), rpc: "https://sepolia-rollup.arbitrum.io/rpc".to_owned(), contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), + billing_contract: String::new(), // TODO: ADD BILLING CONTRACT FOR TESTS abi: abi, signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), operator_wallet_key: String::new(), //TODO: ADD A WALLET KEY FOR RUNNING TESTS diff --git a/src/workerd.rs b/src/workerd.rs index 6801297..3815847 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -55,15 +55,15 @@ pub enum ServerlessError { async fn get_current_deposit( tx_hash: &str, rpc: &str, - contract_add: &str, + billing_contract_add: &str, abi: &Abi, ) -> Result { let provider = Provider::::try_from(rpc)? .interval(Duration::from_millis(1000)); let contract = Contract::new( - contract_add.parse::
()?, + billing_contract_add.parse::
()?, abi.to_owned(), - Arc::new(provider)); + Arc::new(provider)); let mut bytes32_tx_hash = [0u8; 32]; hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?; @@ -99,16 +99,9 @@ pub async fn create_code_file( workerd_runtime_path: &str, rpc: &str, contract: &str, + billing_contract: &str, abi: &Abi, ) -> Result<(), ServerlessError> { - let tx_deposit = get_current_deposit(tx_hash, rpc, contract, abi) - .await - .map_err(|_| ServerlessError::TxDepositNotFound)?; - // TODO: FIX THE FIXED MINIMUM VALUE - if tx_deposit <= U256::from(200) { - return Err(ServerlessError::TxDepositNotEnough); - } - // get tx data let mut tx_data = match get_transaction_data(tx_hash, rpc).await?["result"].take() { Value::Null => Err(ServerlessError::TxNotFound), @@ -135,6 +128,15 @@ pub async fn create_code_file( _ => Err(ServerlessError::InvalidTxCalldataType), }?; + // get tx deposit + let tx_deposit = get_current_deposit(tx_hash, rpc, billing_contract, abi) + .await + .map_err(|_| ServerlessError::TxDepositNotFound)?; + // TODO: FIX THE FIXED MINIMUM VALUE + if tx_deposit <= U256::from(200) { + return Err(ServerlessError::TxDepositNotEnough); + } + // hex decode calldata by skipping to the code bytes let mut calldata = hex::decode(&calldata[138..])?; From 0295563a7252e968a9aa3b6acddf01be0b34bb90 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Wed, 31 Jan 2024 06:55:35 +0530 Subject: [PATCH 07/21] run server to retrieve bill info --- src/bill_handler.rs | 33 ++++++++++++++++++++ src/billing_job.rs | 73 --------------------------------------------- src/handler.rs | 20 ++++++++----- src/lib.rs | 2 +- src/main.rs | 51 +++++++++++-------------------- src/model.rs | 8 ++--- src/tests.rs | 14 ++------- src/workerd.rs | 36 +++++++++++----------- 8 files changed, 87 insertions(+), 150 deletions(-) create mode 100644 src/bill_handler.rs delete mode 100644 src/billing_job.rs diff --git a/src/bill_handler.rs b/src/bill_handler.rs new file mode 100644 index 0000000..de6311b --- /dev/null +++ b/src/bill_handler.rs @@ -0,0 +1,33 @@ +use crate::model::AppState; + +use actix_web::{web::Data, HttpResponse}; +use anyhow::Context; +use k256::elliptic_curve::generic_array::sequence::Lengthen; +use serde_json::json; +use tiny_keccak::{Hasher, Keccak}; + +pub async fn bill_data(appstate: Data) -> HttpResponse { + let mut costs_gaurd = appstate.execution_costs.lock().unwrap(); + let costs_map = costs_gaurd.clone(); + + let mut hash = [0u8; 32]; + let mut hasher_gaurd = appstate.billing_hasher.lock().unwrap(); + hasher_gaurd.clone().finalize(&mut hash); + let sign = appstate + .signer + .sign_prehash_recoverable(&hash) + .context("Failed to sign requests data"); + if sign.is_err() { + return HttpResponse::InternalServerError().body(format!("{:?}", sign.unwrap_err())); + } + let (rs, v) = sign.unwrap(); + let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); + + costs_gaurd.clear(); + hasher_gaurd.clone_from(&Keccak::v256()); + + HttpResponse::Ok().json(json!({ + "execution_costs": costs_map, + "signature": signature, + })) +} diff --git a/src/billing_job.rs b/src/billing_job.rs deleted file mode 100644 index 7c12e1f..0000000 --- a/src/billing_job.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::sync::Arc; -use std::time::Duration; - -use crate::model::AppState; - -use actix_web::web::Data; -use anyhow::{anyhow, Context, Error}; -use ethers::{abi::Token, prelude::*}; -use k256::elliptic_curve::generic_array::sequence::Lengthen; -use tiny_keccak::{Hasher, Keccak}; - -pub async fn billing_scheduler(appstate: Data,) -> Result { - let provider = Provider::::try_from(&appstate.rpc) - .context("Unable to connect to the RPC")? - .interval(Duration::from_millis(1000)); - let wallet: LocalWallet = appstate.operator_wallet_key - .parse() - .context("Unable to parse operator private key")?; - - let client = SignerMiddleware::new(provider, wallet); - let contract = Contract::new( - appstate.billing_contract.as_str() - .parse::
() - .context("Unable to parse contract address")?, - appstate.abi.to_owned(), - Arc::new(client)); - - let mut costs_gaurd = appstate.execution_costs.lock().await; - let mut tx_hashes = Vec::new(); - let mut amounts = Vec::new(); - for (tx_hash, amount) in costs_gaurd.clone().iter() { - let mut bytes32_tx_hash = [0u8; 32]; - hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash) - .context("failed to decode tx hash to bytes")?; - tx_hashes.push(bytes32_tx_hash); - - amounts.push(U256::from(amount.to_owned())); - } - - let mut hash = [0u8; 32]; - let mut hasher_gaurd = appstate.billing_hasher.lock().await; - hasher_gaurd.clone().finalize(&mut hash); - let (rs, v) = appstate.signer - .sign_prehash_recoverable(&hash) - .context("failed to sign requests")?; - let signature = hex::encode(rs - .to_bytes() - .append(27 + v.to_byte()) - .as_slice()); - - let tx_request = contract.method::<_, H256>( - "settle", - (tx_hashes, amounts, Token::Bytes(signature.into_bytes()))) - .context("failed to build transaction request for billing")?; - let pending_tx = tx_request - .send() - .await - .context("Error while sending the billing transaction")?; - - let tx_receipt = pending_tx - .confirmations(7) - .await - .context("failed to receive confirmation for billing")?; - let tx_hash = tx_receipt - .ok_or(anyhow!("Failed to parse transaction receipt!"))? - .transaction_hash - .to_string(); - - costs_gaurd.clear(); - hasher_gaurd.clone_from(&Keccak::v256()); - - Ok(tx_hash) -} \ No newline at end of file diff --git a/src/handler.rs b/src/handler.rs index 1ab93e3..4d27796 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -5,7 +5,7 @@ use std::time::{Duration, Instant}; use crate::{cgroups, model::AppState, workerd}; use actix_web::http::{header, StatusCode}; -use actix_web::{HttpRequest, HttpResponse, Responder, web}; +use actix_web::{web, HttpRequest, HttpResponse, Responder}; use anyhow::{anyhow, Context}; use tiny_keccak::Hasher; use tokio::time::timeout; @@ -68,7 +68,6 @@ pub async fn serverless( &appstate.rpc, &appstate.contract, &appstate.billing_contract, - &appstate.abi, ) .await { @@ -272,14 +271,19 @@ pub async fn serverless( let execution_time = execution_timer_end .duration_since(execution_timer_start) .as_millis(); - + // TODO: FIX THE VALUE OF FIXED COST AND CONVERSION RATE - let execution_cost = 1 + 2*execution_time; - let mut costs_guard = appstate.execution_costs.lock().await; - let amount = costs_guard.entry(tx_hash.to_string()).or_insert(0); - *amount += execution_cost; + let execution_cost = 1 + 2 * execution_time; + + appstate + .execution_costs + .lock() + .unwrap() + .entry(tx_hash.to_owned()) + .and_modify(|cost| *cost += execution_cost) + .or_insert(execution_cost); - appstate.billing_hasher.lock().await.update(&hash); + appstate.billing_hasher.lock().unwrap().update(&hash); return response; } diff --git a/src/lib.rs b/src/lib.rs index b53d19a..5334c5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -pub mod billing_job; +pub mod bill_handler; pub mod cgroups; pub mod handler; pub mod model; diff --git a/src/main.rs b/src/main.rs index a5424a4..5113b5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,13 @@ use std::collections::HashMap; -use serverless::billing_job::billing_scheduler; use serverless::cgroups::Cgroups; use serverless::model::AppState; -use actix_web::{App, HttpServer, web}; +use actix_web::{web, App, HttpServer}; use anyhow::{anyhow, Context}; use clap::Parser; -use ethers::abi::Abi; use tiny_keccak::Keccak; use tokio::fs; -use tokio::time::{Duration, interval}; /// Simple program to greet a person #[derive(Parser, Debug)] @@ -19,6 +16,9 @@ struct Args { #[clap(long, value_parser, default_value = "6001")] port: u16, + #[clap(long, value_parser)] + bill_port: u16, // TODO: ADD THE DEFAULT PORT + #[clap(long, value_parser, default_value = "./runtime/")] runtime_path: String, @@ -40,10 +40,7 @@ struct Args { contract: String, #[clap(long, value_parser)] - billing_contract: String, - - #[clap(long, value_parser)] - operator_wallet_key: String, + billing_contract: String, // TODO: ADD A DEFAULT ADDRESS #[clap(long, value_parser)] signer: String, @@ -64,6 +61,7 @@ async fn main() -> anyhow::Result<()> { // println!("{:?}", response); let port: u16 = cli.port; + let bill_port: u16 = cli.bill_port; let cgroups = Cgroups::new().context("failed to construct cgroups")?; if cgroups.free.is_empty() { @@ -77,12 +75,6 @@ async fn main() -> anyhow::Result<()> { .as_slice(), ) .context("invalid signer key")?; - - let abi_json_string = fs::read_to_string("src/contract_abi.json") - .await - .context("failed to read contract ABI")?; - let abi = serde_json::from_str::(&abi_json_string) - .context("failed to deserialize ABI")?; let app_data = web::Data::new(AppState { cgroups: cgroups.into(), @@ -92,8 +84,6 @@ async fn main() -> anyhow::Result<()> { contract: cli.contract, billing_contract: cli.billing_contract, signer: signer, - abi: abi, - operator_wallet_key: cli.operator_wallet_key, execution_costs: HashMap::new().into(), billing_hasher: Keccak::v256().into(), }); @@ -110,23 +100,18 @@ async fn main() -> anyhow::Result<()> { println!("Server started on port {}", port); - server.await?; - - tokio::spawn(async move { - // TODO: FIX THE REGULAR INTERVAL - let mut interval = interval(Duration::from_secs(600)); - loop { - interval.tick().await; - - if !app_data_clone.execution_costs.lock().await.is_empty() { - - match billing_scheduler(app_data_clone.clone()).await { - Ok(tx_hash) => println!("Transaction sent for billing: {}", tx_hash), - Err(err) => println!("Error while sending billing transaction: {:?}", err), - } - } - } - }); + let bill_server = HttpServer::new(move || { + App::new() + .app_data(app_data_clone.clone()) + .default_service(web::to(serverless::bill_handler::bill_data)) + }) + .bind(("0.0.0.0", bill_port)) + .context(format!("could not bind to port {bill_port}"))? + .run(); + + println!("Bill Server started on port {}", bill_port); + + tokio::try_join!(server, bill_server)?; Ok(()) } diff --git a/src/model.rs b/src/model.rs index 3198e99..17544a0 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,14 +1,12 @@ -use std::sync::atomic::AtomicBool; use std::collections::HashMap; +use std::sync::{atomic::AtomicBool, Mutex}; use crate::cgroups::Cgroups; -use ethers::abi::Abi; use tiny_keccak::Keccak; -use tokio::sync::Mutex; pub struct AppState { - pub cgroups: std::sync::Mutex, + pub cgroups: Mutex, // IMPORTANT: we use Relaxed ordering here since we do not need to synchronize any memory // not even with reads/writes to the same atomic (we just serve a few more requests at worst) // be very careful adding more operations associated with the draining state @@ -18,8 +16,6 @@ pub struct AppState { pub contract: String, pub billing_contract: String, pub signer: k256::ecdsa::SigningKey, - pub abi: Abi, - pub operator_wallet_key: String, pub execution_costs: Mutex>, pub billing_hasher: Mutex, } diff --git a/src/tests.rs b/src/tests.rs index 20debe4..40ab975 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -5,7 +5,6 @@ #[cfg(test)] pub mod serverlesstest { - use std::{collections::HashMap, fs::File, io::Read, sync::atomic::AtomicBool}; use crate::cgroups::Cgroups; use crate::handler; use crate::model::AppState; @@ -15,8 +14,8 @@ pub mod serverlesstest { error::Error, http, test, web, App, }; - use ethers::abi::Abi; use serde_json::json; + use std::{collections::HashMap, sync::atomic::AtomicBool}; use tiny_keccak::Keccak; fn new_app() -> App< @@ -27,12 +26,7 @@ pub mod serverlesstest { InitError = (), Error = Error, >, - > { - let mut abi_json = String::new(); - let mut file = File::open("src/contract_abi.json").unwrap(); - file.read_to_string(&mut abi_json).unwrap(); - let abi = serde_json::from_str::(&abi_json).unwrap(); - + > { App::new() .app_data(web::Data::new(AppState { cgroups: Cgroups::new().unwrap().into(), @@ -40,10 +34,8 @@ pub mod serverlesstest { runtime_path: "./runtime/".to_owned(), rpc: "https://sepolia-rollup.arbitrum.io/rpc".to_owned(), contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), - billing_contract: String::new(), // TODO: ADD BILLING CONTRACT FOR TESTS - abi: abi, + billing_contract: String::new(), // TODO: ADD BILLING CONTRACT FOR TESTS signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), - operator_wallet_key: String::new(), //TODO: ADD A WALLET KEY FOR RUNNING TESTS execution_costs: HashMap::new().into(), billing_hasher: Keccak::v256().into(), })) diff --git a/src/workerd.rs b/src/workerd.rs index 3815847..c835cda 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -1,6 +1,6 @@ -use std::{convert::TryFrom, sync::Arc}; use std::process::Child; use std::time::{Duration, Instant}; +use std::{convert::TryFrom, sync::Arc}; use crate::cgroups::{Cgroups, CgroupsError}; @@ -13,10 +13,10 @@ use reqwest::Client; use serde_json::{json, Value}; use thiserror::Error; use tiny_keccak::{Hasher, Keccak}; -use tokio::fs::File; use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; use tokio::time::sleep; +use tokio::{fs, fs::File}; #[derive(Error, Debug)] pub enum ServerlessError { @@ -53,25 +53,27 @@ pub enum ServerlessError { } async fn get_current_deposit( - tx_hash: &str, - rpc: &str, + tx_hash: &str, + rpc: &str, billing_contract_add: &str, - abi: &Abi, ) -> Result { - let provider = Provider::::try_from(rpc)? - .interval(Duration::from_millis(1000)); + let abi_json_string = fs::read_to_string("src/contract_abi.json").await?; + let abi = serde_json::from_str::(&abi_json_string)?; + + let provider = Provider::::try_from(rpc)?.interval(Duration::from_millis(1000)); let contract = Contract::new( - billing_contract_add.parse::
()?, - abi.to_owned(), - Arc::new(provider)); + billing_contract_add.parse::
()?, + abi.to_owned(), + Arc::new(provider), + ); let mut bytes32_tx_hash = [0u8; 32]; - hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?; + hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?; let req = contract.method::<_, U256>("balanceOf", bytes32_tx_hash)?; - let deposit = req.call().await?; + let deposit = req.call().await?; - Ok(deposit) + Ok(deposit) } async fn get_transaction_data(tx_hash: &str, rpc: &str) -> Result { @@ -100,7 +102,6 @@ pub async fn create_code_file( rpc: &str, contract: &str, billing_contract: &str, - abi: &Abi, ) -> Result<(), ServerlessError> { // get tx data let mut tx_data = match get_transaction_data(tx_hash, rpc).await?["result"].take() { @@ -129,12 +130,12 @@ pub async fn create_code_file( }?; // get tx deposit - let tx_deposit = get_current_deposit(tx_hash, rpc, billing_contract, abi) + let tx_deposit = get_current_deposit(tx_hash, rpc, billing_contract) .await .map_err(|_| ServerlessError::TxDepositNotFound)?; // TODO: FIX THE FIXED MINIMUM VALUE - if tx_deposit <= U256::from(200) { - return Err(ServerlessError::TxDepositNotEnough); + if tx_deposit <= U256::from(200) { + return Err(ServerlessError::TxDepositNotEnough); } // hex decode calldata by skipping to the code bytes @@ -251,7 +252,6 @@ pub async fn get_workerd_response( body: actix_web::web::Bytes, signer: &k256::ecdsa::SigningKey, host_header: &str, - ) -> Result<(HttpResponse, [u8; 32]), anyhow::Error> { let mut hasher = Keccak::v256(); hasher.update(b"|oyster-serverless-hasher|"); From a8a0ee744c51e98cfd3573892afc6094dff279aa Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Thu, 8 Feb 2024 15:10:34 +0530 Subject: [PATCH 08/21] use abigen to create bindings during compile time --- .../billing_contract_abi.json} | 0 src/workerd.rs | 22 +++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) rename src/{contract_abi.json => contracts/billing_contract_abi.json} (100%) diff --git a/src/contract_abi.json b/src/contracts/billing_contract_abi.json similarity index 100% rename from src/contract_abi.json rename to src/contracts/billing_contract_abi.json diff --git a/src/workerd.rs b/src/workerd.rs index c835cda..cf4ca6c 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -6,17 +6,22 @@ use crate::cgroups::{Cgroups, CgroupsError}; use actix_web::{HttpRequest, HttpResponse}; use anyhow::Error; -use ethers::core::abi::Abi; use ethers::prelude::*; use k256::elliptic_curve::generic_array::sequence::Lengthen; use reqwest::Client; use serde_json::{json, Value}; use thiserror::Error; use tiny_keccak::{Hasher, Keccak}; +use tokio::fs::File; use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; use tokio::time::sleep; -use tokio::{fs, fs::File}; + +abigen!( + BillingContract, + "src/contracts/billing_contract_abi.json", + derives(serde::Serialize, serde::Deserialize) +); #[derive(Error, Debug)] pub enum ServerlessError { @@ -57,21 +62,14 @@ async fn get_current_deposit( rpc: &str, billing_contract_add: &str, ) -> Result { - let abi_json_string = fs::read_to_string("src/contract_abi.json").await?; - let abi = serde_json::from_str::(&abi_json_string)?; - let provider = Provider::::try_from(rpc)?.interval(Duration::from_millis(1000)); - let contract = Contract::new( - billing_contract_add.parse::
()?, - abi.to_owned(), - Arc::new(provider), - ); + let contract = + BillingContract::new(billing_contract_add.parse::
()?, Arc::new(provider)); let mut bytes32_tx_hash = [0u8; 32]; hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?; - let req = contract.method::<_, U256>("balanceOf", bytes32_tx_hash)?; - let deposit = req.call().await?; + let deposit = contract.balance_of(bytes32_tx_hash).call().await?; Ok(deposit) } From 4502fbce8bfc64e051a4d15b9abfa8036401fa87 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Fri, 9 Feb 2024 11:38:08 +0530 Subject: [PATCH 09/21] renaming --- src/{bill_handler.rs => billing_handler.rs} | 2 +- src/lib.rs | 2 +- src/main.rs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) rename src/{bill_handler.rs => billing_handler.rs} (93%) diff --git a/src/bill_handler.rs b/src/billing_handler.rs similarity index 93% rename from src/bill_handler.rs rename to src/billing_handler.rs index de6311b..bf94c27 100644 --- a/src/bill_handler.rs +++ b/src/billing_handler.rs @@ -6,7 +6,7 @@ use k256::elliptic_curve::generic_array::sequence::Lengthen; use serde_json::json; use tiny_keccak::{Hasher, Keccak}; -pub async fn bill_data(appstate: Data) -> HttpResponse { +pub async fn billing_data(appstate: Data) -> HttpResponse { let mut costs_gaurd = appstate.execution_costs.lock().unwrap(); let costs_map = costs_gaurd.clone(); diff --git a/src/lib.rs b/src/lib.rs index 5334c5a..560f700 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -pub mod bill_handler; +pub mod billing_handler; pub mod cgroups; pub mod handler; pub mod model; diff --git a/src/main.rs b/src/main.rs index 5113b5d..620eca2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ struct Args { port: u16, #[clap(long, value_parser)] - bill_port: u16, // TODO: ADD THE DEFAULT PORT + billing_port: u16, // TODO: ADD THE DEFAULT PORT #[clap(long, value_parser, default_value = "./runtime/")] runtime_path: String, @@ -61,7 +61,7 @@ async fn main() -> anyhow::Result<()> { // println!("{:?}", response); let port: u16 = cli.port; - let bill_port: u16 = cli.bill_port; + let billing_port: u16 = cli.billing_port; let cgroups = Cgroups::new().context("failed to construct cgroups")?; if cgroups.free.is_empty() { @@ -100,18 +100,18 @@ async fn main() -> anyhow::Result<()> { println!("Server started on port {}", port); - let bill_server = HttpServer::new(move || { + let billing_server = HttpServer::new(move || { App::new() .app_data(app_data_clone.clone()) - .default_service(web::to(serverless::bill_handler::bill_data)) + .default_service(web::to(serverless::billing_handler::billing_data)) }) - .bind(("0.0.0.0", bill_port)) - .context(format!("could not bind to port {bill_port}"))? + .bind(("0.0.0.0", billing_port)) + .context(format!("could not bind to port {billing_port}"))? .run(); - println!("Bill Server started on port {}", bill_port); + println!("Billing Server started on port {}", billing_port); - tokio::try_join!(server, bill_server)?; + tokio::try_join!(server, billing_server)?; Ok(()) } From 2ef0b87115e8d34084825f52d1df7f54f665ceef Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Fri, 9 Feb 2024 13:42:58 +0530 Subject: [PATCH 10/21] add signature for bill generated --- src/billing_handler.rs | 34 +++++++++++++++++++++++++++++----- src/handler.rs | 5 +---- src/main.rs | 2 -- src/model.rs | 3 --- src/tests.rs | 2 -- src/workerd.rs | 4 ++-- 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index bf94c27..b3b5014 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -8,11 +8,35 @@ use tiny_keccak::{Hasher, Keccak}; pub async fn billing_data(appstate: Data) -> HttpResponse { let mut costs_gaurd = appstate.execution_costs.lock().unwrap(); - let costs_map = costs_gaurd.clone(); + + if costs_gaurd.is_empty() { + return HttpResponse::BadRequest().body("Bill is empty"); + } + + let tx_hashes: Vec = costs_gaurd.keys().cloned().collect(); + let amounts: Vec = costs_gaurd.values().cloned().collect(); + + let mut hasher = Keccak::v256(); + hasher.update(b"|txhashes|"); + hasher.update( + tx_hashes + .iter() + .flat_map(|txhash| txhash.as_bytes().to_vec()) + .collect::>() + .as_slice(), + ); + hasher.update(b"|amounts|"); + hasher.update( + amounts + .iter() + .flat_map(|amount| amount.to_be_bytes().to_vec()) + .collect::>() + .as_slice(), + ); let mut hash = [0u8; 32]; - let mut hasher_gaurd = appstate.billing_hasher.lock().unwrap(); - hasher_gaurd.clone().finalize(&mut hash); + hasher.finalize(&mut hash); + let sign = appstate .signer .sign_prehash_recoverable(&hash) @@ -24,10 +48,10 @@ pub async fn billing_data(appstate: Data) -> HttpResponse { let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); costs_gaurd.clear(); - hasher_gaurd.clone_from(&Keccak::v256()); HttpResponse::Ok().json(json!({ - "execution_costs": costs_map, + "txhashes": tx_hashes, + "amounts": amounts, "signature": signature, })) } diff --git a/src/handler.rs b/src/handler.rs index 4d27796..0dec693 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -7,7 +7,6 @@ use crate::{cgroups, model::AppState, workerd}; use actix_web::http::{header, StatusCode}; use actix_web::{web, HttpRequest, HttpResponse, Responder}; use anyhow::{anyhow, Context}; -use tiny_keccak::Hasher; use tokio::time::timeout; pub async fn serverless( @@ -265,7 +264,7 @@ pub async fn serverless( anyhow!(err).context("failed to get a response") )); } - let (response, hash) = response.unwrap(); + let response = response.unwrap(); let execution_timer_end = Instant::now(); let execution_time = execution_timer_end @@ -283,7 +282,5 @@ pub async fn serverless( .and_modify(|cost| *cost += execution_cost) .or_insert(execution_cost); - appstate.billing_hasher.lock().unwrap().update(&hash); - return response; } diff --git a/src/main.rs b/src/main.rs index 620eca2..cef634f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ use serverless::model::AppState; use actix_web::{web, App, HttpServer}; use anyhow::{anyhow, Context}; use clap::Parser; -use tiny_keccak::Keccak; use tokio::fs; /// Simple program to greet a person @@ -85,7 +84,6 @@ async fn main() -> anyhow::Result<()> { billing_contract: cli.billing_contract, signer: signer, execution_costs: HashMap::new().into(), - billing_hasher: Keccak::v256().into(), }); let app_data_clone = app_data.clone(); diff --git a/src/model.rs b/src/model.rs index 17544a0..879a2ec 100644 --- a/src/model.rs +++ b/src/model.rs @@ -3,8 +3,6 @@ use std::sync::{atomic::AtomicBool, Mutex}; use crate::cgroups::Cgroups; -use tiny_keccak::Keccak; - pub struct AppState { pub cgroups: Mutex, // IMPORTANT: we use Relaxed ordering here since we do not need to synchronize any memory @@ -17,5 +15,4 @@ pub struct AppState { pub billing_contract: String, pub signer: k256::ecdsa::SigningKey, pub execution_costs: Mutex>, - pub billing_hasher: Mutex, } diff --git a/src/tests.rs b/src/tests.rs index 40ab975..9d8f83b 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -16,7 +16,6 @@ pub mod serverlesstest { }; use serde_json::json; use std::{collections::HashMap, sync::atomic::AtomicBool}; - use tiny_keccak::Keccak; fn new_app() -> App< impl ServiceFactory< @@ -37,7 +36,6 @@ pub mod serverlesstest { billing_contract: String::new(), // TODO: ADD BILLING CONTRACT FOR TESTS signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), execution_costs: HashMap::new().into(), - billing_hasher: Keccak::v256().into(), })) .default_service(web::to(handler::serverless)) } diff --git a/src/workerd.rs b/src/workerd.rs index cf4ca6c..6e64682 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -250,7 +250,7 @@ pub async fn get_workerd_response( body: actix_web::web::Bytes, signer: &k256::ecdsa::SigningKey, host_header: &str, -) -> Result<(HttpResponse, [u8; 32]), anyhow::Error> { +) -> Result { let mut hasher = Keccak::v256(); hasher.update(b"|oyster-serverless-hasher|"); @@ -313,5 +313,5 @@ pub async fn get_workerd_response( actix_resp.insert_header(("X-Oyster-Timestamp", timestamp.to_string())); actix_resp.insert_header(("X-Oyster-Signature", hex::encode(signature.as_slice()))); - Ok((actix_resp.body(response_body), hash)) + Ok(actix_resp.body(response_body)) } From 350d1cf7b140040bc2af42e6dffa865b7b753791 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Fri, 9 Feb 2024 18:32:44 +0530 Subject: [PATCH 11/21] resolve comments and refactor code --- src/billing_handler.rs | 58 +++++++++++++++++++++++++----------------- src/handler.rs | 50 +++++++++++++++--------------------- src/lib.rs | 7 +++++ src/main.rs | 14 +++++++++- src/model.rs | 8 ++++-- src/tests.rs | 23 ++++++++++++++--- src/workerd.rs | 24 ++++++----------- 7 files changed, 109 insertions(+), 75 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index b3b5014..ca8268d 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -1,38 +1,50 @@ use crate::model::AppState; -use actix_web::{web::Data, HttpResponse}; +use actix_web::HttpResponse; +use actix_web::web::Data; use anyhow::Context; +use ethers::types::U256; use k256::elliptic_curve::generic_array::sequence::Lengthen; use serde_json::json; use tiny_keccak::{Hasher, Keccak}; pub async fn billing_data(appstate: Data) -> HttpResponse { - let mut costs_gaurd = appstate.execution_costs.lock().unwrap(); + let mut execution_costs_gaurd = appstate.execution_costs.lock().unwrap(); - if costs_gaurd.is_empty() { - return HttpResponse::BadRequest().body("Bill is empty"); + if execution_costs_gaurd.is_empty() { + return HttpResponse::BadRequest().body("No billing data available"); } - let tx_hashes: Vec = costs_gaurd.keys().cloned().collect(); - let amounts: Vec = costs_gaurd.values().cloned().collect(); + let txhashes: Vec<[u8; 32]> = execution_costs_gaurd + .keys() + .cloned() + .map(|txhash| { + let mut bytes32_txhash = [0u8; 32]; + hex::decode_to_slice(&txhash[2..], &mut bytes32_txhash).unwrap(); + bytes32_txhash + }).collect(); + let amounts: Vec = execution_costs_gaurd + .values() + .cloned() + .map(|amount| U256::from(amount)) + .collect(); let mut hasher = Keccak::v256(); hasher.update(b"|txhashes|"); - hasher.update( - tx_hashes - .iter() - .flat_map(|txhash| txhash.as_bytes().to_vec()) - .collect::>() - .as_slice(), - ); + hasher.update(txhashes + .iter() + .flat_map(|bytes32_txhash| bytes32_txhash.iter().cloned()) + .collect::>() + .as_slice()); hasher.update(b"|amounts|"); - hasher.update( - amounts - .iter() - .flat_map(|amount| amount.to_be_bytes().to_vec()) - .collect::>() - .as_slice(), - ); + hasher.update(amounts + .iter() + .flat_map(|amount| { + let mut bytes_amount = [0u8; 32]; + amount.to_big_endian(&mut bytes_amount); + bytes_amount + }).collect::>() + .as_slice()); let mut hash = [0u8; 32]; hasher.finalize(&mut hash); @@ -40,17 +52,17 @@ pub async fn billing_data(appstate: Data) -> HttpResponse { let sign = appstate .signer .sign_prehash_recoverable(&hash) - .context("Failed to sign requests data"); + .context("Failed to sign billing data"); if sign.is_err() { return HttpResponse::InternalServerError().body(format!("{:?}", sign.unwrap_err())); } let (rs, v) = sign.unwrap(); let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); - costs_gaurd.clear(); + execution_costs_gaurd.clear(); HttpResponse::Ok().json(json!({ - "txhashes": tx_hashes, + "txhashes": txhashes, "amounts": amounts, "signature": signature, })) diff --git a/src/handler.rs b/src/handler.rs index 0dec693..9a4f568 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -2,7 +2,8 @@ use std::io::{BufRead, BufReader}; use std::sync::atomic::Ordering; use std::time::{Duration, Instant}; -use crate::{cgroups, model::AppState, workerd}; +use crate::{cgroups, workerd}; +use crate::model::AppState; use actix_web::http::{header, StatusCode}; use actix_web::{web, HttpRequest, HttpResponse, Responder}; @@ -155,22 +156,13 @@ pub async fn serverless( use workerd::ServerlessError::*; return match err { - CalldataRetrieve(_) - | TxNotFound - | InvalidTxToType - | InvalidTxToValue(_, _) - | InvalidTxCalldataType - | BadCalldata(_) => HttpResponse::BadRequest().body(format!( + ConfigFileCreate(_) => HttpResponse::InternalServerError().body(format!( "{:?}", - anyhow!(err).context("failed to create code file") - )), - CodeFileCreate(_) => HttpResponse::InternalServerError().body(format!( - "{:?}", - anyhow!(err).context("failed to create code file") + anyhow!(err).context("failed to create config file") )), _ => HttpResponse::InternalServerError().body(format!( "{:?}", - anyhow!(err).context("unexpected error while trying to create code file") + anyhow!(err).context("unexpected error while trying to create config file") )), }; } @@ -252,28 +244,14 @@ pub async fn serverless( .context("CRITICAL: failed to clean up code file") .unwrap_or_else(|err| println!("{err:?}")); - if let Err(err) = response { - return HttpResponse::RequestTimeout() - .body(format!("{:?}", anyhow!(err).context("worker timed out"))); - } - let response = response.unwrap(); - - if let Err(err) = response { - return HttpResponse::InternalServerError().body(format!( - "{:?}", - anyhow!(err).context("failed to get a response") - )); - } - let response = response.unwrap(); - let execution_timer_end = Instant::now(); let execution_time = execution_timer_end .duration_since(execution_timer_start) .as_millis(); - + // TODO: FIX THE VALUE OF FIXED COST AND CONVERSION RATE let execution_cost = 1 + 2 * execution_time; - + appstate .execution_costs .lock() @@ -282,5 +260,19 @@ pub async fn serverless( .and_modify(|cost| *cost += execution_cost) .or_insert(execution_cost); + if let Err(err) = response { + return HttpResponse::RequestTimeout() + .body(format!("{:?}", anyhow!(err).context("worker timed out"))); + } + let response = response.unwrap(); + + if let Err(err) = response { + return HttpResponse::InternalServerError().body(format!( + "{:?}", + anyhow!(err).context("failed to get a response") + )); + } + let response = response.unwrap(); + return response; } diff --git a/src/lib.rs b/src/lib.rs index 560f700..b54cb24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,3 +4,10 @@ pub mod handler; pub mod model; mod tests; pub mod workerd; + +use ethers::contract::abigen; +abigen!( + BillingContract, + "src/contracts/billing_contract_abi.json", + derives(serde::Serialize, serde::Deserialize) +); diff --git a/src/main.rs b/src/main.rs index cef634f..8af1563 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,16 @@ +use std::sync::Arc; use std::collections::HashMap; +use std::time::Duration; +use serverless::BillingContract; use serverless::cgroups::Cgroups; use serverless::model::AppState; use actix_web::{web, App, HttpServer}; use anyhow::{anyhow, Context}; use clap::Parser; +use ethers::providers::{Http, Provider}; +use ethers::types::Address; use tokio::fs; /// Simple program to greet a person @@ -75,14 +80,21 @@ async fn main() -> anyhow::Result<()> { ) .context("invalid signer key")?; + let rpc_provider = Provider::::try_from(&cli.rpc) + .context("Failed to connect to the rpc")? + .interval(Duration::from_millis(1000)); + let billing_contract = BillingContract::new( + cli.billing_contract.parse::
().context("Failed to parse billing contract address")?, + Arc::new(rpc_provider)); + let app_data = web::Data::new(AppState { cgroups: cgroups.into(), running: std::sync::atomic::AtomicBool::new(true), runtime_path: cli.runtime_path, rpc: cli.rpc, contract: cli.contract, - billing_contract: cli.billing_contract, signer: signer, + billing_contract: billing_contract, execution_costs: HashMap::new().into(), }); let app_data_clone = app_data.clone(); diff --git a/src/model.rs b/src/model.rs index 879a2ec..1eebe44 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,8 +1,12 @@ use std::collections::HashMap; -use std::sync::{atomic::AtomicBool, Mutex}; +use std::sync::atomic::AtomicBool; +use std::sync::Mutex; +use crate::BillingContract; use crate::cgroups::Cgroups; +use ethers::providers::{Http, Provider}; + pub struct AppState { pub cgroups: Mutex, // IMPORTANT: we use Relaxed ordering here since we do not need to synchronize any memory @@ -12,7 +16,7 @@ pub struct AppState { pub runtime_path: String, pub rpc: String, pub contract: String, - pub billing_contract: String, pub signer: k256::ecdsa::SigningKey, + pub billing_contract: BillingContract>, pub execution_costs: Mutex>, } diff --git a/src/tests.rs b/src/tests.rs index 9d8f83b..b763ef6 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -5,6 +5,7 @@ #[cfg(test)] pub mod serverlesstest { + use crate::BillingContract; use crate::cgroups::Cgroups; use crate::handler; use crate::model::AppState; @@ -14,8 +15,13 @@ pub mod serverlesstest { error::Error, http, test, web, App, }; + use ethers::providers::{Http, Provider}; + use ethers::types::Address; use serde_json::json; - use std::{collections::HashMap, sync::atomic::AtomicBool}; + use std::collections::HashMap; + use std::sync::Arc; + use std::sync::atomic::AtomicBool; + use std::time::Duration; fn new_app() -> App< impl ServiceFactory< @@ -26,15 +32,24 @@ pub mod serverlesstest { Error = Error, >, > { + + let rpc = String::from("https://sepolia-rollup.arbitrum.io/rpc"); + let billing_contract_add = String::new(); // TODO: ADD BILLING CONTRACT FOR TESTS + + let rpc_provider = Provider::::try_from(&rpc).unwrap().interval(Duration::from_millis(1000)); + let billing_contract = BillingContract::new( + billing_contract_add.parse::
().unwrap(), + Arc::new(rpc_provider)); + App::new() .app_data(web::Data::new(AppState { cgroups: Cgroups::new().unwrap().into(), running: AtomicBool::new(true), runtime_path: "./runtime/".to_owned(), - rpc: "https://sepolia-rollup.arbitrum.io/rpc".to_owned(), - contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), - billing_contract: String::new(), // TODO: ADD BILLING CONTRACT FOR TESTS + rpc: rpc, + contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), + billing_contract: billing_contract, execution_costs: HashMap::new().into(), })) .default_service(web::to(handler::serverless)) diff --git a/src/workerd.rs b/src/workerd.rs index 6e64682..f80de2b 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -1,7 +1,7 @@ use std::process::Child; use std::time::{Duration, Instant}; -use std::{convert::TryFrom, sync::Arc}; +use crate::BillingContract; use crate::cgroups::{Cgroups, CgroupsError}; use actix_web::{HttpRequest, HttpResponse}; @@ -17,12 +17,6 @@ use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; use tokio::time::sleep; -abigen!( - BillingContract, - "src/contracts/billing_contract_abi.json", - derives(serde::Serialize, serde::Deserialize) -); - #[derive(Error, Debug)] pub enum ServerlessError { #[error("failed to retrieve calldata")] @@ -59,17 +53,15 @@ pub enum ServerlessError { async fn get_current_deposit( tx_hash: &str, - rpc: &str, - billing_contract_add: &str, + billing_contract: &BillingContract>, ) -> Result { - let provider = Provider::::try_from(rpc)?.interval(Duration::from_millis(1000)); - let contract = - BillingContract::new(billing_contract_add.parse::
()?, Arc::new(provider)); - let mut bytes32_tx_hash = [0u8; 32]; hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?; - let deposit = contract.balance_of(bytes32_tx_hash).call().await?; + let deposit = billing_contract + .balance_of(bytes32_tx_hash) + .call() + .await?; Ok(deposit) } @@ -99,7 +91,7 @@ pub async fn create_code_file( workerd_runtime_path: &str, rpc: &str, contract: &str, - billing_contract: &str, + billing_contract: &BillingContract>, ) -> Result<(), ServerlessError> { // get tx data let mut tx_data = match get_transaction_data(tx_hash, rpc).await?["result"].take() { @@ -128,7 +120,7 @@ pub async fn create_code_file( }?; // get tx deposit - let tx_deposit = get_current_deposit(tx_hash, rpc, billing_contract) + let tx_deposit = get_current_deposit(tx_hash, billing_contract) .await .map_err(|_| ServerlessError::TxDepositNotFound)?; // TODO: FIX THE FIXED MINIMUM VALUE From bd80202ca032a1fd3e783f821d6e51a18ca0f2e0 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Mon, 12 Feb 2024 12:17:52 +0530 Subject: [PATCH 12/21] updating billing info --- src/billing_handler.rs | 50 ++++++++++++++---------------------------- src/handler.rs | 6 ++--- src/main.rs | 11 ++++++---- src/model.rs | 2 +- src/tests.rs | 20 +++++++++-------- src/workerd.rs | 7 ++---- 6 files changed, 41 insertions(+), 55 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index ca8268d..b385343 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -1,9 +1,8 @@ use crate::model::AppState; -use actix_web::HttpResponse; use actix_web::web::Data; +use actix_web::HttpResponse; use anyhow::Context; -use ethers::types::U256; use k256::elliptic_curve::generic_array::sequence::Lengthen; use serde_json::json; use tiny_keccak::{Hasher, Keccak}; @@ -15,36 +14,21 @@ pub async fn billing_data(appstate: Data) -> HttpResponse { return HttpResponse::BadRequest().body("No billing data available"); } - let txhashes: Vec<[u8; 32]> = execution_costs_gaurd - .keys() - .cloned() - .map(|txhash| { - let mut bytes32_txhash = [0u8; 32]; - hex::decode_to_slice(&txhash[2..], &mut bytes32_txhash).unwrap(); - bytes32_txhash - }).collect(); - let amounts: Vec = execution_costs_gaurd - .values() - .cloned() - .map(|amount| U256::from(amount)) - .collect(); + let mut billing_data: Vec = Vec::new(); + + for (tx_hash, cost) in execution_costs_gaurd.iter() { + let mut bytes32_tx_hash = [0u8; 32]; + if let Err(err) = hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash) { + return HttpResponse::InternalServerError() + .body(format!("Error decoding transaction hash: {:?}", err)); + } + + billing_data.append(&mut bytes32_tx_hash.to_vec()); + billing_data.append(&mut cost.to_be_bytes().to_vec()); + } let mut hasher = Keccak::v256(); - hasher.update(b"|txhashes|"); - hasher.update(txhashes - .iter() - .flat_map(|bytes32_txhash| bytes32_txhash.iter().cloned()) - .collect::>() - .as_slice()); - hasher.update(b"|amounts|"); - hasher.update(amounts - .iter() - .flat_map(|amount| { - let mut bytes_amount = [0u8; 32]; - amount.to_big_endian(&mut bytes_amount); - bytes_amount - }).collect::>() - .as_slice()); + hasher.update(&billing_data); let mut hash = [0u8; 32]; hasher.finalize(&mut hash); @@ -54,16 +38,16 @@ pub async fn billing_data(appstate: Data) -> HttpResponse { .sign_prehash_recoverable(&hash) .context("Failed to sign billing data"); if sign.is_err() { - return HttpResponse::InternalServerError().body(format!("{:?}", sign.unwrap_err())); + return HttpResponse::InternalServerError().body(format!("{}", sign.unwrap_err())); } let (rs, v) = sign.unwrap(); let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); + let billing_data = hex::encode(billing_data.as_slice()); execution_costs_gaurd.clear(); HttpResponse::Ok().json(json!({ - "txhashes": txhashes, - "amounts": amounts, + "billing_data": billing_data, "signature": signature, })) } diff --git a/src/handler.rs b/src/handler.rs index 9a4f568..eb237e0 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -2,8 +2,8 @@ use std::io::{BufRead, BufReader}; use std::sync::atomic::Ordering; use std::time::{Duration, Instant}; -use crate::{cgroups, workerd}; use crate::model::AppState; +use crate::{cgroups, workerd}; use actix_web::http::{header, StatusCode}; use actix_web::{web, HttpRequest, HttpResponse, Responder}; @@ -248,10 +248,10 @@ pub async fn serverless( let execution_time = execution_timer_end .duration_since(execution_timer_start) .as_millis(); - + // TODO: FIX THE VALUE OF FIXED COST AND CONVERSION RATE let execution_cost = 1 + 2 * execution_time; - + appstate .execution_costs .lock() diff --git a/src/main.rs b/src/main.rs index 8af1563..e5cee9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ -use std::sync::Arc; use std::collections::HashMap; +use std::sync::Arc; use std::time::Duration; -use serverless::BillingContract; use serverless::cgroups::Cgroups; use serverless::model::AppState; +use serverless::BillingContract; use actix_web::{web, App, HttpServer}; use anyhow::{anyhow, Context}; @@ -84,8 +84,11 @@ async fn main() -> anyhow::Result<()> { .context("Failed to connect to the rpc")? .interval(Duration::from_millis(1000)); let billing_contract = BillingContract::new( - cli.billing_contract.parse::
().context("Failed to parse billing contract address")?, - Arc::new(rpc_provider)); + cli.billing_contract + .parse::
() + .context("Failed to parse billing contract address")?, + Arc::new(rpc_provider), + ); let app_data = web::Data::new(AppState { cgroups: cgroups.into(), diff --git a/src/model.rs b/src/model.rs index 1eebe44..14d4b7f 100644 --- a/src/model.rs +++ b/src/model.rs @@ -2,8 +2,8 @@ use std::collections::HashMap; use std::sync::atomic::AtomicBool; use std::sync::Mutex; -use crate::BillingContract; use crate::cgroups::Cgroups; +use crate::BillingContract; use ethers::providers::{Http, Provider}; diff --git a/src/tests.rs b/src/tests.rs index b763ef6..fe1fbea 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -5,10 +5,10 @@ #[cfg(test)] pub mod serverlesstest { - use crate::BillingContract; use crate::cgroups::Cgroups; use crate::handler; use crate::model::AppState; + use crate::BillingContract; use actix_web::{ body::MessageBody, dev::{ServiceFactory, ServiceRequest, ServiceResponse}, @@ -19,8 +19,8 @@ pub mod serverlesstest { use ethers::types::Address; use serde_json::json; use std::collections::HashMap; - use std::sync::Arc; use std::sync::atomic::AtomicBool; + use std::sync::Arc; use std::time::Duration; fn new_app() -> App< @@ -32,22 +32,24 @@ pub mod serverlesstest { Error = Error, >, > { - let rpc = String::from("https://sepolia-rollup.arbitrum.io/rpc"); - let billing_contract_add = String::new(); // TODO: ADD BILLING CONTRACT FOR TESTS + let billing_contract_add = String::new(); // TODO: ADD BILLING CONTRACT FOR TESTS - let rpc_provider = Provider::::try_from(&rpc).unwrap().interval(Duration::from_millis(1000)); + let rpc_provider = Provider::::try_from(&rpc) + .unwrap() + .interval(Duration::from_millis(1000)); let billing_contract = BillingContract::new( - billing_contract_add.parse::
().unwrap(), - Arc::new(rpc_provider)); - + billing_contract_add.parse::
().unwrap(), + Arc::new(rpc_provider), + ); + App::new() .app_data(web::Data::new(AppState { cgroups: Cgroups::new().unwrap().into(), running: AtomicBool::new(true), runtime_path: "./runtime/".to_owned(), rpc: rpc, - contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), + contract: "0x44fe06d2940b8782a0a9a9ffd09c65852c0156b1".to_owned(), signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), billing_contract: billing_contract, execution_costs: HashMap::new().into(), diff --git a/src/workerd.rs b/src/workerd.rs index f80de2b..370bd43 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -1,8 +1,8 @@ use std::process::Child; use std::time::{Duration, Instant}; -use crate::BillingContract; use crate::cgroups::{Cgroups, CgroupsError}; +use crate::BillingContract; use actix_web::{HttpRequest, HttpResponse}; use anyhow::Error; @@ -58,10 +58,7 @@ async fn get_current_deposit( let mut bytes32_tx_hash = [0u8; 32]; hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?; - let deposit = billing_contract - .balance_of(bytes32_tx_hash) - .call() - .await?; + let deposit = billing_contract.balance_of(bytes32_tx_hash).call().await?; Ok(deposit) } From 409d90f8e79376fb358ab8a9ba3fc45a8ecea9ac Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Tue, 13 Feb 2024 12:04:11 +0530 Subject: [PATCH 13/21] create endpoints to retrieve and sign bill --- src/billing_handler.rs | 68 +++++++++++++++++-------- src/contracts/billing_contract_abi.json | 23 --------- src/lib.rs | 4 ++ src/main.rs | 6 ++- src/model.rs | 6 +-- src/workerd.rs | 6 +-- 6 files changed, 61 insertions(+), 52 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index b385343..1f2a7e9 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -1,34 +1,63 @@ use crate::model::AppState; -use actix_web::web::Data; -use actix_web::HttpResponse; +use actix_web::web::{Data, Json}; +use actix_web::{get, post, HttpResponse, Responder}; use anyhow::Context; use k256::elliptic_curve::generic_array::sequence::Lengthen; use serde_json::json; use tiny_keccak::{Hasher, Keccak}; -pub async fn billing_data(appstate: Data) -> HttpResponse { - let mut execution_costs_gaurd = appstate.execution_costs.lock().unwrap(); +#[derive(Debug, serde::Deserialize)] +pub struct SigningData { + nonce: String, + txhashes: Vec, +} - if execution_costs_gaurd.is_empty() { - return HttpResponse::BadRequest().body("No billing data available"); +#[get("/bill")] +pub async fn get_bill(appstate: Data) -> impl Responder { + let bill = appstate.execution_costs.lock().unwrap().clone(); + if bill.is_empty() { + return HttpResponse::NoContent().body("No bill data available"); } - let mut billing_data: Vec = Vec::new(); + HttpResponse::Ok().json(json!({ + "bill": bill, + })) +} + +#[post("/sign")] +pub async fn sign_data(appstate: Data, data: Json) -> impl Responder { + let signing_data = data.into_inner(); + if signing_data.nonce.is_empty() { + return HttpResponse::BadRequest().body("Nonce must not be empty"); + } - for (tx_hash, cost) in execution_costs_gaurd.iter() { - let mut bytes32_tx_hash = [0u8; 32]; - if let Err(err) = hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash) { - return HttpResponse::InternalServerError() - .body(format!("Error decoding transaction hash: {:?}", err)); + if signing_data.txhashes.is_empty() { + return HttpResponse::BadRequest().body("List of tx hashes must not be empty"); + } + + let mut signed_data: Vec = Vec::new(); + for txhash in signing_data.txhashes { + if let Some(cost) = appstate.execution_costs.lock().unwrap().remove(&txhash) { + let mut bytes32_txhash = [0u8; 32]; + if let Err(err) = hex::decode_to_slice(&txhash[2..], &mut bytes32_txhash) { + return HttpResponse::InternalServerError() + .body(format!("Error decoding transaction hash: {:?}", err)); + } + + signed_data.append(&mut bytes32_txhash.to_vec()); + signed_data.append(&mut cost.to_be_bytes().to_vec()); + } else { + return HttpResponse::BadRequest().body(format!( + "{} tx hash doesn't exist in the current bill", + txhash + )); } - - billing_data.append(&mut bytes32_tx_hash.to_vec()); - billing_data.append(&mut cost.to_be_bytes().to_vec()); } + signed_data.append(&mut signing_data.nonce.as_bytes().to_vec()); let mut hasher = Keccak::v256(); - hasher.update(&billing_data); + hasher.update(&signed_data); let mut hash = [0u8; 32]; hasher.finalize(&mut hash); @@ -41,13 +70,12 @@ pub async fn billing_data(appstate: Data) -> HttpResponse { return HttpResponse::InternalServerError().body(format!("{}", sign.unwrap_err())); } let (rs, v) = sign.unwrap(); - let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); - let billing_data = hex::encode(billing_data.as_slice()); - execution_costs_gaurd.clear(); + let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); + let signed_data = hex::encode(signed_data.as_slice()); HttpResponse::Ok().json(json!({ - "billing_data": billing_data, + "signed_data": signed_data, "signature": signature, })) } diff --git a/src/contracts/billing_contract_abi.json b/src/contracts/billing_contract_abi.json index b1692ba..b467f1d 100644 --- a/src/contracts/billing_contract_abi.json +++ b/src/contracts/billing_contract_abi.json @@ -17,28 +17,5 @@ ], "stateMutability": "view", "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32[]", - "name": "_txhashes", - "type": "bytes32[]" - }, - { - "internalType": "uint256[]", - "name": "_amounts", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "name": "settle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" } ] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b54cb24..d75b849 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,12 @@ mod tests; pub mod workerd; use ethers::contract::abigen; +use ethers::providers::{Http, Provider}; + abigen!( BillingContract, "src/contracts/billing_contract_abi.json", derives(serde::Serialize, serde::Deserialize) ); + +type BillContract = BillingContract>; diff --git a/src/main.rs b/src/main.rs index e5cee9a..1268f5c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use serverless::cgroups::Cgroups; use serverless::model::AppState; use serverless::BillingContract; -use actix_web::{web, App, HttpServer}; +use actix_web::{web, App, HttpResponse, HttpServer}; use anyhow::{anyhow, Context}; use clap::Parser; use ethers::providers::{Http, Provider}; @@ -116,7 +116,9 @@ async fn main() -> anyhow::Result<()> { let billing_server = HttpServer::new(move || { App::new() .app_data(app_data_clone.clone()) - .default_service(web::to(serverless::billing_handler::billing_data)) + .service(serverless::billing_handler::get_bill) + .service(serverless::billing_handler::sign_data) + .default_service(web::to(HttpResponse::NotFound)) }) .bind(("0.0.0.0", billing_port)) .context(format!("could not bind to port {billing_port}"))? diff --git a/src/model.rs b/src/model.rs index 14d4b7f..add2447 100644 --- a/src/model.rs +++ b/src/model.rs @@ -3,9 +3,7 @@ use std::sync::atomic::AtomicBool; use std::sync::Mutex; use crate::cgroups::Cgroups; -use crate::BillingContract; - -use ethers::providers::{Http, Provider}; +use crate::BillContract; pub struct AppState { pub cgroups: Mutex, @@ -17,6 +15,6 @@ pub struct AppState { pub rpc: String, pub contract: String, pub signer: k256::ecdsa::SigningKey, - pub billing_contract: BillingContract>, + pub billing_contract: BillContract, pub execution_costs: Mutex>, } diff --git a/src/workerd.rs b/src/workerd.rs index 370bd43..5540814 100644 --- a/src/workerd.rs +++ b/src/workerd.rs @@ -2,7 +2,7 @@ use std::process::Child; use std::time::{Duration, Instant}; use crate::cgroups::{Cgroups, CgroupsError}; -use crate::BillingContract; +use crate::BillContract; use actix_web::{HttpRequest, HttpResponse}; use anyhow::Error; @@ -53,7 +53,7 @@ pub enum ServerlessError { async fn get_current_deposit( tx_hash: &str, - billing_contract: &BillingContract>, + billing_contract: &BillContract, ) -> Result { let mut bytes32_tx_hash = [0u8; 32]; hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?; @@ -88,7 +88,7 @@ pub async fn create_code_file( workerd_runtime_path: &str, rpc: &str, contract: &str, - billing_contract: &BillingContract>, + billing_contract: &BillContract, ) -> Result<(), ServerlessError> { // get tx data let mut tx_data = match get_transaction_data(tx_hash, rpc).await?["result"].take() { From 1a471406ad195d38f17d6a14ef1fb48afc51eaf7 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Tue, 13 Feb 2024 13:28:16 +0530 Subject: [PATCH 14/21] resolve comments --- src/billing_handler.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index 1f2a7e9..41dfc62 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -13,19 +13,14 @@ pub struct SigningData { txhashes: Vec, } -#[get("/bill")] +#[get("/billing/inspect")] pub async fn get_bill(appstate: Data) -> impl Responder { - let bill = appstate.execution_costs.lock().unwrap().clone(); - if bill.is_empty() { - return HttpResponse::NoContent().body("No bill data available"); - } - HttpResponse::Ok().json(json!({ - "bill": bill, + "bill": appstate.execution_costs.lock().unwrap().clone(), })) } -#[post("/sign")] +#[post("/billing/export")] pub async fn sign_data(appstate: Data, data: Json) -> impl Responder { let signing_data = data.into_inner(); if signing_data.nonce.is_empty() { @@ -36,13 +31,21 @@ pub async fn sign_data(appstate: Data, data: Json) -> imp return HttpResponse::BadRequest().body("List of tx hashes must not be empty"); } - let mut signed_data: Vec = Vec::new(); + let mut bytes32_nonce = [0u8; 32]; + if let Err(err) = hex::decode_to_slice(&signing_data.nonce, &mut bytes32_nonce) { + return HttpResponse::BadRequest() + .body(format!("Error decoding nonce into 32 bytes: {}", err)); + } + + let mut signed_data: Vec = bytes32_nonce.to_vec(); for txhash in signing_data.txhashes { if let Some(cost) = appstate.execution_costs.lock().unwrap().remove(&txhash) { let mut bytes32_txhash = [0u8; 32]; if let Err(err) = hex::decode_to_slice(&txhash[2..], &mut bytes32_txhash) { - return HttpResponse::InternalServerError() - .body(format!("Error decoding transaction hash: {:?}", err)); + return HttpResponse::InternalServerError().body(format!( + "Error decoding transaction hash into 32 bytes: {}", + err + )); } signed_data.append(&mut bytes32_txhash.to_vec()); @@ -54,7 +57,6 @@ pub async fn sign_data(appstate: Data, data: Json) -> imp )); } } - signed_data.append(&mut signing_data.nonce.as_bytes().to_vec()); let mut hasher = Keccak::v256(); hasher.update(&signed_data); From d59dc0c384926f144d836878cdaa9f6a95a9824e Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Fri, 16 Feb 2024 12:48:08 +0530 Subject: [PATCH 15/21] retrieve latest bill info --- src/billing_handler.rs | 124 +++++++++++++++++++++++++++++------------ src/main.rs | 6 +- src/model.rs | 1 + src/tests.rs | 1 + 4 files changed, 95 insertions(+), 37 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index 41dfc62..a97fa1e 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -2,7 +2,7 @@ use crate::model::AppState; use actix_web::web::{Data, Json}; use actix_web::{get, post, HttpResponse, Responder}; -use anyhow::Context; +use k256::ecdsa::SigningKey; use k256::elliptic_curve::generic_array::sequence::Lengthen; use serde_json::json; use tiny_keccak::{Hasher, Keccak}; @@ -10,24 +10,65 @@ use tiny_keccak::{Hasher, Keccak}; #[derive(Debug, serde::Deserialize)] pub struct SigningData { nonce: String, - txhashes: Vec, + tx_hashes: Vec, } #[get("/billing/inspect")] -pub async fn get_bill(appstate: Data) -> impl Responder { +pub async fn inspect_bill(appstate: Data) -> impl Responder { HttpResponse::Ok().json(json!({ "bill": appstate.execution_costs.lock().unwrap().clone(), })) } +#[get("/billing/latest")] +pub async fn get_last_bill_claim(appstate: Data) -> impl Responder { + let mut last_bill_claim_guard = appstate.last_bill_claim.lock().unwrap(); + if last_bill_claim_guard.0.is_none() { + return HttpResponse::Ok().body("No bill claimed yet"); + } + + if last_bill_claim_guard.1.is_some() { + return HttpResponse::Ok().json(json!({ + "bill_claim_data": last_bill_claim_guard.0.clone().unwrap(), + "signature": last_bill_claim_guard.1.clone().unwrap(), + })); + } + + let bill_claim_data = hex::decode(last_bill_claim_guard.0.clone().unwrap()); + if bill_claim_data.is_err() { + return HttpResponse::InternalServerError().body(format!( + "Failed to decode claimed bill data: {}", + bill_claim_data.unwrap_err() + )); + } + + let bill_claim_data = bill_claim_data.unwrap(); + let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer).await; + if signature.is_err() { + return HttpResponse::InternalServerError().body(format!( + "Failed to sign billing data: {}", + signature.unwrap_err() + )); + } + + let bill_claim_data = hex::encode(bill_claim_data.as_slice()); + let signature = signature.unwrap(); + last_bill_claim_guard.1 = Some(signature.clone()); + + HttpResponse::Ok().json(json!({ + "bill_claim_data": bill_claim_data, + "signature": signature, + })) +} + #[post("/billing/export")] -pub async fn sign_data(appstate: Data, data: Json) -> impl Responder { +pub async fn export_bill(appstate: Data, data: Json) -> impl Responder { let signing_data = data.into_inner(); if signing_data.nonce.is_empty() { return HttpResponse::BadRequest().body("Nonce must not be empty"); } - if signing_data.txhashes.is_empty() { + if signing_data.tx_hashes.is_empty() { return HttpResponse::BadRequest().body("List of tx hashes must not be empty"); } @@ -37,47 +78,60 @@ pub async fn sign_data(appstate: Data, data: Json) -> imp .body(format!("Error decoding nonce into 32 bytes: {}", err)); } - let mut signed_data: Vec = bytes32_nonce.to_vec(); - for txhash in signing_data.txhashes { - if let Some(cost) = appstate.execution_costs.lock().unwrap().remove(&txhash) { - let mut bytes32_txhash = [0u8; 32]; - if let Err(err) = hex::decode_to_slice(&txhash[2..], &mut bytes32_txhash) { - return HttpResponse::InternalServerError().body(format!( - "Error decoding transaction hash into 32 bytes: {}", - err - )); + let mut bill_claim_data = bytes32_nonce.to_vec(); + for tx_hash in signing_data.tx_hashes { + if let Some(cost) = appstate.execution_costs.lock().unwrap().remove(&tx_hash) { + let mut bytes32_tx_hash = [0u8; 32]; + if let Err(_) = hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash) { + continue; } - signed_data.append(&mut bytes32_txhash.to_vec()); - signed_data.append(&mut cost.to_be_bytes().to_vec()); - } else { - return HttpResponse::BadRequest().body(format!( - "{} tx hash doesn't exist in the current bill", - txhash - )); + bill_claim_data.append(&mut bytes32_tx_hash.to_vec()); + bill_claim_data.append(&mut cost.to_be_bytes().to_vec()); } } - let mut hasher = Keccak::v256(); - hasher.update(&signed_data); + if bill_claim_data.len() == 32 { + return HttpResponse::BadRequest().body("No tx present in the bill"); + } - let mut hash = [0u8; 32]; - hasher.finalize(&mut hash); + let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer).await; + if signature.is_err() { + appstate + .last_bill_claim + .lock() + .unwrap() + .0 + .clone_from(&Some(hex::encode(bill_claim_data.as_slice()))); - let sign = appstate - .signer - .sign_prehash_recoverable(&hash) - .context("Failed to sign billing data"); - if sign.is_err() { - return HttpResponse::InternalServerError().body(format!("{}", sign.unwrap_err())); + return HttpResponse::InternalServerError().body(format!( + "Failed to sign billing data: {}", + signature.unwrap_err() + )); } - let (rs, v) = sign.unwrap(); - let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); - let signed_data = hex::encode(signed_data.as_slice()); + let signature = signature.unwrap(); + let bill_claim_data = hex::encode(bill_claim_data.as_slice()); + + let mut last_bill_claim_guard = appstate.last_bill_claim.lock().unwrap(); + last_bill_claim_guard.0 = Some(bill_claim_data.clone()); + last_bill_claim_guard.1 = Some(signature.clone()); HttpResponse::Ok().json(json!({ - "signed_data": signed_data, + "bill_claim_data": bill_claim_data, "signature": signature, })) } + +async fn sign_data(data: &[u8], signer: &SigningKey) -> Result { + let mut hasher = Keccak::v256(); + hasher.update(data); + + let mut hash = [0u8; 32]; + hasher.finalize(&mut hash); + + let (rs, v) = signer.sign_prehash_recoverable(&hash)?; + let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice()); + + return Ok(signature); +} diff --git a/src/main.rs b/src/main.rs index 1268f5c..b244424 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,6 +99,7 @@ async fn main() -> anyhow::Result<()> { signer: signer, billing_contract: billing_contract, execution_costs: HashMap::new().into(), + last_bill_claim: (None, None).into(), }); let app_data_clone = app_data.clone(); @@ -116,8 +117,9 @@ async fn main() -> anyhow::Result<()> { let billing_server = HttpServer::new(move || { App::new() .app_data(app_data_clone.clone()) - .service(serverless::billing_handler::get_bill) - .service(serverless::billing_handler::sign_data) + .service(serverless::billing_handler::inspect_bill) + .service(serverless::billing_handler::get_last_bill_claim) + .service(serverless::billing_handler::export_bill) .default_service(web::to(HttpResponse::NotFound)) }) .bind(("0.0.0.0", billing_port)) diff --git a/src/model.rs b/src/model.rs index add2447..5520149 100644 --- a/src/model.rs +++ b/src/model.rs @@ -17,4 +17,5 @@ pub struct AppState { pub signer: k256::ecdsa::SigningKey, pub billing_contract: BillContract, pub execution_costs: Mutex>, + pub last_bill_claim: Mutex<(Option, Option)>, } diff --git a/src/tests.rs b/src/tests.rs index fe1fbea..09a4639 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -53,6 +53,7 @@ pub mod serverlesstest { signer: k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng), billing_contract: billing_contract, execution_costs: HashMap::new().into(), + last_bill_claim: (None, None).into(), })) .default_service(web::to(handler::serverless)) } From d317e86457bb95ab5fcd5eb7a45ceefb30682d62 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Mon, 19 Feb 2024 15:12:20 +0530 Subject: [PATCH 16/21] resolve comments --- src/billing_handler.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index a97fa1e..84a06dd 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -24,7 +24,7 @@ pub async fn inspect_bill(appstate: Data) -> impl Responder { pub async fn get_last_bill_claim(appstate: Data) -> impl Responder { let mut last_bill_claim_guard = appstate.last_bill_claim.lock().unwrap(); if last_bill_claim_guard.0.is_none() { - return HttpResponse::Ok().body("No bill claimed yet"); + return HttpResponse::BadRequest().body("No bill claimed yet!"); } if last_bill_claim_guard.1.is_some() { @@ -65,17 +65,17 @@ pub async fn get_last_bill_claim(appstate: Data) -> impl Responder { pub async fn export_bill(appstate: Data, data: Json) -> impl Responder { let signing_data = data.into_inner(); if signing_data.nonce.is_empty() { - return HttpResponse::BadRequest().body("Nonce must not be empty"); + return HttpResponse::BadRequest().body("Nonce must not be empty!"); } if signing_data.tx_hashes.is_empty() { - return HttpResponse::BadRequest().body("List of tx hashes must not be empty"); + return HttpResponse::BadRequest().body("List of transaction hashes must not be empty!"); } let mut bytes32_nonce = [0u8; 32]; if let Err(err) = hex::decode_to_slice(&signing_data.nonce, &mut bytes32_nonce) { return HttpResponse::BadRequest() - .body(format!("Error decoding nonce into 32 bytes: {}", err)); + .body(format!("Failed to decode nonce into 32 bytes: {}", err)); } let mut bill_claim_data = bytes32_nonce.to_vec(); @@ -92,7 +92,8 @@ pub async fn export_bill(appstate: Data, data: Json) -> i } if bill_claim_data.len() == 32 { - return HttpResponse::BadRequest().body("No tx present in the bill"); + return HttpResponse::BadRequest() + .body("Given transaction hashes are not present in billing data"); } let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer).await; From f21eee6031e50618c614cda427a57a1b9baa5273 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Tue, 20 Feb 2024 13:12:23 +0530 Subject: [PATCH 17/21] resolve comments --- src/billing_handler.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index 84a06dd..bae8873 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -51,12 +51,11 @@ pub async fn get_last_bill_claim(appstate: Data) -> impl Responder { )); } - let bill_claim_data = hex::encode(bill_claim_data.as_slice()); let signature = signature.unwrap(); last_bill_claim_guard.1 = Some(signature.clone()); HttpResponse::Ok().json(json!({ - "bill_claim_data": bill_claim_data, + "bill_claim_data": last_bill_claim_guard.0.clone().unwrap(), "signature": signature, })) } From 66703c908ddb5020004d8332c065899152cef0a1 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Thu, 22 Feb 2024 12:26:34 +0530 Subject: [PATCH 18/21] refactor using let-else --- src/billing_handler.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index bae8873..d3acfb2 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -23,39 +23,37 @@ pub async fn inspect_bill(appstate: Data) -> impl Responder { #[get("/billing/latest")] pub async fn get_last_bill_claim(appstate: Data) -> impl Responder { let mut last_bill_claim_guard = appstate.last_bill_claim.lock().unwrap(); - if last_bill_claim_guard.0.is_none() { + let Some(bill_data_hex) = last_bill_claim_guard.0.clone() else { return HttpResponse::BadRequest().body("No bill claimed yet!"); - } + }; - if last_bill_claim_guard.1.is_some() { + if let Some(signature) = last_bill_claim_guard.1.clone() { return HttpResponse::Ok().json(json!({ - "bill_claim_data": last_bill_claim_guard.0.clone().unwrap(), - "signature": last_bill_claim_guard.1.clone().unwrap(), + "bill_claim_data": bill_data_hex, + "signature": signature, })); } - let bill_claim_data = hex::decode(last_bill_claim_guard.0.clone().unwrap()); - if bill_claim_data.is_err() { + let bill_claim_data = hex::decode(&bill_data_hex); + let Ok(bill_claim_data) = bill_claim_data else { return HttpResponse::InternalServerError().body(format!( "Failed to decode claimed bill data: {}", bill_claim_data.unwrap_err() )); - } + }; - let bill_claim_data = bill_claim_data.unwrap(); let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer).await; - if signature.is_err() { + let Ok(signature) = signature else { return HttpResponse::InternalServerError().body(format!( "Failed to sign billing data: {}", signature.unwrap_err() )); - } + }; - let signature = signature.unwrap(); last_bill_claim_guard.1 = Some(signature.clone()); HttpResponse::Ok().json(json!({ - "bill_claim_data": last_bill_claim_guard.0.clone().unwrap(), + "bill_claim_data": bill_data_hex, "signature": signature, })) } @@ -96,7 +94,7 @@ pub async fn export_bill(appstate: Data, data: Json) -> i } let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer).await; - if signature.is_err() { + let Ok(signature) = signature else { appstate .last_bill_claim .lock() @@ -108,9 +106,8 @@ pub async fn export_bill(appstate: Data, data: Json) -> i "Failed to sign billing data: {}", signature.unwrap_err() )); - } + }; - let signature = signature.unwrap(); let bill_claim_data = hex::encode(bill_claim_data.as_slice()); let mut last_bill_claim_guard = appstate.last_bill_claim.lock().unwrap(); From 42a3d4ce55a06a39f4559f2c98a5b6ad89dd616f Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Thu, 22 Feb 2024 17:43:46 +0530 Subject: [PATCH 19/21] refactor and optimize --- src/billing_handler.rs | 44 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index d3acfb2..10d5b33 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -1,3 +1,5 @@ +use std::ops::DerefMut; + use crate::model::AppState; use actix_web::web::{Data, Json}; @@ -15,26 +17,29 @@ pub struct SigningData { #[get("/billing/inspect")] pub async fn inspect_bill(appstate: Data) -> impl Responder { + // Can replace with 'appstate.execution_costs.lock().unwrap().clone()' if turns out cloning is faster then Json creation!! HttpResponse::Ok().json(json!({ - "bill": appstate.execution_costs.lock().unwrap().clone(), + "bill": *appstate.execution_costs.lock().unwrap(), })) } #[get("/billing/latest")] pub async fn get_last_bill_claim(appstate: Data) -> impl Responder { let mut last_bill_claim_guard = appstate.last_bill_claim.lock().unwrap(); - let Some(bill_data_hex) = last_bill_claim_guard.0.clone() else { + let last_bill_claim = last_bill_claim_guard.deref_mut(); + + let Some(bill_data_hex) = &last_bill_claim.0 else { return HttpResponse::BadRequest().body("No bill claimed yet!"); }; - if let Some(signature) = last_bill_claim_guard.1.clone() { + if let Some(signature) = &last_bill_claim.1 { return HttpResponse::Ok().json(json!({ "bill_claim_data": bill_data_hex, "signature": signature, })); } - let bill_claim_data = hex::decode(&bill_data_hex); + let bill_claim_data = hex::decode(bill_data_hex); let Ok(bill_claim_data) = bill_claim_data else { return HttpResponse::InternalServerError().body(format!( "Failed to decode claimed bill data: {}", @@ -50,12 +55,13 @@ pub async fn get_last_bill_claim(appstate: Data) -> impl Responder { )); }; - last_bill_claim_guard.1 = Some(signature.clone()); - - HttpResponse::Ok().json(json!({ + let response = HttpResponse::Ok().json(json!({ "bill_claim_data": bill_data_hex, "signature": signature, - })) + })); + + last_bill_claim.1 = Some(signature); + return response; } #[post("/billing/export")] @@ -94,13 +100,10 @@ pub async fn export_bill(appstate: Data, data: Json) -> i } let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer).await; + let bill_claim_data = hex::encode(bill_claim_data.as_slice()); + let Ok(signature) = signature else { - appstate - .last_bill_claim - .lock() - .unwrap() - .0 - .clone_from(&Some(hex::encode(bill_claim_data.as_slice()))); + appstate.last_bill_claim.lock().unwrap().0 = Some(bill_claim_data); return HttpResponse::InternalServerError().body(format!( "Failed to sign billing data: {}", @@ -108,16 +111,13 @@ pub async fn export_bill(appstate: Data, data: Json) -> i )); }; - let bill_claim_data = hex::encode(bill_claim_data.as_slice()); - - let mut last_bill_claim_guard = appstate.last_bill_claim.lock().unwrap(); - last_bill_claim_guard.0 = Some(bill_claim_data.clone()); - last_bill_claim_guard.1 = Some(signature.clone()); - - HttpResponse::Ok().json(json!({ + let response = HttpResponse::Ok().json(json!({ "bill_claim_data": bill_claim_data, "signature": signature, - })) + })); + + *appstate.last_bill_claim.lock().unwrap() = (Some(bill_claim_data), Some(signature)); + return response; } async fn sign_data(data: &[u8], signer: &SigningKey) -> Result { From b4f8a3a91641ed40a907a6c75057ff9d7498fcf4 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Thu, 22 Feb 2024 18:10:16 +0530 Subject: [PATCH 20/21] resolve comments --- src/billing_handler.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/billing_handler.rs b/src/billing_handler.rs index 10d5b33..b00298f 100644 --- a/src/billing_handler.rs +++ b/src/billing_handler.rs @@ -47,7 +47,7 @@ pub async fn get_last_bill_claim(appstate: Data) -> impl Responder { )); }; - let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer).await; + let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer); let Ok(signature) = signature else { return HttpResponse::InternalServerError().body(format!( "Failed to sign billing data: {}", @@ -99,11 +99,11 @@ pub async fn export_bill(appstate: Data, data: Json) -> i .body("Given transaction hashes are not present in billing data"); } - let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer).await; + let signature = sign_data(bill_claim_data.as_slice(), &appstate.signer); let bill_claim_data = hex::encode(bill_claim_data.as_slice()); let Ok(signature) = signature else { - appstate.last_bill_claim.lock().unwrap().0 = Some(bill_claim_data); + *appstate.last_bill_claim.lock().unwrap() = (Some(bill_claim_data), None); return HttpResponse::InternalServerError().body(format!( "Failed to sign billing data: {}", @@ -120,7 +120,7 @@ pub async fn export_bill(appstate: Data, data: Json) -> i return response; } -async fn sign_data(data: &[u8], signer: &SigningKey) -> Result { +fn sign_data(data: &[u8], signer: &SigningKey) -> Result { let mut hasher = Keccak::v256(); hasher.update(data); From 6fe2e1ba6ab6d404113b6d5013d487fa131df0c3 Mon Sep 17 00:00:00 2001 From: Ayush-Yadav Date: Wed, 20 Mar 2024 13:56:32 +0530 Subject: [PATCH 21/21] use try_connect to make rpc connection --- src/main.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index b244424..bbb9626 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use std::sync::Arc; -use std::time::Duration; use serverless::cgroups::Cgroups; use serverless::model::AppState; @@ -9,7 +8,7 @@ use serverless::BillingContract; use actix_web::{web, App, HttpResponse, HttpServer}; use anyhow::{anyhow, Context}; use clap::Parser; -use ethers::providers::{Http, Provider}; +use ethers::providers::{Http, Provider, ProviderExt}; use ethers::types::Address; use tokio::fs; @@ -80,9 +79,9 @@ async fn main() -> anyhow::Result<()> { ) .context("invalid signer key")?; - let rpc_provider = Provider::::try_from(&cli.rpc) - .context("Failed to connect to the rpc")? - .interval(Duration::from_millis(1000)); + let rpc_provider = Provider::::try_connect(&cli.rpc) + .await + .context("Failed to connect to the rpc")?; let billing_contract = BillingContract::new( cli.billing_contract .parse::
()