From c12c7e353bebb198177cd313397772b94a018da4 Mon Sep 17 00:00:00 2001 From: Filipe Azevedo Date: Fri, 7 Feb 2025 20:55:29 +0000 Subject: [PATCH] feat: Add DIPS ipfs validation --- Cargo.lock | 516 +++++++++++++++++++++++++++++----- Cargo.toml | 3 +- crates/dips/Cargo.toml | 12 + crates/dips/src/ipfs.rs | 234 +++++++++++++++ crates/dips/src/lib.rs | 227 ++++++++++++--- crates/dips/src/price.rs | 29 ++ crates/dips/src/server.rs | 9 +- crates/service/src/service.rs | 7 + 8 files changed, 933 insertions(+), 104 deletions(-) create mode 100644 crates/dips/src/ipfs.rs create mode 100644 crates/dips/src/price.rs diff --git a/Cargo.lock b/Cargo.lock index 69a2748c5..3f10be6e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,7 +33,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", ] @@ -45,10 +45,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -328,7 +328,7 @@ dependencies = [ "keccak-asm", "paste", "proptest", - "rand", + "rand 0.8.5", "ruint", "rustc-hash", "serde", @@ -600,7 +600,7 @@ dependencies = [ "coins-bip32", "coins-bip39", "k256", - "rand", + "rand 0.8.5", "thiserror 2.0.11", ] @@ -952,7 +952,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -962,9 +962,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.5.2" @@ -1066,7 +1072,7 @@ dependencies = [ "Inflector", "async-graphql-parser", "darling", - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "strum", @@ -1510,12 +1516,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base16ct" 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.7" @@ -1586,8 +1604,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" dependencies = [ "bitcoin_hashes", - "rand", - "rand_core", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "unicode-normalization", ] @@ -1736,7 +1754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" dependencies = [ "once_cell", - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.90", @@ -1880,9 +1898,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" dependencies = [ "serde", ] @@ -2061,7 +2079,7 @@ dependencies = [ "hmac", "once_cell", "pbkdf2", - "rand", + "rand 0.8.5", "sha2", "thiserror 1.0.69", ] @@ -2095,7 +2113,7 @@ dependencies = [ "byteorder", "cfg-if", "const-hex", - "getrandom", + "getrandom 0.2.15", "hidapi-rusb", "js-sys", "log", @@ -2137,6 +2155,22 @@ dependencies = [ "memchr", ] +[[package]] +name = "common-multipart-rfc7578" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baee326bc603965b0f26583e1ecd7c111c41b49bd92a344897476a352798869" +dependencies = [ + "bytes", + "futures-core", + "futures-util", + "http 0.2.12", + "mime", + "mime_guess", + "rand 0.8.5", + "thiserror 1.0.69", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -2203,6 +2237,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cost-model" version = "0.1.0" @@ -2299,7 +2342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -2369,6 +2412,26 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "data-encoding-macro" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" +dependencies = [ + "data-encoding", + "syn 1.0.109", +] + [[package]] name = "deadpool" version = "0.10.0" @@ -2467,6 +2530,26 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -2539,7 +2622,7 @@ dependencies = [ "group", "pem-rfc7468", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -2658,7 +2741,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -2671,7 +2754,7 @@ dependencies = [ "atomic", "pear", "serde", - "toml", + "toml 0.8.19", "uncased", "version_check", ] @@ -2689,7 +2772,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -2949,10 +3032,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + [[package]] name = "gimli" version = "0.31.1" @@ -2981,7 +3076,7 @@ dependencies = [ "parking_lot", "portable-atomic", "quanta 0.12.3", - "rand", + "rand 0.8.5", "smallvec", "spinning_top", ] @@ -3072,7 +3167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -3350,7 +3445,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -3378,6 +3473,19 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-multipart-rfc7578" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb2cf73e96e9925f4bed948e763aa2901c2f1a3a5f713ee41917433ced6671" +dependencies = [ + "bytes", + "common-multipart-rfc7578", + "futures-core", + "http 0.2.12", + "hyper 0.14.31", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -3684,7 +3792,7 @@ dependencies = [ "serde_with", "tempfile", "thegraph-core", - "toml", + "toml 0.8.19", "tracing", "tracing-test", "url", @@ -3698,8 +3806,17 @@ dependencies = [ "anyhow", "async-trait", "base64 0.22.1", + "bytes", + "derivative", + "futures", + "http 0.2.12", + "ipfs-api-backend-hyper", + "ipfs-api-prelude", "prost", "prost-types", + "rand 0.9.0", + "serde", + "serde_yaml", "thegraph-core", "thiserror 1.0.69", "tokio", @@ -3927,6 +4044,48 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ipfs-api-backend-hyper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9d131b408b4caafe1e7c00d410a09ad3eb7e3ab68690cf668e86904b2176b4" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bytes", + "futures", + "http 0.2.12", + "hyper 0.14.31", + "hyper-multipart-rfc7578", + "ipfs-api-prelude", + "thiserror 1.0.69", +] + +[[package]] +name = "ipfs-api-prelude" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b74065805db266ba2c6edbd670b23c4714824a955628472b2e46cc9f3a869cb" +dependencies = [ + "async-trait", + "bytes", + "cfg-if", + "common-multipart-rfc7578", + "dirs", + "futures", + "http 0.2.12", + "multiaddr", + "multibase", + "serde", + "serde_json", + "serde_urlencoded", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "tracing", + "walkdir", +] + [[package]] name = "ipnet" version = "2.10.1" @@ -4049,7 +4208,7 @@ dependencies = [ "http-body-util", "jsonrpsee-types", "parking_lot", - "rand", + "rand 0.8.5", "rustc-hash", "serde", "serde_json", @@ -4090,7 +4249,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" dependencies = [ "heck 0.5.0", - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.90", @@ -4217,6 +4376,16 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -4441,7 +4610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -4462,6 +4631,61 @@ dependencies = [ "version_check", ] +[[package]] +name = "multiaddr" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b36f567c7099511fa8612bbbb52dda2419ce0bdbacf31714e3a5ffdb766d3bd" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "log", + "multibase", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + +[[package]] +name = "multibase" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + +[[package]] +name = "multihash" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" +dependencies = [ + "core2", + "multihash-derive", + "unsigned-varint", +] + +[[package]] +name = "multihash-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + [[package]] name = "multimap" version = "0.10.0" @@ -4609,7 +4833,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "smallvec", "zeroize", ] @@ -4861,7 +5085,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.90", @@ -5049,7 +5273,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "122ee1f5a6843bec84fcbd5c6ba3622115337a6b8965b93a61aad347648f4e8d" dependencies = [ - "rand", + "rand 0.8.5", "socket2 0.4.10", "thiserror 1.0.69", ] @@ -5099,7 +5323,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -5133,6 +5357,16 @@ dependencies = [ "uint", ] +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror 1.0.69", + "toml 0.5.11", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -5142,6 +5376,30 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -5235,8 +5493,8 @@ dependencies = [ "bitflags 2.6.0", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax 0.8.5", "rusty-fork", @@ -5261,8 +5519,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.10.5", + "heck 0.5.0", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -5282,7 +5540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.13.0", "proc-macro2", "quote", "syn 2.0.90", @@ -5334,7 +5592,7 @@ dependencies = [ "mach2", "once_cell", "raw-cpuid 10.7.0", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -5349,7 +5607,7 @@ dependencies = [ "libc", "once_cell", "raw-cpuid 11.2.0", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -5385,8 +5643,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", - "getrandom", - "rand", + "getrandom 0.2.15", + "rand 0.8.5", "ring", "rustc-hash", "rustls 0.23.19", @@ -5450,11 +5708,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", "serde", ] +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.0", + "zerocopy 0.8.17", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -5462,7 +5731,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0", ] [[package]] @@ -5471,7 +5750,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +dependencies = [ + "getrandom 0.3.1", + "zerocopy 0.8.17", ] [[package]] @@ -5480,7 +5769,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -5536,6 +5825,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 1.0.69", +] + [[package]] name = "regex" version = "1.11.1" @@ -5713,7 +6013,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -5787,7 +6087,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "signature", "spki", "subtle", @@ -5826,7 +6126,7 @@ checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" dependencies = [ "cfg-if", "glob", - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "regex", @@ -5844,7 +6144,7 @@ checksum = "ef0053bbffce09062bee4bcc499b0fbe7a57b879f1efe088d6d8d4c7adcdef9b" dependencies = [ "cfg-if", "glob", - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "regex", @@ -5870,7 +6170,7 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand", + "rand 0.8.5", "rlp", "ruint-macro", "serde", @@ -5904,7 +6204,7 @@ dependencies = [ "borsh", "bytes", "num-traits", - "rand", + "rand 0.8.5", "rkyv", "serde", "serde_json", @@ -6414,6 +6714,19 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.7.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1" version = "0.10.6" @@ -6487,7 +6800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -6570,7 +6883,7 @@ dependencies = [ "http 1.1.0", "httparse", "log", - "rand", + "rand 0.8.5", "sha1", ] @@ -6749,7 +7062,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand", + "rand 0.8.5", "rsa", "rust_decimal", "serde", @@ -6793,7 +7106,7 @@ dependencies = [ "memchr", "num-bigint 0.4.6", "once_cell", - "rand", + "rand 0.8.5", "rust_decimal", "serde", "serde_json", @@ -6944,6 +7257,18 @@ dependencies = [ "futures-core", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + [[package]] name = "synstructure" version = "0.13.1" @@ -7054,7 +7379,7 @@ dependencies = [ "alloy", "anyhow", "async-trait", - "rand", + "rand 0.8.5", "serde", "tap_eip712_message", "tap_graph", @@ -7079,7 +7404,7 @@ version = "0.2.0" source = "git+https://github.com/semiotic-ai/timeline-aggregation-protocol?rev=9fd4beb#9fd4beb4a8c55114a4e33b851b86d80b71d42a00" dependencies = [ "alloy", - "rand", + "rand 0.8.5", "serde", "tap_eip712_message", "tap_receipt", @@ -7433,6 +7758,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" @@ -7527,7 +7861,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project 1.1.9", "pin-project-lite", - "rand", + "rand 0.8.5", "slab", "tokio", "tokio-util", @@ -7738,7 +8072,7 @@ dependencies = [ "http 1.1.0", "httparse", "log", - "rand", + "rand 0.8.5", "rustls 0.23.19", "rustls-pki-types", "sha1", @@ -7859,6 +8193,18 @@ dependencies = [ "void", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unsigned-varint" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" + [[package]] name = "untrusted" version = "0.9.0" @@ -7919,7 +8265,7 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -7996,6 +8342,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasite" version = "0.1.0" @@ -8182,7 +8537,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -8489,11 +8844,20 @@ dependencies = [ "http-body 1.0.1", "log", "prost", - "rand", + "rand 0.8.5", "tokio", "tonic", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -8561,7 +8925,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.90", - "synstructure", + "synstructure 0.13.1", ] [[package]] @@ -8571,7 +8935,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +dependencies = [ + "zerocopy-derive 0.8.17", ] [[package]] @@ -8585,6 +8958,17 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "zerofrom" version = "0.1.5" @@ -8603,7 +8987,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.90", - "synstructure", + "synstructure 0.13.1", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 71d412abc..7a45f72f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = [ "crates/attestation", "crates/config", "crates/dips", - "crates/indexer-receipt", + "crates/indexer-receipt", "crates/monitor", "crates/query", "crates/service", @@ -82,6 +82,7 @@ prost = "0.13.4" prost-types = "0.13.3" dipper-rpc = { git = "https://github.com/edgeandnode/dipper/", rev = "c8700e2", default-features = false } tonic-build = "0.12.3" +serde_yaml = "0.9.21" [patch.crates-io.tap_core] git = "https://github.com/semiotic-ai/timeline-aggregation-protocol" diff --git a/crates/dips/Cargo.toml b/crates/dips/Cargo.toml index 049fd23b1..66c49ebe0 100644 --- a/crates/dips/Cargo.toml +++ b/crates/dips/Cargo.toml @@ -15,6 +15,18 @@ prost-types.workspace = true uuid.workspace = true base64.workspace = true tokio.workspace = true +futures = "0.3" + +http = "0.2" +derivative = "2.2.0" +ipfs-api-backend-hyper = {version = "0.6.0", features = ["with-send-sync"] } +ipfs-api-prelude = {version = "0.6.0", features = ["with-send-sync"] } +bytes = "1.10.0" +serde_yaml.workspace = true +serde.workspace = true + +[dev-dependencies] +rand = "0.9.0" [build-dependencies] tonic-build = { workspace = true } diff --git a/crates/dips/src/ipfs.rs b/crates/dips/src/ipfs.rs new file mode 100644 index 000000000..111de93e0 --- /dev/null +++ b/crates/dips/src/ipfs.rs @@ -0,0 +1,234 @@ +// Copyright 2023-, Edge & Node, GraphOps, and Semiotic Labs. +// SPDX-License-Identifier: Apache-2.0 + +use std::{str::FromStr, sync::Arc}; + +use derivative::Derivative; +use futures::TryStreamExt; +use http::Uri; +use ipfs_api_prelude::{IpfsApi, TryFromUri}; +use serde::Deserialize; +use tonic::async_trait; + +use crate::DipsError; + +#[async_trait] +pub trait IpfsFetcher: Send + Sync + std::fmt::Debug { + async fn fetch(&self, file: &str) -> Result; +} + +#[async_trait] +impl IpfsFetcher for Arc { + async fn fetch(&self, file: &str) -> Result { + self.as_ref().fetch(file).await + } +} + +#[derive(Derivative)] +#[derivative(Debug)] +pub struct IpfsClient { + #[derivative(Debug = "ignore")] + client: ipfs_api_backend_hyper::IpfsClient, +} + +impl IpfsClient { + pub fn new(url: &str) -> anyhow::Result { + Ok(Self { + client: ipfs_api_backend_hyper::IpfsClient::build_with_base_uri( + Uri::from_str(url).map_err(|err| anyhow::Error::from(err))?, + ), + }) + } +} + +#[async_trait] +impl IpfsFetcher for IpfsClient { + async fn fetch(&self, file: &str) -> Result { + let content = self + .client + .get(file.as_ref()) + .map_ok(|chunk| chunk.to_vec()) + .try_concat() + .await + .unwrap(); + + let manifest: GraphManifest = serde_yaml::from_slice(&content) + .map_err(|_| DipsError::InvalidSubgraphManifest(file.to_string()))?; + + Ok(manifest) + } +} + +#[derive(Default, Debug, Clone, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DataSource { + network: String, +} + +#[derive(Default, Debug, Clone, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GraphManifest { + data_sources: Vec, +} + +impl GraphManifest { + pub fn network(&self) -> Option { + self.data_sources.first().map(|ds| ds.network.clone()) + } +} + +#[cfg(test)] +#[derive(Debug)] +pub struct TestIpfsClient { + manifest: GraphManifest, +} + +#[cfg(test)] +impl TestIpfsClient { + pub fn mainnet() -> Self { + Self { + manifest: GraphManifest { + data_sources: vec![DataSource { + network: "mainnet".to_string(), + }], + }, + } + } +} + +#[cfg(test)] +#[async_trait] +impl IpfsFetcher for TestIpfsClient { + async fn fetch(&self, _file: &str) -> Result { + Ok(self.manifest.clone()) + } +} + +#[cfg(test)] +mod test { + use crate::ipfs::{DataSource, GraphManifest}; + + #[test] + fn test_deserialize_manifest() { + let manifest: GraphManifest = serde_yaml::from_str(&MANIFEST).unwrap(); + assert_eq!( + manifest, + GraphManifest { + data_sources: vec![ + DataSource { + network: "scroll".to_string() + }, + DataSource { + network: "scroll".to_string() + } + ], + } + ) + } + + const MANIFEST: &'static str = " +dataSources: + - kind: ethereum/contract + mapping: + abis: + - file: + /: /ipfs/QmTU8eKx6pCgtff6Uvc7srAwR8BPiM3jTMBw9ahrXBjRzY + name: Factory + apiVersion: 0.0.6 + entities: [] + eventHandlers: + - event: >- + PoolCreated(indexed address,indexed address,indexed + uint24,int24,address) + handler: handlePoolCreated + file: + /: /ipfs/Qmbj3ituUaFRnTuahJ8yCG9GPiPqsRYq2T7umucZzPpLFn + kind: ethereum/events + language: wasm/assemblyscript + name: Factory + network: scroll + source: + abi: Factory + address: '0x46B3fDF7b5CDe91Ac049936bF0bDb12c5d22202e' + startBlock: 82522 + - kind: ethereum/contract + mapping: + abis: + - file: + /: /ipfs/QmaxxqQ7xzbGDPWu184uoq2g5sofazB9B9tEDrpPjmRZ8q + name: NonfungiblePositionManager + + apiVersion: 0.0.6 + entities: [] + eventHandlers: + - event: 'IncreaseLiquidity(indexed uint256,uint128,uint256,uint256)' + handler: handleIncreaseLiquidity + file: + /: /ipfs/QmcWrYawVufpST4u2Ed8Jz6jxFFaYXxERGwqstrpniY8C5 + kind: ethereum/events + language: wasm/assemblyscript + name: NonfungiblePositionManager + network: scroll + source: + abi: NonfungiblePositionManager + address: '0x0389879e0156033202C44BF784ac18fC02edeE4f' + startBlock: 82597 +features: + - nonFatalErrors +schema: + file: + /: /ipfs/QmSCM39NPLAjNQXsnkqq6H8z8KBi5YkfYyApPYLQbbC2kb +specVersion: 0.0.4 +templates: + - kind: ethereum/contract + mapping: + abis: + - file: + /: /ipfs/QmULRc8Ac1J6YFy11z7JRpyThb6f7nmL5mMTQvN7LKj2Vy + name: Pool + - file: + /: /ipfs/QmTU8eKx6pCgtff6Uvc7srAwR8BPiM3jTMBw9ahrXBjRzY + name: Factory + - file: + /: /ipfs/QmXuTbDkNrN27VydxbS2huvKRk62PMgUTdPDWkxcr2w7j2 + name: ERC20 + apiVersion: 0.0.6 + entities: [] + eventHandlers: + - event: 'Initialize(uint160,int24)' + handler: handleInitialize + - event: >- + Swap(indexed address,indexed + address,int256,int256,uint160,uint128,int24) + handler: handleSwap + - event: >- + Mint(address,indexed address,indexed int24,indexed + int24,uint128,uint256,uint256) + handler: handleMint + - event: >- + Burn(indexed address,indexed int24,indexed + int24,uint128,uint256,uint256) + handler: handleBurn + - event: >- + Flash(indexed address,indexed + address,uint256,uint256,uint256,uint256) + handler: handleFlash + - event: >- + Collect(indexed address,address,indexed int24,indexed + int24,uint128,uint128) + handler: handlePoolCollect + - event: 'CollectProtocol(indexed address,indexed address,uint128,uint128)' + handler: handleProtocolCollect + - event: 'SetFeeProtocol(uint8,uint8,uint8,uint8)' + handler: handleSetProtocolFee + file: + /: /ipfs/QmPtcuzBcWWBGXFKGdfUgqZLJov4c4Crt85ANbER2eHdCb + kind: ethereum/events + language: wasm/assemblyscript + name: Pool + network: scroll + source: + abi: Pool + + "; +} diff --git a/crates/dips/src/lib.rs b/crates/dips/src/lib.rs index ea00ef060..cf23f073f 100644 --- a/crates/dips/src/lib.rs +++ b/crates/dips/src/lib.rs @@ -3,14 +3,18 @@ use std::{str::FromStr, sync::Arc}; +use ipfs::IpfsFetcher; +use price::PriceCalculator; use thegraph_core::alloy::{ core::primitives::Address, - primitives::{b256, ChainId, PrimitiveSignature as Signature, B256}, + primitives::{b256, ChainId, PrimitiveSignature as Signature, Uint, B256}, signers::SignerSync, sol, sol_types::{eip712_domain, Eip712Domain, SolStruct, SolValue}, }; +pub mod ipfs; +pub mod price; pub mod proto; pub mod server; pub mod store; @@ -131,6 +135,14 @@ pub enum DipsError { PayerNotAuthorised(Address), #[error("voucher payee {actual} does not match the expected address {expected}")] UnexpectedPayee { expected: Address, actual: Address }, + #[error("invalid subgraph id {0}")] + InvalidSubgraphManifest(String), + #[error("voucher for chain id {0}, subgraph manifest has network {1}")] + SubgraphChainIdMistmatch(String, String), + #[error("chainId {0} is not supported")] + UnsupportedChainId(String), + #[error("price per block is below configured price for chain {0}, minimum: {1}, offered: {2}")] + PricePerBlockTooLow(String, u64, String), // cancellation #[error("cancelled_by is expected to match the signer")] UnexpectedSigner, @@ -276,6 +288,8 @@ pub async fn validate_and_create_agreement( expected_payee: &Address, allowed_payers: impl AsRef<[Address]>, voucher: Vec, + price_calculator: &PriceCalculator, + ipfs_client: Arc, ) -> Result { let decoded_voucher = SignedIndexingAgreementVoucher::abi_decode(voucher.as_ref(), true) .map_err(|e| DipsError::AbiDecoding(e.to_string()))?; @@ -287,6 +301,35 @@ pub async fn validate_and_create_agreement( decoded_voucher.validate(domain, expected_payee, allowed_payers)?; + let manifest = ipfs_client.fetch(&metadata.subgraphDeploymentId).await?; + match manifest.network() { + Some(chain_id) if chain_id == metadata.chainId => {} + Some(chain_id) => { + return Err(DipsError::SubgraphChainIdMistmatch( + metadata.chainId, + chain_id, + )) + } + None => return Err(DipsError::UnsupportedChainId("".to_string())), + } + + let chain_id = manifest + .network() + .ok_or_else(|| DipsError::UnsupportedChainId("".to_string()))?; + + let offered_price = metadata.pricePerEntity; + match price_calculator.get_minimum_price(&chain_id) { + Some(price) if offered_price.lt(&Uint::from(price)) => { + return Err(DipsError::PricePerBlockTooLow( + chain_id, + price, + offered_price.to_string(), + )) + } + Some(_) => {} + None => return Err(DipsError::UnsupportedChainId(chain_id)), + } + store .create_agreement(decoded_voucher.clone(), metadata) .await?; @@ -333,15 +376,18 @@ mod test { use thegraph_core::alloy::{ primitives::{Address, FixedBytes, U256}, signers::local::PrivateKeySigner, - sol_types::SolValue, + sol_types::{Eip712Domain, SolValue}, }; use uuid::Uuid; pub use crate::store::{AgreementStore, InMemoryAgreementStore}; use crate::{ - dips_agreement_eip712_domain, dips_cancellation_eip712_domain, CancellationRequest, - DipsError, IndexingAgreementVoucher, SubgraphIndexingVoucherMetadata, + dips_agreement_eip712_domain, dips_cancellation_eip712_domain, ipfs::TestIpfsClient, + price::PriceCalculator, CancellationRequest, DipsError, IndexingAgreementVoucher, + SignedIndexingAgreementVoucher, SubgraphIndexingVoucherMetadata, }; + use rand::distr::Alphanumeric; + use rand::Rng; #[tokio::test] async fn test_validate_and_create_agreement() -> anyhow::Result<()> { @@ -355,7 +401,7 @@ mod test { basePricePerEpoch: U256::from(10000_u64), pricePerEntity: U256::from(100_u64), protocolNetwork: "eip155:42161".to_string(), - chainId: "eip155:1".to_string(), + chainId: "mainnet".to_string(), subgraphDeploymentId: deployment_id, }; @@ -386,6 +432,8 @@ mod test { &payee_addr, vec![payer_addr], abi_voucher, + &PriceCalculator::for_testing(), + Arc::new(TestIpfsClient::mainnet()), ) .await .unwrap(); @@ -530,13 +578,62 @@ mod test { } } } + struct VoucherContext { + payee: PrivateKeySigner, + payer: PrivateKeySigner, + deployment_id: String, + } + + impl VoucherContext { + pub fn random() -> Self { + Self { + payee: PrivateKeySigner::random(), + payer: PrivateKeySigner::random(), + deployment_id: rand::rng() + .sample_iter(&Alphanumeric) + .take(32) + .map(char::from) + .collect(), + } + } + pub fn domain(&self) -> Eip712Domain { + dips_agreement_eip712_domain() + } + + pub fn test_voucher( + &self, + metadata: SubgraphIndexingVoucherMetadata, + ) -> SignedIndexingAgreementVoucher { + let agreement_id = Uuid::now_v7(); + + let domain = dips_agreement_eip712_domain(); + + let voucher = IndexingAgreementVoucher { + agreement_id: agreement_id.as_bytes().into(), + payer: self.payer.address(), + recipient: self.payee.address(), + service: Address::ZERO, + durationEpochs: 100, + maxInitialAmount: U256::from(1000000_u64), + maxOngoingAmountPerEpoch: U256::from(10000_u64), + minEpochsPerCollection: 1, + maxEpochsPerCollection: 10, + deadline: (SystemTime::now() + Duration::from_secs(3600)) + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + metadata: metadata.abi_encode().into(), + }; + + let signed_voucher = voucher.sign(&domain, self.payer.clone()).unwrap(); + + signed_voucher + } + } + #[tokio::test] async fn test_create_and_cancel_agreement() -> anyhow::Result<()> { - let deployment_id = "Qmbg1qF4YgHjiVfsVt6a13ddrVcRtWyJQfD4LA3CwHM29f".to_string(); - let payee = PrivateKeySigner::random(); - let payee_addr = payee.address(); - let payer = PrivateKeySigner::random(); - let payer_addr = payer.address(); + let voucher_ctx = VoucherContext::random(); let store = Arc::new(InMemoryAgreementStore::default()); // Create metadata and voucher @@ -544,37 +641,20 @@ mod test { basePricePerEpoch: U256::from(10000_u64), pricePerEntity: U256::from(100_u64), protocolNetwork: "eip155:42161".to_string(), - chainId: "eip155:1".to_string(), - subgraphDeploymentId: deployment_id, - }; - - let agreement_id = Uuid::now_v7(); - let voucher = IndexingAgreementVoucher { - agreement_id: agreement_id.as_bytes().into(), - payer: payer_addr, - recipient: payee_addr, - service: Address::ZERO, - durationEpochs: 100, - maxInitialAmount: U256::from(1000000_u64), - maxOngoingAmountPerEpoch: U256::from(10000_u64), - minEpochsPerCollection: 1, - maxEpochsPerCollection: 10, - deadline: (SystemTime::now() + Duration::from_secs(3600)) - .duration_since(UNIX_EPOCH)? - .as_secs(), - metadata: metadata.abi_encode().into(), + chainId: "mainnet".to_string(), + subgraphDeploymentId: voucher_ctx.deployment_id.clone(), }; - - let domain = dips_agreement_eip712_domain(); - let signed_voucher = voucher.sign(&domain, payer.clone())?; + let signed_voucher = voucher_ctx.test_voucher(metadata); // Create agreement let agreement_id = super::validate_and_create_agreement( store.clone(), - &domain, - &payee_addr, - vec![payer_addr], + &voucher_ctx.domain(), + &voucher_ctx.payee.address(), + vec![voucher_ctx.payer.address()], signed_voucher.encode_vec(), + &PriceCalculator::for_testing(), + Arc::new(TestIpfsClient::mainnet()), ) .await?; @@ -583,7 +663,7 @@ mod test { let cancel_request = CancellationRequest { agreement_id: agreement_id.as_bytes().into(), }; - let signed_cancel = cancel_request.sign(&cancel_domain, payer)?; + let signed_cancel = cancel_request.sign(&cancel_domain, voucher_ctx.payer)?; // Cancel agreement let cancelled_id = super::validate_and_cancel_agreement( @@ -602,4 +682,79 @@ mod test { Ok(()) } + + #[tokio::test] + async fn test_create_validations_errors() -> anyhow::Result<()> { + let voucher_ctx = VoucherContext::random(); + let store = Arc::new(InMemoryAgreementStore::default()); + + let metadata = SubgraphIndexingVoucherMetadata { + basePricePerEpoch: U256::from(10000_u64), + pricePerEntity: U256::from(100_u64), + protocolNetwork: "eip155:42161".to_string(), + chainId: "mainnet2".to_string(), + subgraphDeploymentId: voucher_ctx.deployment_id.clone(), + }; + + let wrong_network_voucher = voucher_ctx.test_voucher(metadata); + + let metadata = SubgraphIndexingVoucherMetadata { + basePricePerEpoch: U256::from(10000_u64), + pricePerEntity: U256::from(10_u64), + protocolNetwork: "eip155:42161".to_string(), + chainId: "mainnet".to_string(), + subgraphDeploymentId: voucher_ctx.deployment_id.clone(), + }; + + let low_price_voucher = voucher_ctx.test_voucher(metadata); + + let metadata = SubgraphIndexingVoucherMetadata { + basePricePerEpoch: U256::from(10000_u64), + pricePerEntity: U256::from(100_u64), + protocolNetwork: "eip155:42161".to_string(), + chainId: "mainnet".to_string(), + subgraphDeploymentId: voucher_ctx.deployment_id.clone(), + }; + + let valid_voucher = voucher_ctx.test_voucher(metadata); + + let expected_result: Vec> = vec![ + Err(DipsError::SubgraphChainIdMistmatch( + "mainnet2".to_string(), + "mainnet".to_string(), + )), + Err(DipsError::PricePerBlockTooLow( + "mainnet".to_string(), + 100, + "10".to_string(), + )), + Ok(valid_voucher + .voucher + .agreement_id + .as_slice() + .try_into() + .unwrap()), + ]; + let cases = vec![wrong_network_voucher, low_price_voucher, valid_voucher]; + for (voucher, result) in cases.into_iter().zip(expected_result.into_iter()) { + let out = super::validate_and_create_agreement( + store.clone(), + &voucher_ctx.domain(), + &voucher_ctx.payee.address(), + vec![voucher_ctx.payer.address()], + voucher.encode_vec(), + &PriceCalculator::for_testing(), + Arc::new(TestIpfsClient::mainnet()), + ) + .await; + + match (out, result) { + (Ok(a), Ok(b)) => assert_eq!(a.into_bytes(), b), + (Err(a), Err(b)) => assert_eq!(a.to_string(), b.to_string()), + (a, b) => assert!(false, "{:?} did not match {:?}", a, b), + } + } + + Ok(()) + } } diff --git a/crates/dips/src/price.rs b/crates/dips/src/price.rs new file mode 100644 index 000000000..e98026b78 --- /dev/null +++ b/crates/dips/src/price.rs @@ -0,0 +1,29 @@ +// Copyright 2023-, Edge & Node, GraphOps, and Semiotic Labs. +// SPDX-License-Identifier: Apache-2.0 + +use std::collections::HashMap; + +#[derive(Debug, Default)] +pub struct PriceCalculator { + prices_per_chain: HashMap, + default_price: Option, +} + +impl PriceCalculator { + #[cfg(test)] + pub fn for_testing() -> Self { + Self { + prices_per_chain: HashMap::default(), + default_price: Some(100), + } + } + + pub fn is_supported(&self, chain_id: &str) -> bool { + self.get_minimum_price(chain_id).is_some() + } + pub fn get_minimum_price(&self, chain_id: &str) -> Option { + let chain_price = self.prices_per_chain.get(chain_id).map(|p| *p); + + chain_price.or(self.default_price) + } +} diff --git a/crates/dips/src/server.rs b/crates/dips/src/server.rs index 0feb35c39..926829834 100644 --- a/crates/dips/src/server.rs +++ b/crates/dips/src/server.rs @@ -4,10 +4,13 @@ use std::sync::Arc; use async_trait::async_trait; -use thegraph_core::alloy::{dyn_abi::Eip712Domain, primitives::Address}; +use thegraph_core::alloy::primitives::Address; +use thegraph_core::alloy::sol_types::Eip712Domain; use tonic::{Request, Response, Status}; use crate::{ + ipfs::IpfsFetcher, + price::PriceCalculator, proto::indexer::graphprotocol::indexer::dips::{ dips_service_server::DipsService, CancelAgreementRequest, CancelAgreementResponse, ProposalResponse, SubmitAgreementProposalRequest, SubmitAgreementProposalResponse, @@ -22,6 +25,8 @@ pub struct DipsServer { pub expected_payee: Address, pub allowed_payers: Vec
, pub domain: Eip712Domain, + pub ipfs_fetcher: Arc, + pub price_calculator: PriceCalculator, } #[async_trait] @@ -50,6 +55,8 @@ impl DipsService for DipsServer { &self.expected_payee, &self.allowed_payers, signed_voucher, + &self.price_calculator, + self.ipfs_fetcher.clone(), ) .await .map_err(Into::::into)?; diff --git a/crates/service/src/service.rs b/crates/service/src/service.rs index fea102ecf..f74807aaa 100644 --- a/crates/service/src/service.rs +++ b/crates/service/src/service.rs @@ -8,6 +8,8 @@ use axum::{extract::Request, serve, ServiceExt}; use clap::Parser; use indexer_config::{Config, DipsConfig, GraphNodeConfig, SubgraphConfig}; use indexer_dips::{ + ipfs::{IpfsClient, IpfsFetcher}, + price::PriceCalculator, proto::indexer::graphprotocol::indexer::dips::dips_service_server::{ DipsService, DipsServiceServer, }, @@ -133,11 +135,16 @@ pub async fn run() -> anyhow::Result<()> { .parse() .expect("invalid dips host port"); + let ipfs_fetcher: Arc = + Arc::new(IpfsClient::new("https://api.thegraph.com/ipfs/").unwrap()); + let dips = DipsServer { agreement_store: Arc::new(PsqlAgreementStore { pool: database }), expected_payee: indexer_address, allowed_payers: allowed_payers.clone(), domain: domain_separator, + ipfs_fetcher, + price_calculator: PriceCalculator::default(), }; info!("starting dips grpc server on {}", addr);