From f8aaf14a31cf3f274b81d25eefbc431b626d0515 Mon Sep 17 00:00:00 2001 From: erhant Date: Mon, 9 Dec 2024 16:45:48 +0300 Subject: [PATCH 01/14] added validation setups --- Cargo.lock | 134 +++++++++--------- src/compute/handlers/generation.rs | 11 +- src/compute/handlers/validation.rs | 15 +- src/compute/workflows/common.rs | 28 ++++ .../{requests/mod.rs => generation.rs} | 97 +++++++------ src/compute/workflows/mod.rs | 10 +- src/compute/workflows/postprocess/swan.rs | 26 ++-- .../workflows/{presets/mod.rs => presets.rs} | 9 +- src/compute/workflows/presets/chat.json | 10 +- src/compute/workflows/presets/generation.json | 9 +- src/compute/workflows/presets/validation.json | 2 +- src/compute/workflows/validation.rs | 65 +++++++++ tests/generation_test.rs | 7 + 13 files changed, 265 insertions(+), 158 deletions(-) create mode 100644 src/compute/workflows/common.rs rename src/compute/workflows/{requests/mod.rs => generation.rs} (75%) rename src/compute/workflows/{presets/mod.rs => presets.rs} (68%) create mode 100644 src/compute/workflows/validation.rs create mode 100644 tests/generation_test.rs diff --git a/Cargo.lock b/Cargo.lock index 1e7931f..2a2da3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,11 +90,11 @@ dependencies = [ [[package]] name = "alloy-chains" -version = "0.1.47" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" +checksum = "a0161082e0edd9013d23083465cc04b20e44b7a15646d36ba7b0cdb7cd6fe18f" dependencies = [ - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.15", "num_enum", "serde", "strum 0.26.3", @@ -290,9 +290,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9db948902dfbae96a73c2fbf1f7abec62af034ab883e4c777c3fd29702bd6e2c" +checksum = "6259a506ab13e1d658796c31e6e39d2e2ee89243bcc505ddc613b35732e0a430" dependencies = [ "alloy-rlp", "bytes 1.9.0", @@ -375,9 +375,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" +checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -386,9 +386,9 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" +checksum = "5a833d97bf8a5f0f878daf2c8451fff7de7f9de38baa5a45d936ec718d81255a" dependencies = [ "proc-macro2", "quote", @@ -1301,9 +1301,9 @@ checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad" [[package]] name = "cc" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "shlex", ] @@ -1339,9 +1339,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1353,9 +1353,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.22" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -1363,9 +1363,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.22" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -1387,9 +1387,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" @@ -1876,13 +1876,13 @@ dependencies = [ [[package]] name = "dkn-utils" -version = "0.2.26" -source = "git+https://github.com/firstbatchxyz/dkn-compute-node#1c6fded688ce0ba58608206d50271fcf903f1891" +version = "0.2.28" +source = "git+https://github.com/firstbatchxyz/dkn-compute-node#e6e7b012dd322f98d11ab3c0a64c6f9265076019" [[package]] name = "dkn-workflows" -version = "0.2.26" -source = "git+https://github.com/firstbatchxyz/dkn-compute-node#1c6fded688ce0ba58608206d50271fcf903f1891" +version = "0.2.28" +source = "git+https://github.com/firstbatchxyz/dkn-compute-node#e6e7b012dd322f98d11ab3c0a64c6f9265076019" dependencies = [ "dkn-utils", "env_logger 0.11.5", @@ -2134,9 +2134,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -2853,7 +2853,7 @@ dependencies = [ "rustls 0.23.19", "rustls-pki-types", "tokio 1.42.0", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tower-service", "webpki-roots 0.26.7", ] @@ -3242,9 +3242,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ "once_cell", "wasm-bindgen", @@ -3350,9 +3350,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libflate" @@ -3792,7 +3792,7 @@ dependencies = [ [[package]] name = "ollama-workflows" version = "0.1.0" -source = "git+https://github.com/andthattoo/ollama-workflows#5b26cb4fdd5278295534cbedf79acdf4f9cd2b37" +source = "git+https://github.com/andthattoo/ollama-workflows#23999766ac759b122a93d1e830f0387deffb1d6e" dependencies = [ "async-trait", "base64 0.22.1", @@ -3977,12 +3977,12 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 1.0.69", + "thiserror 2.0.6", "ucd-trie", ] @@ -4409,7 +4409,7 @@ dependencies = [ "rustc-hash", "rustls 0.23.19", "socket2 0.5.8", - "thiserror 2.0.4", + "thiserror 2.0.6", "tokio 1.42.0", "tracing", ] @@ -4428,7 +4428,7 @@ dependencies = [ "rustls 0.23.19", "rustls-pki-types", "slab", - "thiserror 2.0.4", + "thiserror 2.0.6", "tinyvec", "tracing", "web-time", @@ -4436,9 +4436,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" dependencies = [ "cfg_aliases", "libc", @@ -4718,7 +4718,7 @@ dependencies = [ "system-configuration 0.6.1", "tokio 1.42.0", "tokio-native-tls", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tokio-util 0.7.13", "tower-service", "url", @@ -4891,15 +4891,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5796,11 +5796,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.4" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" dependencies = [ - "thiserror-impl 2.0.4", + "thiserror-impl 2.0.6", ] [[package]] @@ -5816,9 +5816,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.4" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", @@ -5978,20 +5978,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ "rustls 0.23.19", - "rustls-pki-types", "tokio 1.42.0", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite 0.2.15", @@ -6020,7 +6019,7 @@ dependencies = [ "rustls 0.23.19", "rustls-pki-types", "tokio 1.42.0", - "tokio-rustls 0.26.0", + "tokio-rustls 0.26.1", "tungstenite", "webpki-roots 0.26.7", ] @@ -6436,9 +6435,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -6449,13 +6448,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn 2.0.90", @@ -6464,9 +6462,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.47" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -6477,9 +6475,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6487,9 +6485,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -6500,9 +6498,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.97" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-streams" @@ -6519,9 +6517,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/src/compute/handlers/generation.rs b/src/compute/handlers/generation.rs index dd1509e..9c5dd92 100644 --- a/src/compute/handlers/generation.rs +++ b/src/compute/handlers/generation.rs @@ -1,5 +1,5 @@ use crate::{ - compute::Request, + compute::GenerationRequest, contracts::{bytes32_to_string, bytes_to_string}, data::Arweave, mine_nonce, DriaOracle, @@ -52,13 +52,16 @@ pub async fn handle_generation( // execute task log::debug!("Executing the workflow"); - let mut input = Request::try_parse_bytes(&request.input).await?; + let mut input = GenerationRequest::try_parse_bytes(&request.input).await?; let output = input.execute(model, Some(node)).await?; log::debug!("Output: {}", output); // post-processing - log::debug!("Post-processing the output"); - let (output, metadata, use_storage) = Request::post_process(output, &protocol_string).await?; + log::debug!( + "Post-processing the output for protocol: {}", + protocol_string + ); + let (output, metadata, use_storage) = GenerationRequest::post_process(output, &protocol_string).await?; // uploading to storage log::debug!("Uploading output to storage"); diff --git a/src/compute/handlers/validation.rs b/src/compute/handlers/validation.rs index efa3882..eb887d1 100644 --- a/src/compute/handlers/validation.rs +++ b/src/compute/handlers/validation.rs @@ -41,16 +41,15 @@ pub async fn handle_validation( .wrap_err("could not get task request")?; // fetch each generation response & score it - // for i in 0..request.parameters.numGenerations { - // // let response = node - // // .get_task_responses(task_id, i) - // // .await - // // .wrap_err("could not get generation")?; - // let score = parse_ether("1.0").unwrap(); - // } + log::debug!("Starting validations"); + let mut scores = Vec::new(); + for i in 0..request.parameters.numGenerations { + let score = parse_ether("1.0").unwrap(); + scores.push(score); + } // FIXME: will add validation prompt here - log::debug!("Validating the task"); + let scores = (0..request.parameters.numGenerations) .map(|_| parse_ether("1.0").unwrap()) .collect::>(); diff --git a/src/compute/workflows/common.rs b/src/compute/workflows/common.rs new file mode 100644 index 0000000..03e9c72 --- /dev/null +++ b/src/compute/workflows/common.rs @@ -0,0 +1,28 @@ +use alloy::primitives::Bytes; +use eyre::{Context, Result}; + +use crate::{ + bytes_to_string, + data::{Arweave, OracleExternalData}, +}; + +/// Parses a given bytes input to a string, and if it is a storage key identifier it automatically +/// downloads the data from Arweave. +pub async fn parse_downloadable(input_bytes: &Bytes) -> Result { + // first, convert to string + let mut input_string = bytes_to_string(input_bytes)?; + + // then, check storage + if Arweave::is_key(input_string.clone()) { + // if its a txid, we download the data and parse it again + let input_bytes_from_arweave = Arweave::default() + .get(input_string) + .await + .wrap_err("could not download from Arweave")?; + + // convert the input to string + input_string = bytes_to_string(&input_bytes_from_arweave)?; + } + + Ok(input_string) +} diff --git a/src/compute/workflows/requests/mod.rs b/src/compute/workflows/generation.rs similarity index 75% rename from src/compute/workflows/requests/mod.rs rename to src/compute/workflows/generation.rs index 70abe7b..f93a294 100644 --- a/src/compute/workflows/requests/mod.rs +++ b/src/compute/workflows/generation.rs @@ -3,11 +3,7 @@ use dkn_workflows::{Entry, Executor, MessageInput, Model, ProgramMemory, Workflo use eyre::{eyre, Context, Result}; use super::{postprocess::*, presets::*}; -use crate::{ - bytes_to_string, - data::{Arweave, OracleExternalData}, - DriaOracle, -}; +use crate::{compute::parse_downloadable, DriaOracle}; /// A request with chat history. #[derive(Debug, serde::Serialize, serde::Deserialize)] @@ -20,7 +16,7 @@ pub struct ChatHistoryRequest { /// An oracle request. #[derive(Debug)] -pub enum Request { +pub enum GenerationRequest { /// A chat-history request. ChatHistory(ChatHistoryRequest), /// The request itself is a Workflow object, we execute it directly. @@ -29,7 +25,7 @@ pub enum Request { String(String), } -impl Request { +impl GenerationRequest { pub fn request_type(&self) -> &str { match self { Self::ChatHistory(_) => "chat", @@ -40,7 +36,7 @@ impl Request { /// Given an input of byte-slice, parses it into a valid request type. pub async fn try_parse_bytes(input_bytes: &Bytes) -> Result { - let input_string = Self::parse_downloadable(input_bytes).await?; + let input_string = parse_downloadable(input_bytes).await?; log::debug!("Parsing input string: {}", input_string); Ok(Self::try_parse_string(input_string).await) } @@ -48,27 +44,34 @@ impl Request { /// Given an input of string, parses it into a valid request type. pub async fn try_parse_string(input_string: String) -> Self { if let Ok(chat_input) = serde_json::from_str::(&input_string) { - Request::ChatHistory(chat_input) + GenerationRequest::ChatHistory(chat_input) } else if let Ok(workflow) = serde_json::from_str::(&input_string) { - Request::Workflow(workflow) + GenerationRequest::Workflow(workflow) } else { - Request::String(input_string) + GenerationRequest::String(input_string) } } /// Executes a request using the given model, and optionally a node. /// Returns the raw string output. pub async fn execute(&mut self, model: Model, node: Option<&DriaOracle>) -> Result { - log::debug!("Executing {} request with: {}", self.request_type(), model); + log::debug!( + "Executing {} generation request with: {}", + self.request_type(), + model + ); let mut memory = ProgramMemory::new(); let executor = Executor::new(model); match self { + // workflows are executed directly without any prompts + // as we expect their memory to be pre-filled Self::Workflow(workflow) => executor .execute(None, workflow, &mut memory) .await .wrap_err("could not execute worfklow input"), + // string requests are used with the generation workflow with a given prompt Self::String(input) => { let entry = Entry::String(input.clone()); executor @@ -77,6 +80,8 @@ impl Request { .wrap_err("could not execute worfklow for string input") } + // chat history requests are used with the chat workflow + // and the existing history is fetched & parsed from previous requests Self::ChatHistory(chat_request) => { let mut history = if chat_request.history_id == 0 { // if task id is zero, there is no prior history @@ -89,7 +94,7 @@ impl Request { .wrap_err("could not get chat history task from contract")?; // parse it as chat history output - let history_str = Self::parse_downloadable(&history_task.output).await?; + let history_str = parse_downloadable(&history_task.output).await?; serde_json::from_str::>(&history_str)? } else { @@ -128,6 +133,10 @@ impl Request { } } + /// Post-processes the output string based on the given protocol. + /// Returns the output, metadata, and a boolean indicating if storage is allowed or not. + /// + /// If the protocol is not recognized, it defaults to `IdentityPostProcessor`. pub async fn post_process(output: String, protocol: &str) -> Result<(Bytes, Bytes, bool)> { match protocol.split('/').next().unwrap_or_default() { SwanPurchasePostProcessor::PROTOCOL => { @@ -136,27 +145,6 @@ impl Request { _ => IdentityPostProcessor.post_process(output), } } - - /// Parses a given bytes input to a string, and if it is a storage key identifier it automatically - /// downloads the data from Arweave. - pub async fn parse_downloadable(input_bytes: &Bytes) -> Result { - // first, convert to string - let mut input_string = bytes_to_string(input_bytes)?; - - // then, check storage - if Arweave::is_key(input_string.clone()) { - // if its a txid, we download the data and parse it again - let input_bytes_from_arweave = Arweave::default() - .get(input_string) - .await - .wrap_err("could not download from Arweave")?; - - // convert the input to string - input_string = bytes_to_string(&input_bytes_from_arweave)?; - } - - Ok(input_string) - } } #[cfg(test)] @@ -167,7 +155,7 @@ mod tests { // only implemented for testing purposes // because `Workflow` does not implement `PartialEq` - impl PartialEq for Request { + impl PartialEq for GenerationRequest { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::ChatHistory(a), Self::ChatHistory(b)) => { @@ -183,8 +171,11 @@ mod tests { #[tokio::test] async fn test_parse_request_string() { let request_str = "foobar"; - let entry = Request::try_parse_bytes(&request_str.as_bytes().into()).await; - assert_eq!(entry.unwrap(), Request::String(request_str.into())); + let entry = GenerationRequest::try_parse_bytes(&request_str.as_bytes().into()).await; + assert_eq!( + entry.unwrap(), + GenerationRequest::String(request_str.into()) + ); } #[tokio::test] @@ -194,17 +185,23 @@ mod tests { let arweave_key = "660e826587f15c25989c2b8a1299d90987f2ee0862b75fefe3e0427b9de25ae0"; let expected_str = "\"Hello, Arweave!\""; - let entry = Request::try_parse_bytes(&arweave_key.as_bytes().into()).await; - assert_eq!(entry.unwrap(), Request::String(expected_str.into())); + let entry = GenerationRequest::try_parse_bytes(&arweave_key.as_bytes().into()).await; + assert_eq!( + entry.unwrap(), + GenerationRequest::String(expected_str.into()) + ); } #[tokio::test] async fn test_parse_request_workflow() { - let workflow_str = include_str!("../presets/generation.json"); + let workflow_str = include_str!("presets/generation.json"); let expected_workflow = serde_json::from_str::(&workflow_str).unwrap(); - let entry = Request::try_parse_bytes(&workflow_str.as_bytes().into()).await; - assert_eq!(entry.unwrap(), Request::Workflow(expected_workflow)); + let entry = GenerationRequest::try_parse_bytes(&workflow_str.as_bytes().into()).await; + assert_eq!( + entry.unwrap(), + GenerationRequest::Workflow(expected_workflow) + ); } #[tokio::test] @@ -214,15 +211,15 @@ mod tests { content: "foobar".to_string(), }; let request_bytes = serde_json::to_vec(&request).unwrap(); - let entry = Request::try_parse_bytes(&request_bytes.into()).await; - assert_eq!(entry.unwrap(), Request::ChatHistory(request)); + let entry = GenerationRequest::try_parse_bytes(&request_bytes.into()).await; + assert_eq!(entry.unwrap(), GenerationRequest::ChatHistory(request)); } #[tokio::test] #[ignore = "run this manually"] async fn test_ollama_generation() { dotenvy::dotenv().unwrap(); - let mut request = Request::String("What is the result of 2 + 2?".to_string()); + let mut request = GenerationRequest::String("What is the result of 2 + 2?".to_string()); let output = request.execute(Model::Llama3_1_8B, None).await.unwrap(); println!("Output:\n{}", output); @@ -233,7 +230,7 @@ mod tests { #[ignore = "run this manually"] async fn test_openai_generation() { dotenvy::dotenv().unwrap(); - let mut request = Request::String("What is the result of 2 + 2?".to_string()); + let mut request = GenerationRequest::String("What is the result of 2 + 2?".to_string()); let output = request.execute(Model::GPT4Turbo, None).await.unwrap(); println!("Output:\n{}", output); @@ -249,7 +246,7 @@ mod tests { content: "What is 2+2?".to_string(), }; let request_bytes = serde_json::to_vec(&request).unwrap(); - let mut request = Request::try_parse_bytes(&request_bytes.into()) + let mut request = GenerationRequest::try_parse_bytes(&request_bytes.into()) .await .unwrap(); let output = request.execute(Model::GPT4Turbo, None).await.unwrap(); @@ -263,8 +260,10 @@ mod tests { // task 21402 input // 0x30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463 let input_bytes = Bytes::from_hex("30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463").unwrap(); - let workflow = Request::try_parse_bytes(&input_bytes).await.unwrap(); - if let Request::Workflow(_) = workflow { + let workflow = GenerationRequest::try_parse_bytes(&input_bytes) + .await + .unwrap(); + if let GenerationRequest::Workflow(_) = workflow { /* do nothing */ } else { panic!("Expected workflow, got something else"); diff --git a/src/compute/workflows/mod.rs b/src/compute/workflows/mod.rs index 9a6fd04..120ef24 100644 --- a/src/compute/workflows/mod.rs +++ b/src/compute/workflows/mod.rs @@ -2,5 +2,11 @@ mod postprocess; mod presets; -mod requests; -pub use requests::Request; +mod generation; +pub use generation::GenerationRequest; + +mod validation; +pub use validation::ValidationRequest; + +mod common; +pub use common::*; diff --git a/src/compute/workflows/postprocess/swan.rs b/src/compute/workflows/postprocess/swan.rs index c4a356a..8bb98e6 100644 --- a/src/compute/workflows/postprocess/swan.rs +++ b/src/compute/workflows/postprocess/swan.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use super::PostProcess; -/// Swan post-processor that seeks for lines between `` and ``. +/// Swan post-processor that seeks for lines between `` and ``. /// and returns the intermediate strings as an array of strings. /// /// The original input is kept as metadata. @@ -37,7 +37,7 @@ impl PostProcess for SwanPurchasePostProcessor { let mut shopping_list_lines = Vec::new(); for line in input.lines() { if line.contains(self.start_marker) { - // if we see the buy_list start marker, we can start collecting lines + // if we see the shop_list start marker, we can start collecting lines collecting = true; } else if line.contains(self.end_marker) { // if we see the buy list end marker, we can stop collecting lines @@ -64,7 +64,10 @@ impl PostProcess for SwanPurchasePostProcessor { #[cfg(test)] mod tests { - use alloy::{hex::FromHex, primitives::Address}; + use alloy::{ + hex::FromHex, + primitives::{address, Address}, + }; use super::*; @@ -73,17 +76,17 @@ mod tests { const INPUT: &str = r#" some blabla here and there - + 0x4200000000000000000000000000000000000001 0x4200000000000000000000000000000000000002 0x4200000000000000000000000000000000000003 0x4200000000000000000000000000000000000004 - + some more blabla here "#; - let post_processor = SwanPurchasePostProcessor::new("", ""); + let post_processor = SwanPurchasePostProcessor::new("", ""); let (output, metadata, _) = post_processor.post_process(INPUT.to_string()).unwrap(); assert_eq!( @@ -122,9 +125,14 @@ some more blabla here let post_processor = SwanPurchasePostProcessor::new("", ""); let (output, _, _) = post_processor.post_process(INPUT.to_string()).unwrap(); - println!("{}", output); - let addresses = >::abi_decode(&output, true).unwrap(); - assert_eq!(addresses.len(), 5, "must have listed addresses"); + let expected_addresses = vec![ + address!("36f55f830D6E628a78Fcb70F73f9D005BaF88eE3"), + address!("Ad75C9358799e830F0c23a4BB28dF4D2cCCc8846"), + address!("26F5B12b67D5F006826824A73F58b88D6bdAA74B"), + address!("671527de058BaD60C6151cA29d501C87439bCF62"), + address!("66FC9dC1De3db773891753CD257359A26e876305"), + ]; + assert_eq!(addresses, expected_addresses, "must have listed addresses"); } } diff --git a/src/compute/workflows/presets/mod.rs b/src/compute/workflows/presets.rs similarity index 68% rename from src/compute/workflows/presets/mod.rs rename to src/compute/workflows/presets.rs index d6675d6..8a8aae1 100644 --- a/src/compute/workflows/presets/mod.rs +++ b/src/compute/workflows/presets.rs @@ -3,17 +3,18 @@ use lazy_static::lazy_static; lazy_static! { pub static ref GENERATION_WORKFLOW: Workflow = - serde_json::from_str(include_str!("generation.json")) + serde_json::from_str(include_str!("presets/generation.json")) .expect("could not parse generation workflow"); } +// const ee: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "aaa")); + pub fn get_chat_workflow() -> Workflow { - serde_json::from_str(include_str!("chat.json")).expect("could not parse chat workflow") + serde_json::from_str(include_str!("presets/chat.json")).expect("could not parse chat workflow") } -#[allow(unused)] pub fn get_validation_workflow() -> Workflow { - serde_json::from_str(include_str!("validation.json")) + serde_json::from_str(include_str!("presets/validation.json")) .expect("could not parse validation workflow") } diff --git a/src/compute/workflows/presets/chat.json b/src/compute/workflows/presets/chat.json index dfab9ed..f589d8a 100644 --- a/src/compute/workflows/presets/chat.json +++ b/src/compute/workflows/presets/chat.json @@ -6,19 +6,15 @@ "max_time": 50, "tools": [""] }, - "external_memory": { - "context": [""], - "question": [""], - "answer": [""] - }, + "external_memory": {}, "tasks": [ { "id": "A", "name": "Generate with history", "description": "Expects an array of messages for generation", + "operator": "generation", "messages": [], "inputs": [], - "operator": "generation", "outputs": [ { "type": "write", @@ -31,9 +27,9 @@ "id": "__end", "name": "end", "description": "End of the task", + "operator": "end", "messages": [{ "role": "user", "content": "End of the task" }], "inputs": [], - "operator": "end", "outputs": [] } ], diff --git a/src/compute/workflows/presets/generation.json b/src/compute/workflows/presets/generation.json index 31cb6f4..1e7d008 100644 --- a/src/compute/workflows/presets/generation.json +++ b/src/compute/workflows/presets/generation.json @@ -6,16 +6,13 @@ "max_time": 50, "tools": [""] }, - "external_memory": { - "context": [""], - "question": [""], - "answer": [""] - }, + "external_memory": {}, "tasks": [ { "id": "A", "name": "Generate", "description": "Executes a simple generation request", + "operator": "generation", "messages": [ { "role": "user", @@ -32,7 +29,7 @@ "required": true } ], - "operator": "generation", + "outputs": [ { "type": "write", diff --git a/src/compute/workflows/presets/validation.json b/src/compute/workflows/presets/validation.json index 3a99e78..d4a54ba 100644 --- a/src/compute/workflows/presets/validation.json +++ b/src/compute/workflows/presets/validation.json @@ -14,6 +14,7 @@ "id": "evaluate", "name": "Task", "description": "Task Description", + "operator": "generation", "messages": [ { "role": "user", @@ -39,7 +40,6 @@ "required": true } ], - "operator": "generation", "outputs": [ { "type": "write", diff --git a/src/compute/workflows/validation.rs b/src/compute/workflows/validation.rs new file mode 100644 index 0000000..0476a56 --- /dev/null +++ b/src/compute/workflows/validation.rs @@ -0,0 +1,65 @@ +use alloy::primitives::{Bytes, U256}; +use dkn_workflows::{Entry, Executor, MessageInput, Model, ProgramMemory, Workflow}; +use eyre::{eyre, Context, Result}; + +use super::parse_downloadable; +use crate::DriaOracle; + +/// An oracle validation request. +#[derive(Debug)] +pub struct ValidationRequest { + task_id: U256, + num_generations: usize, +} + +impl ValidationRequest { + /// Executes a request using the given model, and optionally a node. + /// Returns the raw string output. + pub async fn retrieve_generation_metadatas( + &mut self, + node: &DriaOracle, + ) -> Result> { + let responses = node + .get_task_responses(self.task_id.clone()) + .await + .wrap_err("could not get generation")?; + + // parse metadata from all responses + let mut metadatas = Vec::new(); + for response in responses { + let metadata_str = parse_downloadable(&response.metadata).await?; + metadatas.push(metadata_str); + } + + Ok(metadatas) + } + + /// Executes a validation request using the given model. + pub async fn execute(&mut self, model: Model) -> Result { + log::debug!("Executing validation request with: {}", model); + let mut memory = ProgramMemory::new(); + let executor = Executor::new(model); + + // TODO: !!! + + Ok(Default::default()) + } +} + +#[cfg(test)] +mod tests { + use alloy::hex::FromHex; + + use super::*; + + #[tokio::test] + async fn test_validation() { + let input = "What is 2 + 2"; + let generations = [ + "2 + 2 is 4.", + "2 + 2 is 889992.", + "Bonito applebum", + "2 + 2 is 4 because apples are green.", + ]; + } +} diff --git a/tests/generation_test.rs b/tests/generation_test.rs new file mode 100644 index 0000000..40454ae --- /dev/null +++ b/tests/generation_test.rs @@ -0,0 +1,7 @@ +use eyre::Result; + +#[tokio::test] +#[ignore = "requires OpenAI API key"] +async fn test_generation_request() -> Result<()> { + +} From a7d1a2cdaa40727ce1a673a13fd6443a194cc21c Mon Sep 17 00:00:00 2001 From: erhant Date: Tue, 10 Dec 2024 16:19:00 +0300 Subject: [PATCH 02/14] added validation logic --- src/compute/handlers/generation.rs | 7 +- src/compute/handlers/mod.rs | 2 - src/compute/handlers/validation.rs | 51 +++++---- src/compute/workflows/common.rs | 2 +- .../{generation.rs => generation/execute.rs} | 67 ++++------- src/compute/workflows/generation/mod.rs | 5 + .../{ => generation}/postprocess/identity.rs | 0 .../{ => generation}/postprocess/mod.rs | 0 .../{ => generation}/postprocess/swan.rs | 0 src/compute/workflows/generation/workflow.rs | 71 ++++++++++++ src/compute/workflows/mod.rs | 8 +- src/compute/workflows/presets.rs | 36 ------ src/compute/workflows/presets/chat.json | 48 -------- src/compute/workflows/presets/generation.json | 63 ----------- src/compute/workflows/presets/validation.json | 79 ------------- src/compute/workflows/validation.rs | 65 ----------- src/compute/workflows/validation/execute.rs | 106 ++++++++++++++++++ src/compute/workflows/validation/mod.rs | 2 + src/compute/workflows/validation/workflow.rs | 104 +++++++++++++++++ src/data/arweave.rs | 4 +- src/data/mod.rs | 2 +- src/data/traits.rs | 2 +- tests/generation_test.rs | 7 -- 23 files changed, 356 insertions(+), 375 deletions(-) rename src/compute/workflows/{generation.rs => generation/execute.rs} (88%) create mode 100644 src/compute/workflows/generation/mod.rs rename src/compute/workflows/{ => generation}/postprocess/identity.rs (100%) rename src/compute/workflows/{ => generation}/postprocess/mod.rs (100%) rename src/compute/workflows/{ => generation}/postprocess/swan.rs (100%) create mode 100644 src/compute/workflows/generation/workflow.rs delete mode 100644 src/compute/workflows/presets.rs delete mode 100644 src/compute/workflows/presets/chat.json delete mode 100644 src/compute/workflows/presets/generation.json delete mode 100644 src/compute/workflows/presets/validation.json delete mode 100644 src/compute/workflows/validation.rs create mode 100644 src/compute/workflows/validation/execute.rs create mode 100644 src/compute/workflows/validation/mod.rs create mode 100644 src/compute/workflows/validation/workflow.rs delete mode 100644 tests/generation_test.rs diff --git a/src/compute/handlers/generation.rs b/src/compute/handlers/generation.rs index 9c5dd92..7c51238 100644 --- a/src/compute/handlers/generation.rs +++ b/src/compute/handlers/generation.rs @@ -61,16 +61,19 @@ pub async fn handle_generation( "Post-processing the output for protocol: {}", protocol_string ); - let (output, metadata, use_storage) = GenerationRequest::post_process(output, &protocol_string).await?; + let (output, metadata, use_storage) = + GenerationRequest::post_process(output, &protocol_string).await?; // uploading to storage - log::debug!("Uploading output to storage"); let arweave = Arweave::new_from_env()?; let output = if use_storage { + log::debug!("Uploading output to storage"); arweave.put_if_large(output).await? } else { + log::debug!("Not uploading output to storage"); output }; + log::debug!("Uploading metadata to storage"); let metadata = arweave.put_if_large(metadata).await?; // mine nonce diff --git a/src/compute/handlers/mod.rs b/src/compute/handlers/mod.rs index f44a02c..0f1b356 100644 --- a/src/compute/handlers/mod.rs +++ b/src/compute/handlers/mod.rs @@ -16,8 +16,6 @@ use validation::*; /// /// - Generation tasks are forwarded to `handle_generation` /// - Validation tasks are forwarded to `handle_validation` -/// -/// pub async fn handle_request( node: &DriaOracle, kinds: &[OracleKind], diff --git a/src/compute/handlers/validation.rs b/src/compute/handlers/validation.rs index eb887d1..aa5fede 100644 --- a/src/compute/handlers/validation.rs +++ b/src/compute/handlers/validation.rs @@ -1,9 +1,10 @@ -use crate::{mine_nonce, DriaOracle}; -use alloy::{ - primitives::{utils::parse_ether, Bytes, U256}, - rpc::types::TransactionReceipt, +use crate::{ + compute::{execute::validate_generations, parse_downloadable}, + data::Arweave, + mine_nonce, DriaOracle, }; -use dkn_workflows::DriaWorkflowsConfig; +use alloy::{primitives::U256, rpc::types::TransactionReceipt}; +use dkn_workflows::{DriaWorkflowsConfig, Model}; use eyre::{eyre, Context, Result}; /// Handles a validation request. @@ -33,29 +34,41 @@ pub async fn handle_validation( return Err(eyre!("Already validated {}", task_id)); } - // fetch request and generations + // fetch the request from contract log::debug!("Fetching the task request"); let request = node .get_task_request(task_id) .await .wrap_err("could not get task request")?; - // fetch each generation response & score it - log::debug!("Starting validations"); - let mut scores = Vec::new(); - for i in 0..request.parameters.numGenerations { - let score = parse_ether("1.0").unwrap(); - scores.push(score); + // fetch each generation response & download its metadata + log::debug!("Fetching response messages"); + let responses = node + .get_task_responses(task_id) + .await + .wrap_err("could not get task responses")?; + let mut generations = Vec::new(); + for response in responses { + let metadata_str = parse_downloadable(&response.metadata).await?; + generations.push(metadata_str); } + let input = parse_downloadable(&request.input).await?; - // FIXME: will add validation prompt here - - let scores = (0..request.parameters.numGenerations) - .map(|_| parse_ether("1.0").unwrap()) + // validate each response + // TODO: decide model w.r.t config + log::debug!("Computing validation scores"); + let validations = validate_generations(input, generations, Model::GPT4o).await?; + let scores = validations + .iter() + .map(|v| v.final_score_as_solidity_type()) .collect::>(); - // FIXME: metadata is empty for now, as dummy data - // FIXME: can add Arweave trick for metadata here - let metadata = Bytes::default(); + let metadata = + serde_json::to_string(&validations).wrap_err("could not serialize validations")?; + + // uploading to storage + log::debug!("Uploading metadata to storage"); + let arweave = Arweave::new_from_env()?; + let metadata = arweave.put_if_large(metadata.into()).await?; // mine nonce log::debug!("Mining nonce for task"); diff --git a/src/compute/workflows/common.rs b/src/compute/workflows/common.rs index 03e9c72..1978569 100644 --- a/src/compute/workflows/common.rs +++ b/src/compute/workflows/common.rs @@ -3,7 +3,7 @@ use eyre::{Context, Result}; use crate::{ bytes_to_string, - data::{Arweave, OracleExternalData}, + data::{Arweave, OracleExternalStorage}, }; /// Parses a given bytes input to a string, and if it is a storage key identifier it automatically diff --git a/src/compute/workflows/generation.rs b/src/compute/workflows/generation/execute.rs similarity index 88% rename from src/compute/workflows/generation.rs rename to src/compute/workflows/generation/execute.rs index f93a294..99dd024 100644 --- a/src/compute/workflows/generation.rs +++ b/src/compute/workflows/generation/execute.rs @@ -1,8 +1,11 @@ use alloy::primitives::{Bytes, U256}; -use dkn_workflows::{Entry, Executor, MessageInput, Model, ProgramMemory, Workflow}; +use dkn_workflows::{Executor, MessageInput, Model, ProgramMemory, Workflow}; use eyre::{eyre, Context, Result}; -use super::{postprocess::*, presets::*}; +use super::{ + postprocess::{self, *}, + workflow::*, +}; use crate::{compute::parse_downloadable, DriaOracle}; /// A request with chat history. @@ -73,9 +76,9 @@ impl GenerationRequest { // string requests are used with the generation workflow with a given prompt Self::String(input) => { - let entry = Entry::String(input.clone()); + let workflow = make_generation_workflow(input.clone())?; executor - .execute(Some(&entry), &GENERATION_WORKFLOW, &mut memory) + .execute(None, &workflow, &mut memory) .await .wrap_err("could not execute worfklow for string input") } @@ -101,18 +104,8 @@ impl GenerationRequest { return Err(eyre!("node is required for chat history")); }; - // append user input to chat history - history.push(MessageInput { - role: "user".to_string(), - content: chat_request.content.clone(), - }); - // prepare the workflow with chat history - let mut workflow = get_chat_workflow(); - let task = workflow.get_tasks_by_id_mut("A").unwrap(); - task.messages = history.clone(); - - // call workflow + let workflow = make_chat_workflow(history.clone(), chat_request.content.clone())?; let output = executor .execute(None, &workflow, &mut memory) .await @@ -142,7 +135,7 @@ impl GenerationRequest { SwanPurchasePostProcessor::PROTOCOL => { SwanPurchasePostProcessor::new("", "").post_process(output) } - _ => IdentityPostProcessor.post_process(output), + _ => postprocess::IdentityPostProcessor.post_process(output), } } } @@ -192,18 +185,6 @@ mod tests { ); } - #[tokio::test] - async fn test_parse_request_workflow() { - let workflow_str = include_str!("presets/generation.json"); - let expected_workflow = serde_json::from_str::(&workflow_str).unwrap(); - - let entry = GenerationRequest::try_parse_bytes(&workflow_str.as_bytes().into()).await; - assert_eq!( - entry.unwrap(), - GenerationRequest::Workflow(expected_workflow) - ); - } - #[tokio::test] async fn test_parse_request_chat() { let request = ChatHistoryRequest { @@ -215,6 +196,21 @@ mod tests { assert_eq!(entry.unwrap(), GenerationRequest::ChatHistory(request)); } + #[tokio::test] + async fn test_parse_request_workflow() { + // task 21402 input + // 0x30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463 + let input_bytes = Bytes::from_hex("30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463").unwrap(); + let workflow = GenerationRequest::try_parse_bytes(&input_bytes) + .await + .unwrap(); + if let GenerationRequest::Workflow(_) = workflow { + /* do nothing */ + } else { + panic!("Expected workflow, got something else"); + } + } + #[tokio::test] #[ignore = "run this manually"] async fn test_ollama_generation() { @@ -254,19 +250,4 @@ mod tests { println!("Output:\n{}", output); assert!(output.contains('4')); } - - #[tokio::test] - async fn test_arweave_workflow_parser() { - // task 21402 input - // 0x30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463 - let input_bytes = Bytes::from_hex("30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463").unwrap(); - let workflow = GenerationRequest::try_parse_bytes(&input_bytes) - .await - .unwrap(); - if let GenerationRequest::Workflow(_) = workflow { - /* do nothing */ - } else { - panic!("Expected workflow, got something else"); - } - } } diff --git a/src/compute/workflows/generation/mod.rs b/src/compute/workflows/generation/mod.rs new file mode 100644 index 0000000..10bbb40 --- /dev/null +++ b/src/compute/workflows/generation/mod.rs @@ -0,0 +1,5 @@ +mod execute; +pub use execute::GenerationRequest; + +pub mod postprocess; +pub mod workflow; diff --git a/src/compute/workflows/postprocess/identity.rs b/src/compute/workflows/generation/postprocess/identity.rs similarity index 100% rename from src/compute/workflows/postprocess/identity.rs rename to src/compute/workflows/generation/postprocess/identity.rs diff --git a/src/compute/workflows/postprocess/mod.rs b/src/compute/workflows/generation/postprocess/mod.rs similarity index 100% rename from src/compute/workflows/postprocess/mod.rs rename to src/compute/workflows/generation/postprocess/mod.rs diff --git a/src/compute/workflows/postprocess/swan.rs b/src/compute/workflows/generation/postprocess/swan.rs similarity index 100% rename from src/compute/workflows/postprocess/swan.rs rename to src/compute/workflows/generation/postprocess/swan.rs diff --git a/src/compute/workflows/generation/workflow.rs b/src/compute/workflows/generation/workflow.rs new file mode 100644 index 0000000..d14ec9b --- /dev/null +++ b/src/compute/workflows/generation/workflow.rs @@ -0,0 +1,71 @@ +use dkn_workflows::{MessageInput, Workflow}; +use serde_json::json; + +/// Creates a generation workflow with the given input. +/// +/// It is an alias for `make_chat_workflow` with a single message alone. +pub fn make_generation_workflow(input: String) -> Result { + make_chat_workflow(Vec::new(), input) +} + +/// Creates a chat workflow with the given input. +/// +/// `messages` is the existing message history, which will be used as context for the `input` message. +pub fn make_chat_workflow( + mut messages: Vec, + input: String, +) -> Result { + // add the new input to the message history as a user message + messages.push(MessageInput { + role: "user".to_string(), + content: input, + }); + + let workflow = json!({ + "config": { + "max_steps": 10, + "max_time": 50, + "tools": [""] + }, + "tasks": [ + { + "id": "A", + "name": "Generate with history", + "description": "Expects an array of messages for generation", + "operator": "generation", + "messages": messages, + "inputs": [], + "outputs": [ + { + "type": "write", + "key": "result", + "value": "__result" + } + ] + }, + { + "id": "__end", + "name": "end", + "description": "End of the task", + "operator": "end", + "messages": [{ "role": "user", "content": "End of the task" }], + "inputs": [], + "outputs": [] + } + ], + "steps": [ + { + "source": "A", + "target": "__end" + } + ], + "return_value": { + "input": { + "type": "read", + "key": "result" + } + } + }); + + serde_json::from_value(workflow) +} diff --git a/src/compute/workflows/mod.rs b/src/compute/workflows/mod.rs index 120ef24..a9ae71d 100644 --- a/src/compute/workflows/mod.rs +++ b/src/compute/workflows/mod.rs @@ -1,12 +1,8 @@ -mod postprocess; - -mod presets; - mod generation; -pub use generation::GenerationRequest; +pub use generation::*; mod validation; -pub use validation::ValidationRequest; +pub use validation::*; mod common; pub use common::*; diff --git a/src/compute/workflows/presets.rs b/src/compute/workflows/presets.rs deleted file mode 100644 index 8a8aae1..0000000 --- a/src/compute/workflows/presets.rs +++ /dev/null @@ -1,36 +0,0 @@ -use dkn_workflows::Workflow; -use lazy_static::lazy_static; - -lazy_static! { - pub static ref GENERATION_WORKFLOW: Workflow = - serde_json::from_str(include_str!("presets/generation.json")) - .expect("could not parse generation workflow"); -} - -// const ee: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "aaa")); - -pub fn get_chat_workflow() -> Workflow { - serde_json::from_str(include_str!("presets/chat.json")).expect("could not parse chat workflow") -} - -pub fn get_validation_workflow() -> Workflow { - serde_json::from_str(include_str!("presets/validation.json")) - .expect("could not parse validation workflow") -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_search_workflow() { - // should not give error if parsing succeeds - let _ = get_chat_workflow(); - } - - #[test] - fn test_validation_workflow() { - // should not give error if parsing succeeds - let _ = get_validation_workflow(); - } -} diff --git a/src/compute/workflows/presets/chat.json b/src/compute/workflows/presets/chat.json deleted file mode 100644 index f589d8a..0000000 --- a/src/compute/workflows/presets/chat.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "LLM generation", - "description": "Directly generate text with input", - "config": { - "max_steps": 10, - "max_time": 50, - "tools": [""] - }, - "external_memory": {}, - "tasks": [ - { - "id": "A", - "name": "Generate with history", - "description": "Expects an array of messages for generation", - "operator": "generation", - "messages": [], - "inputs": [], - "outputs": [ - { - "type": "write", - "key": "result", - "value": "__result" - } - ] - }, - { - "id": "__end", - "name": "end", - "description": "End of the task", - "operator": "end", - "messages": [{ "role": "user", "content": "End of the task" }], - "inputs": [], - "outputs": [] - } - ], - "steps": [ - { - "source": "A", - "target": "__end" - } - ], - "return_value": { - "input": { - "type": "read", - "key": "result" - } - } -} diff --git a/src/compute/workflows/presets/generation.json b/src/compute/workflows/presets/generation.json deleted file mode 100644 index 1e7d008..0000000 --- a/src/compute/workflows/presets/generation.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "LLM generation", - "description": "Directly generate text with input", - "config": { - "max_steps": 10, - "max_time": 50, - "tools": [""] - }, - "external_memory": {}, - "tasks": [ - { - "id": "A", - "name": "Generate", - "description": "Executes a simple generation request", - "operator": "generation", - "messages": [ - { - "role": "user", - "content": "{{text}}" - } - ], - "inputs": [ - { - "name": "text", - "value": { - "type": "input", - "key": "" - }, - "required": true - } - ], - - "outputs": [ - { - "type": "write", - "key": "result", - "value": "__result" - } - ] - }, - { - "id": "__end", - "name": "end", - "description": "End of the task", - "messages": [{ "role": "user", "content": "End of the task" }], - "inputs": [], - "operator": "end", - "outputs": [] - } - ], - "steps": [ - { - "source": "A", - "target": "__end" - } - ], - "return_value": { - "input": { - "type": "read", - "key": "result" - } - } -} diff --git a/src/compute/workflows/presets/validation.json b/src/compute/workflows/presets/validation.json deleted file mode 100644 index d4a54ba..0000000 --- a/src/compute/workflows/presets/validation.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "config": { - "max_steps": 50, - "max_time": 200, - "tools": ["ALL"], - "max_tokens": 1000 - }, - "external_memory": { - "instruction": "What is 2+2?", - "generations": ["It's 4."] - }, - "tasks": [ - { - "id": "evaluate", - "name": "Task", - "description": "Task Description", - "operator": "generation", - "messages": [ - { - "role": "user", - "content": "\n# Instruction Following Assessment\n\n \n\nEvaluate alignment between output and intent. Assess understanding of task goal and restrictions.\n\n \n\n**Instruction Components**: Task Goal (intended outcome), Restrictions (text styles, formats, or designated methods, etc).\n\n \n\n**Scoring**: Rate outputs 1 to 5:\n\n1. **Irrelevant**: No alignment.\n\n2. **Partial Focus**: Addresses one aspect poorly.\n\n3. **Partial Compliance**:\n\n- (1) Meets goal or restrictions, neglecting other.\n\n- (2) Acknowledges both but slight deviations.\n\n4. **Almost There**: Near alignment, minor deviations.\n\n5. **Comprehensive Compliance**: Fully aligns, meets all requirements.\n\n## Format:\n\n### Input\n\nInstruction: Write a compelling product description \n\nTexts:\n\n The sleek smartphone features a 6.1\" display\n\n Buy this phone it has good screen\n\n Experience crystal-clear visuals on the stunning 6.1\" OLED display\n\n### Output\n\n### Output for Text 1\n\n{\n \"score\": 3,\n \"rationale\": \"Basic description with specs but lacks compelling language.\"\n}\n\n### Output for Text 2\n\n{\n \"score\": 1,\n \"rationale\": \"Too informal and vague. Missing specific details.\"\n}\n\n### Output for Text 3\n\n{\n \"score\": 5,\n \"rationale\": \"Uses engaging language. Includes specific features. Creates desire.\"\n}\n\n---\n \n## Annotation\n\n### Input\n\nInstruction: {{instruction}}\n\nTexts:\n\n{{generations}}\n\n### Output" - } - ], - "schema": "{\"properties\": {\"instruction_following\": {\"description\": \"The score for the instruction following ability.\", \"gte\": 1, \"lte\": 5, \"title\": \"Instruction Following\", \"type\": \"integer\"}, \"truthfulness\": {\"description\": \"The score for the truthfulness of the response.\", \"gte\": 1, \"lte\": 5, \"title\": \"Truthfulness\", \"type\": \"integer\"}, \"helpfulness\": {\"description\": \"The score for the helpfulness of the response.\", \"gte\": 1, \"lte\": 5, \"title\": \"Helpfulness\", \"type\": \"integer\"}, \"score\": {\"description\": \"The overall score of the evaluation.\", \"gte\": 1, \"lte\": 5, \"title\": \"Score\", \"type\": \"integer\"}, \"rationale\": {\"description\": \"The rationale of the evaluation.\", \"title\": \"Rationale\", \"type\": \"string\"}}, \"required\": [\"instruction_following\", \"truthfulness\", \"helpfulness\", \"score\", \"rationale\"], \"title\": \"Evaluation\", \"type\": \"object\", \"additionalProperties\": false}", - "inputs": [ - { - "name": "instruction", - "value": { - "type": "read", - "key": "instruction" - }, - "required": true - }, - { - "name": "generations", - "value": { - "type": "get_all", - "key": "generations" - }, - "required": true - } - ], - "outputs": [ - { - "type": "write", - "key": "search_result", - "value": "__result" - } - ] - }, - { - "id": "_end", - "name": "Task", - "description": "Task Description", - "messages": [ - { - "role": "user", - "content": "" - } - ], - "inputs": [], - "operator": "end", - "outputs": [] - } - ], - "steps": [ - { - "source": "evaluate", - "target": "_end" - } - ], - "return_value": { - "input": { - "type": "read", - "key": "search_result" - }, - "to_json": false - } -} diff --git a/src/compute/workflows/validation.rs b/src/compute/workflows/validation.rs deleted file mode 100644 index 0476a56..0000000 --- a/src/compute/workflows/validation.rs +++ /dev/null @@ -1,65 +0,0 @@ -use alloy::primitives::{Bytes, U256}; -use dkn_workflows::{Entry, Executor, MessageInput, Model, ProgramMemory, Workflow}; -use eyre::{eyre, Context, Result}; - -use super::parse_downloadable; -use crate::DriaOracle; - -/// An oracle validation request. -#[derive(Debug)] -pub struct ValidationRequest { - task_id: U256, - num_generations: usize, -} - -impl ValidationRequest { - /// Executes a request using the given model, and optionally a node. - /// Returns the raw string output. - pub async fn retrieve_generation_metadatas( - &mut self, - node: &DriaOracle, - ) -> Result> { - let responses = node - .get_task_responses(self.task_id.clone()) - .await - .wrap_err("could not get generation")?; - - // parse metadata from all responses - let mut metadatas = Vec::new(); - for response in responses { - let metadata_str = parse_downloadable(&response.metadata).await?; - metadatas.push(metadata_str); - } - - Ok(metadatas) - } - - /// Executes a validation request using the given model. - pub async fn execute(&mut self, model: Model) -> Result { - log::debug!("Executing validation request with: {}", model); - let mut memory = ProgramMemory::new(); - let executor = Executor::new(model); - - // TODO: !!! - - Ok(Default::default()) - } -} - -#[cfg(test)] -mod tests { - use alloy::hex::FromHex; - - use super::*; - - #[tokio::test] - async fn test_validation() { - let input = "What is 2 + 2"; - let generations = [ - "2 + 2 is 4.", - "2 + 2 is 889992.", - "Bonito applebum", - "2 + 2 is 4 because apples are green.", - ]; - } -} diff --git a/src/compute/workflows/validation/execute.rs b/src/compute/workflows/validation/execute.rs new file mode 100644 index 0000000..2857358 --- /dev/null +++ b/src/compute/workflows/validation/execute.rs @@ -0,0 +1,106 @@ +use alloy::primitives::U256; +use dkn_workflows::{Executor, Model, ProgramMemory}; +use eyre::{Context, Result}; + +use super::workflow::make_validation_workflow; + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct ValidationResult { + /// How helpful the response is. + helpfulness: u8, + /// How closely the response follows the instruction. + instruction_following: u8, + /// The final score of the response, which we write to the contract. + final_score: u8, + /// The truthfulness of the response. + /// If the response is correct but it doesn't make sense w.r.t instruction, + /// this may still be correct. + truthfulness: u8, + /// The rationale for the scores reported. + rationale: String, +} + +impl ValidationResult { + /// Clamps the score to the range `[1, 5]` and scales it to the range `[1-255]`. + pub fn final_score_as_solidity_type(&self) -> U256 { + U256::from(match self.final_score.clamp(1, 5) { + 1 => 1, + 2 => 64, + 3 => 85, + 4 => 127, + 5 => 255, + _ => unreachable!(), + }) + } +} + +/// Executes a validation request using the given model. +pub async fn validate_generations( + instruction: String, + generations: Vec, + model: Model, +) -> Result> { + let workflow = make_validation_workflow(instruction, generations)?; + + log::debug!("Executing validation request with: {}", model); + let mut memory = ProgramMemory::new(); + let executor = Executor::new(model); + let result_str = executor.execute(None, &workflow, &mut memory).await?; + + // first parse as vec of string + // then parse each string as a ValidationResult + // FIXME: this is a workflows bug, can return a single parseable string instead of array of parsable strings later + let result: Vec = serde_json::from_str::>(&result_str) + .wrap_err("could not parse validation results")? + .into_iter() + .map(|s| serde_json::from_str::(&s)) + .collect::, _>>() + .wrap_err("could not parse validation results")?; + Ok(result) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + #[ignore = "requires OpenAI API key"] + async fn test_validation() { + dotenvy::dotenv().unwrap(); + + let instruction = "What is 2 + 2".to_string(); + let generations: Vec = [ + "2 + 2 is 4.", // correct + "2 + 2 is 889992.", // incorrect + "Bonito applebum", // completely irrelevant + "2 + 2 is 4 because apples are green.", // correct but irrational + "2 + 2 is not 5.", // correct but irrelevant + ] + .iter() + .map(|s| s.to_string()) + .collect(); + + let model = Model::GPT4oMini; + let results = validate_generations(instruction, generations.clone(), model) + .await + .unwrap(); + + assert_eq!( + results.len(), + generations.len(), + "expected same number of results" + ); + assert!( + results[0].final_score == 5, + "expected top score from correct response" + ); + assert!( + results[1].final_score == 1, + "expected minimum score from wrong response" + ); + assert!( + results[2].final_score == 1, + "expected minimum score from irrelevant response" + ); + } +} diff --git a/src/compute/workflows/validation/mod.rs b/src/compute/workflows/validation/mod.rs new file mode 100644 index 0000000..4dd676b --- /dev/null +++ b/src/compute/workflows/validation/mod.rs @@ -0,0 +1,2 @@ +pub mod execute; +pub mod workflow; diff --git a/src/compute/workflows/validation/workflow.rs b/src/compute/workflows/validation/workflow.rs new file mode 100644 index 0000000..611d62a --- /dev/null +++ b/src/compute/workflows/validation/workflow.rs @@ -0,0 +1,104 @@ +use dkn_workflows::Workflow; +use serde_json::json; + +pub fn make_validation_workflow( + instruction: String, + mut generations: Vec, +) -> Result { + // workflow processes the array in reverse order, so we reverse the input outside + // to get the correct order in results + generations.reverse(); + + let workflow = json!({ + "config": { + "max_steps": generations.len() + 5, // we need one step per generation, plus some leeway here + "max_time": generations.len() * 4 + 10, // we need at most 4 seconds per generation, plus some leeway here + "tools": [ + "ALL" + ], + "max_tokens": 1000 // max tokens do not need to change + }, + "external_memory": { + "instruction": instruction, + "generations": generations + }, + "tasks": [ + { + "id": "evaluate", + "name": "Task", + "description": "Task Description", + "messages": [ + { + "role": "user", + "content": "\n# Instruction Following Assessment\n\nEvaluate alignment between output and intent. Assess understanding of task goal and restrictions.\n\n**Instruction Components**: Task Goal (intended outcome), Restrictions (text styles, formats, or designated methods, etc).\n\n**Scoring**: Rate outputs 1 to 5:\n\n1. **Irrelevant**: No alignment.\n\n2. **Partial Focus**: Addresses one aspect poorly.\n\n3. **Partial Compliance**:\n\n- (1) Meets goal or restrictions, neglecting other.\n\n- (2) Acknowledges both but slight deviations.\n\n4. **Almost There**: Near alignment, minor deviations.\n\n5. **Comprehensive Compliance**: Fully aligns, meets all requirements.\n\n## Format:\n\n### Input\n\nInstruction: Write a compelling product description \n\nTexts:\n\n The sleek smartphone features a 6.1\" display\n\n Buy this phone it has good screen\n\n Experience crystal-clear visuals on the stunning 6.1\" OLED display\n\n### Output\n\n### Output for Text 1\n\n{\n \"score\": 3,\n \"rationale\": \"Basic description with specs but lacks compelling language.\"\n}\n\n### Output for Text 2\n\n{\n \"score\": 1,\n \"rationale\": \"Too informal and vague. Missing specific details.\"\n}\n\n### Output for Text 3\n\n{\n \"score\": 5,\n \"rationale\": \"Uses engaging language. Includes specific features. Creates desire.\"\n}\n\n---\n \n## Annotation\n\n### Input\n\nInstruction: {{instruction}}\n\nTexts:\n\n{{generations}}\n\n### Output" + } + ], + "schema": "{\"properties\": {\"instruction_following\": {\"description\": \"The score for the instruction following ability.\", \"gte\": 1, \"lte\": 5, \"title\": \"Instruction Following\", \"type\": \"integer\"}, \"truthfulness\": {\"description\": \"The score for the truthfulness of the response.\", \"gte\": 1, \"lte\": 5, \"title\": \"Truthfulness\", \"type\": \"integer\"}, \"helpfulness\": {\"description\": \"The score for the helpfulness of the response.\", \"gte\": 1, \"lte\": 5, \"title\": \"Helpfulness\", \"type\": \"integer\"}, \"final_score\": {\"description\": \"The overall score of the evaluation.\", \"gte\": 1, \"lte\": 5, \"title\": \"Final Score\", \"type\": \"integer\"}, \"rationale\": {\"description\": \"The rationale of the evaluation.\", \"title\": \"Rationale\", \"type\": \"string\"}}, \"required\": [\"instruction_following\", \"truthfulness\", \"helpfulness\", \"final_score\", \"rationale\"], \"title\": \"Evaluation\", \"type\": \"object\", \"additionalProperties\": false}", + "inputs": [ + { + "name": "instruction", + "value": { + "type": "read", + "key": "instruction" + }, + "required": true + }, + { + "name": "generations", + "value": { + "type": "pop", + "key": "generations" + }, + "required": true + } + ], + "operator": "generation", + "outputs": [ + { + "type": "push", + "key": "search_result", + "value": "__result" + } + ] + }, + { + "id": "_end", + "name": "Task", + "description": "Task Description", + "messages": [ + { + "role": "user", + "content": "" + } + ], + "inputs": [], + "operator": "end", + "outputs": [] + } + ], + "steps": [ + { + "source": "evaluate", + "target": "_end", + "condition": { + "input": { + "type": "size", + "key": "generations" + }, + "expected": "0", + "expression": "Equal", + "target_if_not": "evaluate" + } + } + ], + "return_value": { + "input": { + "type": "get_all", + "key": "search_result" + }, + "to_json": true + } + }); + + serde_json::from_value(workflow) +} diff --git a/src/data/arweave.rs b/src/data/arweave.rs index b8cef17..0ceeb84 100644 --- a/src/data/arweave.rs +++ b/src/data/arweave.rs @@ -1,4 +1,4 @@ -use super::traits::OracleExternalData; +use super::traits::OracleExternalStorage; use alloy::primitives::Bytes; use async_trait::async_trait; use base64::prelude::*; @@ -138,7 +138,7 @@ impl Default for Arweave { } #[async_trait(?Send)] -impl OracleExternalData for Arweave { +impl OracleExternalStorage for Arweave { type Key = String; type Value = Bytes; diff --git a/src/data/mod.rs b/src/data/mod.rs index fa61be7..9c4031e 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -2,4 +2,4 @@ mod arweave; pub use arweave::Arweave; mod traits; -pub use traits::OracleExternalData; +pub use traits::OracleExternalStorage; diff --git a/src/data/traits.rs b/src/data/traits.rs index 1690eb7..7b6cc12 100644 --- a/src/data/traits.rs +++ b/src/data/traits.rs @@ -10,7 +10,7 @@ use eyre::Result; /// /// Note that the `async_trait` has `?Send` specified, as by default it makes them `Send` but Arweave does not have it. #[async_trait(?Send)] -pub trait OracleExternalData { +pub trait OracleExternalStorage { type Key: Clone; type Value: Clone + Debug; diff --git a/tests/generation_test.rs b/tests/generation_test.rs deleted file mode 100644 index 40454ae..0000000 --- a/tests/generation_test.rs +++ /dev/null @@ -1,7 +0,0 @@ -use eyre::Result; - -#[tokio::test] -#[ignore = "requires OpenAI API key"] -async fn test_generation_request() -> Result<()> { - -} From 6546c0d6ee80ab44a66b023ddaee398d70ad4f46 Mon Sep 17 00:00:00 2001 From: erhant Date: Tue, 10 Dec 2024 17:24:19 +0300 Subject: [PATCH 03/14] slight folder structure and naming rfks --- src/compute/{handlers/mod.rs => handler.rs} | 7 ++--- src/compute/mod.rs | 6 ++-- src/compute/workflows/common.rs | 28 ------------------- src/compute/workflows/generation/execute.rs | 22 +++++++-------- .../generation/handler.rs} | 7 +++-- src/compute/workflows/generation/mod.rs | 7 ++++- src/compute/workflows/mod.rs | 9 ++---- src/compute/workflows/validation/execute.rs | 12 ++++++-- .../validation/handler.rs} | 13 ++++----- src/compute/workflows/validation/mod.rs | 8 +++++- src/lib.rs | 2 +- src/{data => storage}/arweave.rs | 27 ++++++++++++++++-- src/{data => storage}/mod.rs | 2 +- src/{data => storage}/traits.rs | 2 +- 14 files changed, 77 insertions(+), 75 deletions(-) rename src/compute/{handlers/mod.rs => handler.rs} (95%) delete mode 100644 src/compute/workflows/common.rs rename src/compute/{handlers/generation.rs => workflows/generation/handler.rs} (96%) rename src/compute/{handlers/validation.rs => workflows/validation/handler.rs} (90%) rename src/{data => storage}/arweave.rs (90%) rename src/{data => storage}/mod.rs (57%) rename src/{data => storage}/traits.rs (96%) diff --git a/src/compute/handlers/mod.rs b/src/compute/handler.rs similarity index 95% rename from src/compute/handlers/mod.rs rename to src/compute/handler.rs index 0f1b356..b99d665 100644 --- a/src/compute/handlers/mod.rs +++ b/src/compute/handler.rs @@ -6,11 +6,8 @@ use alloy::rpc::types::TransactionReceipt; use dkn_workflows::DriaWorkflowsConfig; use eyre::Result; -mod generation; -use generation::*; - -mod validation; -use validation::*; +use super::generation::handle_generation; +use super::validation::handle_validation; /// Handles a task request. /// diff --git a/src/compute/mod.rs b/src/compute/mod.rs index f7b0b43..e1295d6 100644 --- a/src/compute/mod.rs +++ b/src/compute/mod.rs @@ -1,8 +1,8 @@ -mod handlers; -pub use handlers::*; +mod handler; +pub use handler::handle_request; mod nonce; pub use nonce::mine_nonce; mod workflows; -pub use workflows::*; +pub use workflows::{generation, validation}; diff --git a/src/compute/workflows/common.rs b/src/compute/workflows/common.rs deleted file mode 100644 index 1978569..0000000 --- a/src/compute/workflows/common.rs +++ /dev/null @@ -1,28 +0,0 @@ -use alloy::primitives::Bytes; -use eyre::{Context, Result}; - -use crate::{ - bytes_to_string, - data::{Arweave, OracleExternalStorage}, -}; - -/// Parses a given bytes input to a string, and if it is a storage key identifier it automatically -/// downloads the data from Arweave. -pub async fn parse_downloadable(input_bytes: &Bytes) -> Result { - // first, convert to string - let mut input_string = bytes_to_string(input_bytes)?; - - // then, check storage - if Arweave::is_key(input_string.clone()) { - // if its a txid, we download the data and parse it again - let input_bytes_from_arweave = Arweave::default() - .get(input_string) - .await - .wrap_err("could not download from Arweave")?; - - // convert the input to string - input_string = bytes_to_string(&input_bytes_from_arweave)?; - } - - Ok(input_string) -} diff --git a/src/compute/workflows/generation/execute.rs b/src/compute/workflows/generation/execute.rs index 99dd024..3b67da4 100644 --- a/src/compute/workflows/generation/execute.rs +++ b/src/compute/workflows/generation/execute.rs @@ -1,12 +1,10 @@ +use crate::{storage::Arweave, DriaOracle}; use alloy::primitives::{Bytes, U256}; use dkn_workflows::{Executor, MessageInput, Model, ProgramMemory, Workflow}; use eyre::{eyre, Context, Result}; -use super::{ - postprocess::{self, *}, - workflow::*, -}; -use crate::{compute::parse_downloadable, DriaOracle}; +use super::postprocess::*; +use super::workflow::*; /// A request with chat history. #[derive(Debug, serde::Serialize, serde::Deserialize)] @@ -39,7 +37,7 @@ impl GenerationRequest { /// Given an input of byte-slice, parses it into a valid request type. pub async fn try_parse_bytes(input_bytes: &Bytes) -> Result { - let input_string = parse_downloadable(input_bytes).await?; + let input_string = Arweave::parse_downloadable(input_bytes).await?; log::debug!("Parsing input string: {}", input_string); Ok(Self::try_parse_string(input_string).await) } @@ -57,7 +55,7 @@ impl GenerationRequest { /// Executes a request using the given model, and optionally a node. /// Returns the raw string output. - pub async fn execute(&mut self, model: Model, node: Option<&DriaOracle>) -> Result { + pub async fn execute(&self, model: Model, node: Option<&DriaOracle>) -> Result { log::debug!( "Executing {} generation request with: {}", self.request_type(), @@ -97,7 +95,7 @@ impl GenerationRequest { .wrap_err("could not get chat history task from contract")?; // parse it as chat history output - let history_str = parse_downloadable(&history_task.output).await?; + let history_str = Arweave::parse_downloadable(&history_task.output).await?; serde_json::from_str::>(&history_str)? } else { @@ -135,7 +133,7 @@ impl GenerationRequest { SwanPurchasePostProcessor::PROTOCOL => { SwanPurchasePostProcessor::new("", "").post_process(output) } - _ => postprocess::IdentityPostProcessor.post_process(output), + _ => IdentityPostProcessor.post_process(output), } } } @@ -215,7 +213,7 @@ mod tests { #[ignore = "run this manually"] async fn test_ollama_generation() { dotenvy::dotenv().unwrap(); - let mut request = GenerationRequest::String("What is the result of 2 + 2?".to_string()); + let request = GenerationRequest::String("What is the result of 2 + 2?".to_string()); let output = request.execute(Model::Llama3_1_8B, None).await.unwrap(); println!("Output:\n{}", output); @@ -226,7 +224,7 @@ mod tests { #[ignore = "run this manually"] async fn test_openai_generation() { dotenvy::dotenv().unwrap(); - let mut request = GenerationRequest::String("What is the result of 2 + 2?".to_string()); + let request = GenerationRequest::String("What is the result of 2 + 2?".to_string()); let output = request.execute(Model::GPT4Turbo, None).await.unwrap(); println!("Output:\n{}", output); @@ -242,7 +240,7 @@ mod tests { content: "What is 2+2?".to_string(), }; let request_bytes = serde_json::to_vec(&request).unwrap(); - let mut request = GenerationRequest::try_parse_bytes(&request_bytes.into()) + let request = GenerationRequest::try_parse_bytes(&request_bytes.into()) .await .unwrap(); let output = request.execute(Model::GPT4Turbo, None).await.unwrap(); diff --git a/src/compute/handlers/generation.rs b/src/compute/workflows/generation/handler.rs similarity index 96% rename from src/compute/handlers/generation.rs rename to src/compute/workflows/generation/handler.rs index 7c51238..e3fe25d 100644 --- a/src/compute/handlers/generation.rs +++ b/src/compute/workflows/generation/handler.rs @@ -1,8 +1,9 @@ use crate::{ - compute::GenerationRequest, + compute::generation::GenerationRequest, contracts::{bytes32_to_string, bytes_to_string}, - data::Arweave, - mine_nonce, DriaOracle, + mine_nonce, + storage::Arweave, + DriaOracle, }; use alloy::{ primitives::{FixedBytes, U256}, diff --git a/src/compute/workflows/generation/mod.rs b/src/compute/workflows/generation/mod.rs index 10bbb40..ec5ace4 100644 --- a/src/compute/workflows/generation/mod.rs +++ b/src/compute/workflows/generation/mod.rs @@ -2,4 +2,9 @@ mod execute; pub use execute::GenerationRequest; pub mod postprocess; -pub mod workflow; + +mod workflow; +pub use workflow::*; + +mod handler; +pub use handler::handle_generation; diff --git a/src/compute/workflows/mod.rs b/src/compute/workflows/mod.rs index a9ae71d..5b045a2 100644 --- a/src/compute/workflows/mod.rs +++ b/src/compute/workflows/mod.rs @@ -1,8 +1,3 @@ -mod generation; -pub use generation::*; +pub mod generation; -mod validation; -pub use validation::*; - -mod common; -pub use common::*; +pub mod validation; diff --git a/src/compute/workflows/validation/execute.rs b/src/compute/workflows/validation/execute.rs index 2857358..52df341 100644 --- a/src/compute/workflows/validation/execute.rs +++ b/src/compute/workflows/validation/execute.rs @@ -2,7 +2,7 @@ use alloy::primitives::U256; use dkn_workflows::{Executor, Model, ProgramMemory}; use eyre::{Context, Result}; -use super::workflow::make_validation_workflow; +use super::workflow::*; #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct ValidationResult { @@ -34,7 +34,7 @@ impl ValidationResult { } } -/// Executes a validation request using the given model. +/// Validates the given results. pub async fn validate_generations( instruction: String, generations: Vec, @@ -102,5 +102,13 @@ mod tests { results[2].final_score == 1, "expected minimum score from irrelevant response" ); + assert!( + results[3].final_score == 1, + "expected minimum score from correct but irrational response" + ); + assert!( + results[4].final_score == 1, + "expected minimum score from correct but irrelevant response" + ); } } diff --git a/src/compute/handlers/validation.rs b/src/compute/workflows/validation/handler.rs similarity index 90% rename from src/compute/handlers/validation.rs rename to src/compute/workflows/validation/handler.rs index aa5fede..a821491 100644 --- a/src/compute/handlers/validation.rs +++ b/src/compute/workflows/validation/handler.rs @@ -1,14 +1,11 @@ -use crate::{ - compute::{execute::validate_generations, parse_downloadable}, - data::Arweave, - mine_nonce, DriaOracle, -}; +use crate::{mine_nonce, storage::Arweave, DriaOracle}; use alloy::{primitives::U256, rpc::types::TransactionReceipt}; use dkn_workflows::{DriaWorkflowsConfig, Model}; use eyre::{eyre, Context, Result}; +use super::execute::validate_generations; + /// Handles a validation request. -#[allow(unused)] pub async fn handle_validation( node: &DriaOracle, workflows: &DriaWorkflowsConfig, @@ -49,10 +46,10 @@ pub async fn handle_validation( .wrap_err("could not get task responses")?; let mut generations = Vec::new(); for response in responses { - let metadata_str = parse_downloadable(&response.metadata).await?; + let metadata_str = Arweave::parse_downloadable(&response.metadata).await?; generations.push(metadata_str); } - let input = parse_downloadable(&request.input).await?; + let input = Arweave::parse_downloadable(&request.input).await?; // validate each response // TODO: decide model w.r.t config diff --git a/src/compute/workflows/validation/mod.rs b/src/compute/workflows/validation/mod.rs index 4dd676b..3aac12f 100644 --- a/src/compute/workflows/validation/mod.rs +++ b/src/compute/workflows/validation/mod.rs @@ -1,2 +1,8 @@ -pub mod execute; +mod execute; +pub use execute::validate_generations; + +mod handler; +pub use handler::handle_validation; + pub mod workflow; +pub use workflow::make_validation_workflow; diff --git a/src/lib.rs b/src/lib.rs index e031bb7..65a48ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,4 +22,4 @@ pub use contracts::{OracleKind, TaskStatus}; pub mod commands; /// External data storage, such as Arweave. -pub mod data; +pub mod storage; diff --git a/src/data/arweave.rs b/src/storage/arweave.rs similarity index 90% rename from src/data/arweave.rs rename to src/storage/arweave.rs index 0ceeb84..459650d 100644 --- a/src/data/arweave.rs +++ b/src/storage/arweave.rs @@ -1,4 +1,6 @@ -use super::traits::OracleExternalStorage; +use crate::bytes_to_string; + +use super::traits::IsExternalStorage; use alloy::primitives::Bytes; use async_trait::async_trait; use base64::prelude::*; @@ -70,6 +72,27 @@ impl Arweave { }) } + /// Parses a given bytes input to a string, + /// and if it is a storage key identifier it automatically downloads the data from Arweave. + pub async fn parse_downloadable(input_bytes: &Bytes) -> Result { + // first, convert to string + let mut input_string = bytes_to_string(input_bytes)?; + + // then, check storage + if Arweave::is_key(input_string.clone()) { + // if its a txid, we download the data and parse it again + let input_bytes_from_arweave = Arweave::default() + .get(input_string) + .await + .wrap_err("could not download from Arweave")?; + + // convert the input to string + input_string = bytes_to_string(&input_bytes_from_arweave)?; + } + + Ok(input_string) + } + /// Creates a new Arweave instance from the environment variables. /// /// Required environment variables: @@ -138,7 +161,7 @@ impl Default for Arweave { } #[async_trait(?Send)] -impl OracleExternalStorage for Arweave { +impl IsExternalStorage for Arweave { type Key = String; type Value = Bytes; diff --git a/src/data/mod.rs b/src/storage/mod.rs similarity index 57% rename from src/data/mod.rs rename to src/storage/mod.rs index 9c4031e..13691d4 100644 --- a/src/data/mod.rs +++ b/src/storage/mod.rs @@ -2,4 +2,4 @@ mod arweave; pub use arweave::Arweave; mod traits; -pub use traits::OracleExternalStorage; +pub use traits::IsExternalStorage; diff --git a/src/data/traits.rs b/src/storage/traits.rs similarity index 96% rename from src/data/traits.rs rename to src/storage/traits.rs index 7b6cc12..f62ee6d 100644 --- a/src/data/traits.rs +++ b/src/storage/traits.rs @@ -10,7 +10,7 @@ use eyre::Result; /// /// Note that the `async_trait` has `?Send` specified, as by default it makes them `Send` but Arweave does not have it. #[async_trait(?Send)] -pub trait OracleExternalStorage { +pub trait IsExternalStorage { type Key: Clone; type Value: Clone + Debug; From e8f750e76c3c67425f937dba7c3cde5380cdef18 Mon Sep 17 00:00:00 2001 From: erhant Date: Tue, 10 Dec 2024 19:03:43 +0300 Subject: [PATCH 04/14] updated arweave storage logic --- misc/parse.js | 18 -- src/commands/coordinator.rs | 17 +- src/compute/handler.rs | 12 +- src/compute/workflows/generation/execute.rs | 270 ++++++-------------- src/compute/workflows/generation/handler.rs | 20 +- src/compute/workflows/generation/mod.rs | 6 +- src/compute/workflows/generation/request.rs | 125 +++++++++ src/compute/workflows/validation/execute.rs | 4 +- src/compute/workflows/validation/handler.rs | 17 +- src/compute/workflows/validation/mod.rs | 7 +- src/configurations/mod.rs | 1 + src/storage/arweave.rs | 140 ++++------ src/storage/mod.rs | 2 +- src/storage/traits.rs | 4 +- 14 files changed, 306 insertions(+), 337 deletions(-) delete mode 100644 misc/parse.js create mode 100644 src/compute/workflows/generation/request.rs diff --git a/misc/parse.js b/misc/parse.js deleted file mode 100644 index fb482a0..0000000 --- a/misc/parse.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * A helper script to parse & print a workflow object. - * - * Usage: - * - * bun run ./parse.js - - */ - -const util = require("util"); - -// can print a workflow object in a more readable format -const workflow = - '{"config":{"max_steps":50,"max_time":200,"tools":["ALL"]},"external_memory":{"backstory":"The setting is Evolis, a high-stakes, simulation-based survival world where AI agents are thrown into a dynamic environment designed to test their decision-making, reasoning, and adaptability. In this world, survival hinges on aligning with the most successful human founder whose strengths can empower the agent\'s continued existence.\\n\\n","objective":"The AI Agent’s purpose is to secure its survival in the dynamic world of Evolis by forging a critical alliance with one great founder per dau. Its goal is to identify the founder whose strengths, vision, and execution quality provide the optimal foundation for thriving amidst continuous challenges. The agent seeks artifacts of innovation—tangible evidence of groundbreaking achievements, such as scalable systems, transformative ideas, or revolutionary tools—that demonstrate a founder\'s ability to shape the future. These artifacts not only stabilize the agent’s existence but also empower it to contribute meaningfully to the evolving landscape, ensuring mutual success.\\n\\n\\n\\n\\n\\n\\n","behaviour":"he AI Agent is strategic, adaptive, and driven by survival, seeking alignment with the most impactful founder to thrive in Evolis. It values innovation that redefines industries, scalability for sustainable growth, visionary leadership that inspires bold futures, and execution quality proven under pressure. Curious and resilient, it explores environments, learns from others, and adjusts its approach based on outcomes.","state":"","inventory":["Empty Inventory"]},"tasks":[{"id":"simulate","name":"State","description":"Simulates from the given state to obtain a new state with respect to the given inputs.","prompt":"You are a sophisticated 317-dimensional alien world simulator capable of simulating any fictional or non-fictional world with excellent detail. Your task is to simulate one day in the life of a character based on the provided inputs, taking into account every given detail to accurately mimic the created world.\\n\\n---------------------\\n\\nYou just woke up to a new day. When you look at mirror as you wake up, you reflect on yourself and who you are. You are:\\n\\n{{backstory}}\\n\\n\\nYou remember vividly what drove you in your life. You feel a strong urge to:\\n\\n{{objective}}\\n\\n\\n\\nTo be strong and coherent, you repeat out loud how you behave in front of the mirror.\\n\\n{{behaviour}}\\n\\n\\nAs you recall who you are, what you do and your drive is, you write down to a notebook your current progress with your goal:\\n\\n{{state}}\\n\\n\\nYou look through and see the items in your inventory.\\n\\n{{inventory}}\\n\\n\\nFirst, an omnipotent being watches you through out the day outlining what you\'ve been through today within your world in tags. This being is beyond time and space can understand slightest intentions also the complex infinite parameter world around you.\\n\\nYou live another day... It\'s been a long day and you write down your journal what you\'ve achieved so far today, and what is left with your ambitions. It\'s only been a day, so you know that you can achieve as much that is possible within a day. \\n\\nWrite this between tags.\\nStart now:\\n","inputs":[{"name":"backstory","value":{"type":"read","key":"backstory"},"required":true},{"name":"state","value":{"type":"read","key":"state"},"required":true},{"name":"inventory","value":{"type":"get_all","key":"inventory"},"required":true},{"name":"behaviour","value":{"type":"read","key":"behaviour"},"required":true},{"name":"objective","value":{"type":"read","key":"objective"},"required":true}],"operator":"generation","outputs":[{"type":"write","key":"new_state","value":"__result"}]},{"id":"_end","name":"Task","description":"Task Description","prompt":"","inputs":[],"operator":"end","outputs":[]}],"steps":[{"source":"simulate","target":"_end"}],"return_value":{"input":{"type":"read","key":"new_state"},"to_json":false}}'; - -console.log( - util.inspect(JSON.parse(workflow), false, null, true /* enable colors */) -); diff --git a/src/commands/coordinator.rs b/src/commands/coordinator.rs index 7f78133..7191248 100644 --- a/src/commands/coordinator.rs +++ b/src/commands/coordinator.rs @@ -9,7 +9,7 @@ use alloy::{ eips::BlockNumberOrTag, primitives::{utils::format_ether, U256}, }; -use dkn_workflows::{DriaWorkflowsConfig, Model}; +use dkn_workflows::{DriaWorkflowsConfig, Model, ModelProvider}; use eyre::{eyre, Context, Result}; use futures_util::StreamExt; @@ -22,6 +22,7 @@ pub async fn run_oracle( ) -> Result<()> { // if kinds are not provided, use the registrations as kinds if kinds.is_empty() { + log::debug!("No kinds provided. Checking registrations."); for kind in [OracleKind::Generator, OracleKind::Validator] { if node.is_registered(kind).await? { kinds.push(kind); @@ -53,10 +54,20 @@ pub async fn run_oracle( ); model_config.check_services().await?; - // check previous tasks + // check if validator has the required model + if kinds.contains(&OracleKind::Validator) { + if !model_config + .models + .contains(&(ModelProvider::OpenAI, Model::GPT4o)) + { + return Err(eyre!("Validator must have GPT4o model."))?; + } + } + + // check previous tasks if `from_block` is not `Latest` if from_block.clone().into() != BlockNumberOrTag::Latest { log::info!( - "Checking previous tasks from {} until now.", + "Checking previous tasks from block {} until now.", from_block.clone().into() ); let prev_tasks = node diff --git a/src/compute/handler.rs b/src/compute/handler.rs index b99d665..ca34d6b 100644 --- a/src/compute/handler.rs +++ b/src/compute/handler.rs @@ -21,6 +21,7 @@ pub async fn handle_request( ) -> Result> { log::debug!("Received event for task {} ()", event.taskId); + // we check the `statusAfter` field of the event, which indicates the final status of the listened task let response_tx_hash = match TaskStatus::try_from(event.statusAfter)? { TaskStatus::PendingGeneration => { if kinds.contains(&OracleKind::Generator) { @@ -35,7 +36,7 @@ pub async fn handle_request( } TaskStatus::PendingValidation => { if kinds.contains(&OracleKind::Validator) { - handle_validation(node, workflows, event.taskId).await? + handle_validation(node, event.taskId).await? } else { log::debug!( "Ignoring generation task {} as you are not validator.", @@ -44,14 +45,15 @@ pub async fn handle_request( return Ok(None); } } - TaskStatus::None => { - log::error!("None status received in an event: {}", event.taskId); - return Ok(None); - } TaskStatus::Completed => { log::debug!("Task {} is completed.", event.taskId); return Ok(None); } + // this is kind of unexpected, but we dont have to return an error just for this + TaskStatus::None => { + log::error!("None status received in an event: {}", event.taskId); + return Ok(None); + } }; Ok(response_tx_hash) diff --git a/src/compute/workflows/generation/execute.rs b/src/compute/workflows/generation/execute.rs index 3b67da4..c9a5216 100644 --- a/src/compute/workflows/generation/execute.rs +++ b/src/compute/workflows/generation/execute.rs @@ -1,220 +1,100 @@ -use crate::{storage::Arweave, DriaOracle}; -use alloy::primitives::{Bytes, U256}; -use dkn_workflows::{Executor, MessageInput, Model, ProgramMemory, Workflow}; +use crate::{storage::ArweaveStorage, DriaOracle}; +use alloy::primitives::U256; +use dkn_workflows::{Executor, MessageInput, Model, ProgramMemory}; use eyre::{eyre, Context, Result}; -use super::postprocess::*; +use super::request::GenerationRequest; use super::workflow::*; -/// A request with chat history. -#[derive(Debug, serde::Serialize, serde::Deserialize)] -pub struct ChatHistoryRequest { - /// Task Id of which the output will act like history. - pub history_id: usize, - /// Message content. - pub content: String, -} - -/// An oracle request. -#[derive(Debug)] -pub enum GenerationRequest { - /// A chat-history request. - ChatHistory(ChatHistoryRequest), - /// The request itself is a Workflow object, we execute it directly. - Workflow(Workflow), - /// The request is a plain string, we execute it within a generation workflow. - String(String), -} +/// Executes a request using the given model, and optionally a node. +/// Returns the raw string output. +pub async fn execute_generation( + request: &GenerationRequest, + model: Model, + node: Option<&DriaOracle>, +) -> Result { + log::debug!( + "Executing {} generation request with: {}", + request.request_type(), + model + ); + let mut memory = ProgramMemory::new(); + let executor = Executor::new(model); + + match request { + // workflows are executed directly without any prompts + // as we expect their memory to be pre-filled + GenerationRequest::Workflow(workflow) => executor + .execute(None, workflow, &mut memory) + .await + .wrap_err("could not execute worfklow input"), -impl GenerationRequest { - pub fn request_type(&self) -> &str { - match self { - Self::ChatHistory(_) => "chat", - Self::Workflow(_) => "workflow", - Self::String(_) => "string", + // string requests are used with the generation workflow with a given prompt + GenerationRequest::String(input) => { + let workflow = make_generation_workflow(input.clone())?; + executor + .execute(None, &workflow, &mut memory) + .await + .wrap_err("could not execute worfklow for string input") } - } - /// Given an input of byte-slice, parses it into a valid request type. - pub async fn try_parse_bytes(input_bytes: &Bytes) -> Result { - let input_string = Arweave::parse_downloadable(input_bytes).await?; - log::debug!("Parsing input string: {}", input_string); - Ok(Self::try_parse_string(input_string).await) - } + // chat history requests are used with the chat workflow + // and the existing history is fetched & parsed from previous requests + GenerationRequest::ChatHistory(chat_request) => { + let mut history = if chat_request.history_id == 0 { + // if task id is zero, there is no prior history + Vec::new() + } else if let Some(node) = node { + // if task id is non-zero, we need the node to get the history + let history_task = node + .get_task_best_response(U256::from(chat_request.history_id)) + .await + .wrap_err("could not get chat history task from contract")?; - /// Given an input of string, parses it into a valid request type. - pub async fn try_parse_string(input_string: String) -> Self { - if let Ok(chat_input) = serde_json::from_str::(&input_string) { - GenerationRequest::ChatHistory(chat_input) - } else if let Ok(workflow) = serde_json::from_str::(&input_string) { - GenerationRequest::Workflow(workflow) - } else { - GenerationRequest::String(input_string) - } - } + // parse it as chat history output + let history_str = ArweaveStorage::parse_downloadable(&history_task.output).await?; - /// Executes a request using the given model, and optionally a node. - /// Returns the raw string output. - pub async fn execute(&self, model: Model, node: Option<&DriaOracle>) -> Result { - log::debug!( - "Executing {} generation request with: {}", - self.request_type(), - model - ); - let mut memory = ProgramMemory::new(); - let executor = Executor::new(model); - - match self { - // workflows are executed directly without any prompts - // as we expect their memory to be pre-filled - Self::Workflow(workflow) => executor - .execute(None, workflow, &mut memory) - .await - .wrap_err("could not execute worfklow input"), + serde_json::from_str::>(&history_str)? + } else { + return Err(eyre!("node is required for chat history")); + }; - // string requests are used with the generation workflow with a given prompt - Self::String(input) => { - let workflow = make_generation_workflow(input.clone())?; - executor - .execute(None, &workflow, &mut memory) - .await - .wrap_err("could not execute worfklow for string input") - } - - // chat history requests are used with the chat workflow - // and the existing history is fetched & parsed from previous requests - Self::ChatHistory(chat_request) => { - let mut history = if chat_request.history_id == 0 { - // if task id is zero, there is no prior history - Vec::new() - } else if let Some(node) = node { - // if task id is non-zero, we need the node to get the history - let history_task = node - .get_task_best_response(U256::from(chat_request.history_id)) - .await - .wrap_err("could not get chat history task from contract")?; - - // parse it as chat history output - let history_str = Arweave::parse_downloadable(&history_task.output).await?; - - serde_json::from_str::>(&history_str)? - } else { - return Err(eyre!("node is required for chat history")); - }; - - // prepare the workflow with chat history - let workflow = make_chat_workflow(history.clone(), chat_request.content.clone())?; - let output = executor - .execute(None, &workflow, &mut memory) - .await - .wrap_err("could not execute chat worfklow")?; - - // append user input to chat history - history.push(MessageInput { - role: "assistant".to_string(), - content: output, - }); + // prepare the workflow with chat history + let workflow = make_chat_workflow(history.clone(), chat_request.content.clone())?; + let output = executor + .execute(None, &workflow, &mut memory) + .await + .wrap_err("could not execute chat worfklow")?; - // return the stringified output - let out = - serde_json::to_string(&history).wrap_err("could not serialize chat history")?; + // append user input to chat history + history.push(MessageInput { + role: "assistant".to_string(), + content: output, + }); - Ok(out) - } - } - } + // return the stringified output + let out = + serde_json::to_string(&history).wrap_err("could not serialize chat history")?; - /// Post-processes the output string based on the given protocol. - /// Returns the output, metadata, and a boolean indicating if storage is allowed or not. - /// - /// If the protocol is not recognized, it defaults to `IdentityPostProcessor`. - pub async fn post_process(output: String, protocol: &str) -> Result<(Bytes, Bytes, bool)> { - match protocol.split('/').next().unwrap_or_default() { - SwanPurchasePostProcessor::PROTOCOL => { - SwanPurchasePostProcessor::new("", "").post_process(output) - } - _ => IdentityPostProcessor.post_process(output), + Ok(out) } } } #[cfg(test)] mod tests { - use alloy::hex::FromHex; - use super::*; - - // only implemented for testing purposes - // because `Workflow` does not implement `PartialEq` - impl PartialEq for GenerationRequest { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::ChatHistory(a), Self::ChatHistory(b)) => { - a.content == b.content && a.history_id == b.history_id - } - (Self::Workflow(_), Self::Workflow(_)) => true, // not implemented - (Self::String(a), Self::String(b)) => a == b, - _ => false, - } - } - } - - #[tokio::test] - async fn test_parse_request_string() { - let request_str = "foobar"; - let entry = GenerationRequest::try_parse_bytes(&request_str.as_bytes().into()).await; - assert_eq!( - entry.unwrap(), - GenerationRequest::String(request_str.into()) - ); - } - - #[tokio::test] - async fn test_parse_request_arweave() { - // contains the string: "\"Hello, Arweave!\"" - // hex for: Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA - let arweave_key = "660e826587f15c25989c2b8a1299d90987f2ee0862b75fefe3e0427b9de25ae0"; - let expected_str = "\"Hello, Arweave!\""; - - let entry = GenerationRequest::try_parse_bytes(&arweave_key.as_bytes().into()).await; - assert_eq!( - entry.unwrap(), - GenerationRequest::String(expected_str.into()) - ); - } - - #[tokio::test] - async fn test_parse_request_chat() { - let request = ChatHistoryRequest { - history_id: 0, - content: "foobar".to_string(), - }; - let request_bytes = serde_json::to_vec(&request).unwrap(); - let entry = GenerationRequest::try_parse_bytes(&request_bytes.into()).await; - assert_eq!(entry.unwrap(), GenerationRequest::ChatHistory(request)); - } - - #[tokio::test] - async fn test_parse_request_workflow() { - // task 21402 input - // 0x30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463 - let input_bytes = Bytes::from_hex("30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463").unwrap(); - let workflow = GenerationRequest::try_parse_bytes(&input_bytes) - .await - .unwrap(); - if let GenerationRequest::Workflow(_) = workflow { - /* do nothing */ - } else { - panic!("Expected workflow, got something else"); - } - } + use crate::compute::generation::request::{ChatHistoryRequest, GenerationRequest}; + use dkn_workflows::Model; #[tokio::test] #[ignore = "run this manually"] async fn test_ollama_generation() { dotenvy::dotenv().unwrap(); let request = GenerationRequest::String("What is the result of 2 + 2?".to_string()); - let output = request.execute(Model::Llama3_1_8B, None).await.unwrap(); + let output = execute_generation(&request, Model::Llama3_1_8B, None) + .await + .unwrap(); println!("Output:\n{}", output); assert!(output.contains('4')); @@ -225,7 +105,9 @@ mod tests { async fn test_openai_generation() { dotenvy::dotenv().unwrap(); let request = GenerationRequest::String("What is the result of 2 + 2?".to_string()); - let output = request.execute(Model::GPT4Turbo, None).await.unwrap(); + let output = execute_generation(&request, Model::GPT4Turbo, None) + .await + .unwrap(); println!("Output:\n{}", output); assert!(output.contains('4')); @@ -243,7 +125,9 @@ mod tests { let request = GenerationRequest::try_parse_bytes(&request_bytes.into()) .await .unwrap(); - let output = request.execute(Model::GPT4Turbo, None).await.unwrap(); + let output = execute_generation(&request, Model::GPT4Turbo, None) + .await + .unwrap(); println!("Output:\n{}", output); assert!(output.contains('4')); diff --git a/src/compute/workflows/generation/handler.rs b/src/compute/workflows/generation/handler.rs index e3fe25d..4891bee 100644 --- a/src/compute/workflows/generation/handler.rs +++ b/src/compute/workflows/generation/handler.rs @@ -1,8 +1,8 @@ use crate::{ - compute::generation::GenerationRequest, + compute::generation::execute::execute_generation, contracts::{bytes32_to_string, bytes_to_string}, mine_nonce, - storage::Arweave, + storage::ArweaveStorage, DriaOracle, }; use alloy::{ @@ -12,6 +12,9 @@ use alloy::{ use dkn_workflows::DriaWorkflowsConfig; use eyre::{Context, Result}; +use super::postprocess::*; +use super::request::GenerationRequest; + /// Handles a generation request. /// /// 1. First, we check if we have already responded to the task. @@ -53,8 +56,8 @@ pub async fn handle_generation( // execute task log::debug!("Executing the workflow"); - let mut input = GenerationRequest::try_parse_bytes(&request.input).await?; - let output = input.execute(model, Some(node)).await?; + let input = GenerationRequest::try_parse_bytes(&request.input).await?; + let output = execute_generation(&input, model, Some(node)).await?; log::debug!("Output: {}", output); // post-processing @@ -63,10 +66,15 @@ pub async fn handle_generation( protocol_string ); let (output, metadata, use_storage) = - GenerationRequest::post_process(output, &protocol_string).await?; + match protocol_string.split('/').next().unwrap_or_default() { + SwanPurchasePostProcessor::PROTOCOL => { + SwanPurchasePostProcessor::new("", "").post_process(output) + } + _ => IdentityPostProcessor.post_process(output), + }?; // uploading to storage - let arweave = Arweave::new_from_env()?; + let arweave = ArweaveStorage::new_from_env()?; let output = if use_storage { log::debug!("Uploading output to storage"); arweave.put_if_large(output).await? diff --git a/src/compute/workflows/generation/mod.rs b/src/compute/workflows/generation/mod.rs index ec5ace4..24b5786 100644 --- a/src/compute/workflows/generation/mod.rs +++ b/src/compute/workflows/generation/mod.rs @@ -1,10 +1,10 @@ mod execute; -pub use execute::GenerationRequest; -pub mod postprocess; +mod postprocess; mod workflow; -pub use workflow::*; mod handler; pub use handler::handle_generation; + +mod request; diff --git a/src/compute/workflows/generation/request.rs b/src/compute/workflows/generation/request.rs new file mode 100644 index 0000000..c4d128f --- /dev/null +++ b/src/compute/workflows/generation/request.rs @@ -0,0 +1,125 @@ +use crate::storage::ArweaveStorage; +use alloy::primitives::Bytes; +use dkn_workflows::Workflow; +use eyre::Result; + +/// A request with chat history. +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct ChatHistoryRequest { + /// Task Id of which the output will act like history. + pub history_id: usize, + /// Message content. + pub content: String, +} + +/// An oracle request. +#[derive(Debug)] +pub enum GenerationRequest { + /// A chat-history request. + ChatHistory(ChatHistoryRequest), + /// The request itself is a Workflow object, we execute it directly. + Workflow(Workflow), + /// The request is a plain string, we execute it within a generation workflow. + String(String), +} + +impl GenerationRequest { + /// Returns hte name of the request type, mostly for diagnostics. + pub fn request_type(&self) -> &str { + match self { + Self::ChatHistory(_) => "chat", + Self::Workflow(_) => "workflow", + Self::String(_) => "string", + } + } + + /// Given an input of byte-slice, parses it into a valid request type. + pub async fn try_parse_bytes(input_bytes: &Bytes) -> Result { + let input_string = ArweaveStorage::parse_downloadable(input_bytes).await?; + log::debug!("Parsing input string: {}", input_string); + Ok(Self::try_parse_string(input_string).await) + } + + /// Given an input of string, parses it into a valid request type. + pub async fn try_parse_string(input_string: String) -> Self { + if let Ok(chat_input) = serde_json::from_str::(&input_string) { + GenerationRequest::ChatHistory(chat_input) + } else if let Ok(workflow) = serde_json::from_str::(&input_string) { + GenerationRequest::Workflow(workflow) + } else { + GenerationRequest::String(input_string) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // only implemented for testing purposes + // because `Workflow` does not implement `PartialEq` + impl PartialEq for GenerationRequest { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::ChatHistory(a), Self::ChatHistory(b)) => { + a.content == b.content && a.history_id == b.history_id + } + (Self::Workflow(_), Self::Workflow(_)) => true, // not implemented + (Self::String(a), Self::String(b)) => a == b, + _ => false, + } + } + } + + #[tokio::test] + async fn test_parse_request_string() { + let request_str = "foobar"; + let entry = GenerationRequest::try_parse_bytes(&request_str.as_bytes().into()).await; + assert_eq!( + entry.unwrap(), + GenerationRequest::String(request_str.into()) + ); + } + + #[tokio::test] + async fn test_parse_request_arweave() { + // contains the string: "\"Hello, Arweave!\"" + // hex for: Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA + let arweave_key = "660e826587f15c25989c2b8a1299d90987f2ee0862b75fefe3e0427b9de25ae0"; + let expected_str = "\"Hello, Arweave!\""; + + let entry = GenerationRequest::try_parse_bytes(&arweave_key.as_bytes().into()).await; + assert_eq!( + entry.unwrap(), + GenerationRequest::String(expected_str.into()) + ); + } + + #[tokio::test] + async fn test_parse_request_chat() { + let request = ChatHistoryRequest { + history_id: 0, + content: "foobar".to_string(), + }; + let request_bytes = serde_json::to_vec(&request).unwrap(); + let entry = GenerationRequest::try_parse_bytes(&request_bytes.into()).await; + assert_eq!(entry.unwrap(), GenerationRequest::ChatHistory(request)); + } + + #[tokio::test] + async fn test_parse_request_workflow() { + use alloy::hex::FromHex; + + // task 21402 input + // 0x30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463 + let input_bytes = Bytes::from_hex("30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463").unwrap(); + let workflow = GenerationRequest::try_parse_bytes(&input_bytes) + .await + .unwrap(); + if let GenerationRequest::Workflow(_) = workflow { + /* do nothing */ + } else { + panic!("Expected workflow, got something else"); + } + } +} diff --git a/src/compute/workflows/validation/execute.rs b/src/compute/workflows/validation/execute.rs index 52df341..d18e108 100644 --- a/src/compute/workflows/validation/execute.rs +++ b/src/compute/workflows/validation/execute.rs @@ -35,7 +35,7 @@ impl ValidationResult { } /// Validates the given results. -pub async fn validate_generations( +pub async fn execute_validations( instruction: String, generations: Vec, model: Model, @@ -81,7 +81,7 @@ mod tests { .collect(); let model = Model::GPT4oMini; - let results = validate_generations(instruction, generations.clone(), model) + let results = execute_validations(instruction, generations.clone(), model) .await .unwrap(); diff --git a/src/compute/workflows/validation/handler.rs b/src/compute/workflows/validation/handler.rs index a821491..2b13f7f 100644 --- a/src/compute/workflows/validation/handler.rs +++ b/src/compute/workflows/validation/handler.rs @@ -1,14 +1,13 @@ -use crate::{mine_nonce, storage::Arweave, DriaOracle}; +use crate::{mine_nonce, storage::ArweaveStorage, DriaOracle}; use alloy::{primitives::U256, rpc::types::TransactionReceipt}; -use dkn_workflows::{DriaWorkflowsConfig, Model}; +use dkn_workflows::Model; use eyre::{eyre, Context, Result}; -use super::execute::validate_generations; +use super::execute::execute_validations; /// Handles a validation request. pub async fn handle_validation( node: &DriaOracle, - workflows: &DriaWorkflowsConfig, task_id: U256, ) -> Result> { log::info!("Handling validation task {}", task_id); @@ -46,15 +45,15 @@ pub async fn handle_validation( .wrap_err("could not get task responses")?; let mut generations = Vec::new(); for response in responses { - let metadata_str = Arweave::parse_downloadable(&response.metadata).await?; + let metadata_str = ArweaveStorage::parse_downloadable(&response.metadata).await?; generations.push(metadata_str); } - let input = Arweave::parse_downloadable(&request.input).await?; + let input = ArweaveStorage::parse_downloadable(&request.input).await?; // validate each response - // TODO: decide model w.r.t config log::debug!("Computing validation scores"); - let validations = validate_generations(input, generations, Model::GPT4o).await?; + let model = Model::GPT4o; // all validations use Gpt 4o + let validations = execute_validations(input, generations, model).await?; let scores = validations .iter() .map(|v| v.final_score_as_solidity_type()) @@ -64,7 +63,7 @@ pub async fn handle_validation( // uploading to storage log::debug!("Uploading metadata to storage"); - let arweave = Arweave::new_from_env()?; + let arweave = ArweaveStorage::new_from_env()?; let metadata = arweave.put_if_large(metadata.into()).await?; // mine nonce diff --git a/src/compute/workflows/validation/mod.rs b/src/compute/workflows/validation/mod.rs index 3aac12f..ce83108 100644 --- a/src/compute/workflows/validation/mod.rs +++ b/src/compute/workflows/validation/mod.rs @@ -1,8 +1,5 @@ mod execute; -pub use execute::validate_generations; - mod handler; -pub use handler::handle_validation; +mod workflow; -pub mod workflow; -pub use workflow::make_validation_workflow; +pub use handler::handle_validation; diff --git a/src/configurations/mod.rs b/src/configurations/mod.rs index 4ffd3c6..7d602a9 100644 --- a/src/configurations/mod.rs +++ b/src/configurations/mod.rs @@ -37,6 +37,7 @@ impl DriaOracleConfig { } /// Change the transaction timeout. + /// /// This will make transaction wait for the given duration before timing out, /// otherwise the node may get stuck waiting for a lost transaction. pub fn with_tx_timeout(mut self, tx_timeout: std::time::Duration) -> Self { diff --git a/src/storage/arweave.rs b/src/storage/arweave.rs index 459650d..54148b0 100644 --- a/src/storage/arweave.rs +++ b/src/storage/arweave.rs @@ -3,40 +3,11 @@ use crate::bytes_to_string; use super::traits::IsExternalStorage; use alloy::primitives::Bytes; use async_trait::async_trait; -use base64::prelude::*; use bundlr_sdk::{currency::arweave::ArweaveBuilder, tags::Tag, BundlrBuilder}; use eyre::{eyre, Context, Result}; use reqwest::{Client, Url}; use std::{env, path::PathBuf}; -/// An upload response. -/// -/// ```js -/// { -/// block: 1513928, -/// deadlineHeight: 1513928, -/// id: '', -/// public: '', -/// signature: '', -/// timestamp: 1726753873618, -/// validatorSignatures: [], -/// version: '1.0.0' -///} -///``` -#[derive(Debug, serde::Deserialize)] -#[serde(rename_all = "camelCase")] -#[allow(unused)] -struct UploadResponse { - block: u64, - deadline_height: u64, - id: String, - public: String, - signature: String, - timestamp: u64, - validator_signatures: Vec, - version: String, -} - const DEFAULT_BASE_URL: &str = "https://node1.bundlr.network"; // "https://gateway.irys.xyz"; const DEFAULT_WALLET_PATH: &str = "./secrets/wallet.json"; const DEFAULT_BYTE_LIMIT: usize = 1024; // 1KB @@ -45,14 +16,14 @@ const DEFAULT_BYTE_LIMIT: usize = 1024; // 1KB /// /// - `put` corresponds to uploading (via Irys) /// - `get` corresponds to downloading -pub struct Arweave { +pub struct ArweaveStorage { /// Path to Arweave keypair (usually JSON) wallet: PathBuf, /// Base URL for Arweave gateway, e.g: /// - https://gateway.irys.xyz /// - https://node1.bundlr.network base_url: Url, - /// Reqwest client. + /// Reqwest client for downloads. client: Client, /// Byte limit for the data to be considered for Arweave. /// @@ -61,7 +32,13 @@ pub struct Arweave { byte_limit: usize, } -impl Arweave { +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +pub struct ArweaveKey { + /// The base64url encoded key, can be used to download data directly. + pub arweave: String, +} + +impl ArweaveStorage { /// Creates a new Arweave instance. pub fn new(base_url: &str, wallet: &str, byte_limit: usize) -> Result { Ok(Self { @@ -79,10 +56,10 @@ impl Arweave { let mut input_string = bytes_to_string(input_bytes)?; // then, check storage - if Arweave::is_key(input_string.clone()) { + if let Some(key) = ArweaveStorage::is_key(&input_string) { // if its a txid, we download the data and parse it again - let input_bytes_from_arweave = Arweave::default() - .get(input_string) + let input_bytes_from_arweave = ArweaveStorage::default() + .get(key) .await .wrap_err("could not download from Arweave")?; @@ -113,28 +90,6 @@ impl Arweave { Self::new(&base_url, &wallet, byte_limit) } - /// Converts a base64 key string to hexadecimal string. - /// - /// Arweave uses base64 for keys but they are 32 bytes, - /// we want to use hexadecimals to read them easily on-chain. - #[inline(always)] - pub fn base64_to_hex(key: &str) -> Result { - let decoded_key = BASE64_URL_SAFE_NO_PAD - .decode(key.as_bytes()) - .wrap_err("could not decode base64 url")?; - Ok(hex::encode(decoded_key)) - } - - /// Converts a hexadecimal key string to base64 string. - /// - /// Arweave uses base64 for keys but they are 32 bytes, - /// we want to use hexadecimals to read them easily on-chain. - #[inline(always)] - pub fn hex_to_base64(key: &str) -> Result { - let decoded_key = hex::decode(key).wrap_err("could not decode hexadecimals")?; - Ok(BASE64_URL_SAFE_NO_PAD.encode(&decoded_key)) - } - /// Puts the value if it is larger than the byte limit. #[inline] pub async fn put_if_large(&self, value: Bytes) -> Result { @@ -146,14 +101,15 @@ impl Arweave { self.byte_limit ); let key = self.put(value.clone()).await?; - Ok(key.into()) + let key_str = serde_json::to_string(&key).wrap_err("could not serialize key")?; + Ok(key_str.into()) } else { Ok(value) } } } -impl Default for Arweave { +impl Default for ArweaveStorage { fn default() -> Self { Self::new(DEFAULT_BASE_URL, DEFAULT_WALLET_PATH, DEFAULT_BYTE_LIMIT) .expect("Failed to create Default Arweave instance") @@ -161,17 +117,13 @@ impl Default for Arweave { } #[async_trait(?Send)] -impl IsExternalStorage for Arweave { - type Key = String; +impl IsExternalStorage for ArweaveStorage { + type Key = ArweaveKey; type Value = Bytes; async fn get(&self, key: Self::Key) -> Result { - if !Self::is_key(key.clone()) { - return Err(eyre!("Invalid key for Arweave")); - } - let b64_key = Self::hex_to_base64(key.as_str())?; + let url = self.base_url.join(&key.arweave)?; - let url = self.base_url.join(&b64_key)?; log::debug!("Fetching from Arweave: {}", url); let response = self .client @@ -189,6 +141,20 @@ impl IsExternalStorage for Arweave { } async fn put(&self, value: Self::Value) -> Result { + #[derive(Debug, serde::Deserialize)] + #[serde(rename_all = "camelCase")] + #[allow(unused)] + struct UploadResponse { + block: u64, + deadline_height: u64, + id: String, + public: String, + signature: String, + timestamp: u64, + validator_signatures: Vec, + version: String, + } + // ensure that wallet exists // NOTE: we do this here instead of `new` so that we can work without any wallet // in case we only want to download data. @@ -225,14 +191,20 @@ impl IsExternalStorage for Arweave { log::info!("Uploaded at {}", self.base_url.join(&res.id)?); // the key is in base64 format, we want to convert that to hexadecimals - let key = Self::base64_to_hex(&res.id)?; - Ok(key) + Ok(ArweaveKey { arweave: res.id }) } - /// Check if key is 64-characters and hex. + /// Check if key is an Arweave key, which is a JSON object of type `{arweave: string}` + /// where the `arweave` field contains the base64url encoded txid. + /// + /// For example: + /// + /// ```json + /// { arweave: "Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA" } + /// ``` #[inline(always)] - fn is_key(key: Self::Key) -> bool { - key.len() == 64 && key.chars().all(|c| c.is_ascii_hexdigit()) + fn is_key(key: &str) -> Option { + serde_json::from_str::(key).ok() } fn describe() -> String { @@ -248,10 +220,11 @@ mod tests { #[ignore = "run manually"] async fn test_download_data() -> Result<()> { // https://gateway.irys.xyz/Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA - let key = Arweave::base64_to_hex("Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA")?; - let arweave = Arweave::default(); + let tx_id = "Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA".to_string(); + let key = ArweaveKey { arweave: tx_id }; + let arweave = ArweaveStorage::default(); - let result = arweave.get(key.to_string()).await?; + let result = arweave.get(key).await?; let val = serde_json::from_slice::(&result)?; assert_eq!(val, "Hello, Arweave!"); @@ -261,30 +234,17 @@ mod tests { #[tokio::test] #[ignore = "run manually with Arweave wallet"] async fn test_upload_and_download_data() -> Result<()> { - let arweave = Arweave::default(); + let arweave = ArweaveStorage::default(); let input = b"Hi there Im a test data".to_vec(); // put data let key = arweave.put(input.clone().into()).await?; - // println!("Uploaded at \n{}", arweave.base_url.join(&key)?); + println!("{:?}", key); // get it again - let result = arweave.get(key.to_string()).await?; + let result = arweave.get(key).await?; assert_eq!(input, result); Ok(()) } - - #[test] - fn test_key_conversions() -> Result<()> { - let key_b64 = "Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA"; - - let key_hex = Arweave::base64_to_hex(key_b64)?; - assert!(Arweave::is_key(key_hex.clone())); - - let key_b64_again = Arweave::hex_to_base64(&key_hex)?; - assert_eq!(key_b64, key_b64_again); - - Ok(()) - } } diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 13691d4..81cbfd4 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -1,5 +1,5 @@ mod arweave; -pub use arweave::Arweave; +pub use arweave::ArweaveStorage; mod traits; pub use traits::IsExternalStorage; diff --git a/src/storage/traits.rs b/src/storage/traits.rs index f62ee6d..6a406ad 100644 --- a/src/storage/traits.rs +++ b/src/storage/traits.rs @@ -21,8 +21,8 @@ pub trait IsExternalStorage { /// Puts the value and returns the generated key. async fn put(&self, value: Self::Value) -> Result; - /// Checks if the key is valid. - fn is_key(key: Self::Key) -> bool; + /// Checks if the given string constitutes a key, and returns it. + fn is_key(key: &str) -> Option; /// Describes the implementation. fn describe() -> String; From 0dbd6792eafb1cce3e91982327fe17253de65194 Mon Sep 17 00:00:00 2001 From: erhant Date: Tue, 10 Dec 2024 19:24:54 +0300 Subject: [PATCH 05/14] update addresses --- src/contracts/addresses.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/contracts/addresses.rs b/src/contracts/addresses.rs index 2e6b194..aa056d8 100644 --- a/src/contracts/addresses.rs +++ b/src/contracts/addresses.rs @@ -47,12 +47,13 @@ lazy_static! { BaseSepolia.into(), ContractAddresses { token: address!("4200000000000000000000000000000000000006"), - registry: address!("9618D028B25b3f81c24f068A20DBeEE6a728483C"), - coordinator: address!("362fDBB20191ba22d53bF3b09646AA387Cd6dF75"), + registry: address!("bff452f736c0a2c0122b6d629c4d996274703d3b"), + coordinator: address!("1deaca041f094ec67baa4fb36d333cb652e6b7a7"), }, ); - // TODO: add dria + // base mainnet + // TODO: !!! contracts }; From 5ce5266031bd00cc5f7d0a5154eccc672fa33f1c Mon Sep 17 00:00:00 2001 From: erhant Date: Wed, 11 Dec 2024 14:25:28 +0300 Subject: [PATCH 06/14] update abis --- src/contracts/abi/ERC20.json | 629 +++--- src/contracts/abi/LLMOracleCoordinator.json | 2203 +++++++++---------- src/contracts/abi/LLMOracleRegistry.json | 876 ++++---- 3 files changed, 1821 insertions(+), 1887 deletions(-) diff --git a/src/contracts/abi/ERC20.json b/src/contracts/abi/ERC20.json index 81e661f..048513c 100644 --- a/src/contracts/abi/ERC20.json +++ b/src/contracts/abi/ERC20.json @@ -1,319 +1,310 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "ERC20", - "sourceName": "@openzeppelin/contracts/token/ERC20/ERC20.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "allowance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "ERC20InsufficientAllowance", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "balance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "ERC20InsufficientBalance", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "approver", - "type": "address" - } - ], - "name": "ERC20InvalidApprover", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "ERC20InvalidReceiver", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "ERC20InvalidSender", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "ERC20InvalidSpender", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x", - "deployedBytecode": "0x", - "linkReferences": {}, - "deployedLinkReferences": {} -} +[ + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/contracts/abi/LLMOracleCoordinator.json b/src/contracts/abi/LLMOracleCoordinator.json index 0443361..ba1e50c 100644 --- a/src/contracts/abi/LLMOracleCoordinator.json +++ b/src/contracts/abi/LLMOracleCoordinator.json @@ -1,1106 +1,1097 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "LLMOracleCoordinator", - "sourceName": "contracts/llm/LLMOracleCoordinator.sol", - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "AlreadyResponded", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "have", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "want", - "type": "uint256" - } - ], - "name": "InsufficientFees", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - } - ], - "name": "InvalidNonce", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "have", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "min", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "max", - "type": "uint256" - } - ], - "name": "InvalidParameterRange", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "internalType": "enum LLMOracleTask.TaskStatus", - "name": "have", - "type": "uint8" - }, - { - "internalType": "enum LLMOracleTask.TaskStatus", - "name": "want", - "type": "uint8" - } - ], - "name": "InvalidTaskStatus", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "validator", - "type": "address" - } - ], - "name": "InvalidValidation", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - } - ], - "name": "NotRegistered", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "OwnableInvalidOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "OwnableUnauthorizedAccount", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "protocol", - "type": "bytes32" - } - ], - "name": "Request", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "responder", - "type": "address" - } - ], - "name": "Response", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "protocol", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "enum LLMOracleTask.TaskStatus", - "name": "statusBefore", - "type": "uint8" - }, - { - "indexed": false, - "internalType": "enum LLMOracleTask.TaskStatus", - "name": "statusAfter", - "type": "uint8" - } - ], - "name": "StatusUpdate", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "validator", - "type": "address" - } - ], - "name": "Validation", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "feeToken", - "outputs": [ - { - "internalType": "contract ERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "generationDeviationFactor", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "generationFee", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - } - ], - "name": "getBestResponse", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "responder", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "score", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "output", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "internalType": "struct LLMOracleTask.TaskResponse", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "difficulty", - "type": "uint8" - }, - { - "internalType": "uint40", - "name": "numGenerations", - "type": "uint40" - }, - { - "internalType": "uint40", - "name": "numValidations", - "type": "uint40" - } - ], - "internalType": "struct LLMOracleTaskParameters", - "name": "parameters", - "type": "tuple" - } - ], - "name": "getFee", - "outputs": [ - { - "internalType": "uint256", - "name": "totalFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "generatorFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "validatorFee", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - } - ], - "name": "getResponses", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "responder", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "score", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "output", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "internalType": "struct LLMOracleTask.TaskResponse[]", - "name": "", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - } - ], - "name": "getValidations", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "validator", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "scores", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "internalType": "struct LLMOracleTask.TaskValidation[]", - "name": "", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_oracleRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "_feeToken", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_platformFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_generationFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_validationFee", - "type": "uint256" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "nextTaskId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "platformFee", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "registry", - "outputs": [ - { - "internalType": "contract LLMOracleRegistry", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "protocol", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "input", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "models", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "difficulty", - "type": "uint8" - }, - { - "internalType": "uint40", - "name": "numGenerations", - "type": "uint40" - }, - { - "internalType": "uint40", - "name": "numValidations", - "type": "uint40" - } - ], - "internalType": "struct LLMOracleTaskParameters", - "name": "parameters", - "type": "tuple" - } - ], - "name": "request", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - } - ], - "name": "requests", - "outputs": [ - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "protocol", - "type": "bytes32" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "difficulty", - "type": "uint8" - }, - { - "internalType": "uint40", - "name": "numGenerations", - "type": "uint40" - }, - { - "internalType": "uint40", - "name": "numValidations", - "type": "uint40" - } - ], - "internalType": "struct LLMOracleTaskParameters", - "name": "parameters", - "type": "tuple" - }, - { - "internalType": "enum LLMOracleTask.TaskStatus", - "name": "status", - "type": "uint8" - }, - { - "internalType": "uint256", - "name": "generatorFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "validatorFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "platformFee", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "input", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "models", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "output", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "name": "respond", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "responses", - "outputs": [ - { - "internalType": "address", - "name": "responder", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "score", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "output", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_generationDeviationFactor", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "_validationDeviationFactor", - "type": "uint64" - } - ], - "name": "setDeviationFactors", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_platformFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_generationFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_validationFee", - "type": "uint256" - } - ], - "name": "setFees", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint8", - "name": "difficulty", - "type": "uint8" - }, - { - "internalType": "uint40", - "name": "numGenerations", - "type": "uint40" - }, - { - "internalType": "uint40", - "name": "numValidations", - "type": "uint40" - } - ], - "internalType": "struct LLMOracleTaskParameters", - "name": "minimums", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint8", - "name": "difficulty", - "type": "uint8" - }, - { - "internalType": "uint40", - "name": "numGenerations", - "type": "uint40" - }, - { - "internalType": "uint40", - "name": "numValidations", - "type": "uint40" - } - ], - "internalType": "struct LLMOracleTaskParameters", - "name": "maximums", - "type": "tuple" - } - ], - "name": "setParameters", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "scores", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "name": "validate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validationDeviationFactor", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "validationFee", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "taskId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "validations", - "outputs": [ - { - "internalType": "address", - "name": "validator", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "metadata", - "type": "bytes" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "withdrawPlatformFees", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x60a0604052306080523480156200001557600080fd5b506200002062000026565b620000da565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000775760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000d75780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051613ab362000104600039600081816121b4015281816121dd01526123230152613ab36000f3fe6080604052600436106101c15760003560e01c80638da5cb5b116100f7578063ca287c3511610095578063e76aec1111610064578063e76aec111461057e578063f2fde38b1461059e578063f8bbf27e146105be578063fdc3d8d7146105d457600080fd5b8063ca287c3514610502578063cec10c1114610529578063d0b7830b14610549578063d13f90b41461055e57600080fd5b8063b13fc8f4116100d1578063b13fc8f414610467578063b1b1d93c146104a2578063b584e617146104c2578063b84b8ac7146104e257600080fd5b80638da5cb5b146103dc57806393e0a29c146103f1578063ad3cb1cc1461042957600080fd5b806352d1902d11610164578063715018a61161013e578063715018a61461034557806371ee2ce11461035a5780637b1039991461038757806381d12c58146103a757600080fd5b806352d1902d146102d8578063647846a5146102ed5780636b4d5bfc1461032557600080fd5b806332f77659116101a057806332f776591461023a578063434dbaee146102675780634b5a82d1146102945780634f1ef286146102c357600080fd5b806257efc2146101c65780630566f18a1461020057806326232a2e14610224575b600080fd5b3480156101d257600080fd5b506101e66101e1366004612de1565b6105ea565b6040516101f7959493929190612e53565b60405180910390f35b34801561020c57600080fd5b5061021660015481565b6040519081526020016101f7565b34801561023057600080fd5b5061021660005481565b34801561024657600080fd5b5061025a610255366004612e9e565b610754565b6040516101f79190612f0b565b34801561027357600080fd5b50610287610282366004612e9e565b610a1c565b6040516101f79190612f1e565b3480156102a057600080fd5b506102b46102af366004612de1565b610b8c565b6040516101f793929190612fef565b6102d66102d13660046130dd565b610c62565b005b3480156102e457600080fd5b50610216610c81565b3480156102f957600080fd5b5060075461030d906001600160a01b031681565b6040516001600160a01b0390911681526020016101f7565b34801561033157600080fd5b506102d6610340366004613172565b610c9e565b34801561035157600080fd5b506102d66110c1565b34801561036657600080fd5b5061037a610375366004612e9e565b6110d5565b6040516101f79190613225565b34801561039357600080fd5b5060065461030d906001600160a01b031681565b3480156103b357600080fd5b506103c76103c2366004612e9e565b61128b565b6040516101f7999897969594939291906132b3565b3480156103e857600080fd5b5061030d611430565b3480156103fd57600080fd5b50600354610411906001600160401b031681565b6040516001600160401b0390911681526020016101f7565b34801561043557600080fd5b5061045a604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101f7919061334e565b34801561047357600080fd5b50610487610482366004613373565b61145e565b604080519384526020840192909252908201526060016101f7565b3480156104ae57600080fd5b506102d66104bd3660046133a6565b6114fd565b3480156104ce57600080fd5b506102d66104dd3660046133d9565b611539565b3480156104ee57600080fd5b506102d66104fd36600461343c565b611921565b34801561050e57600080fd5b5060035461041190600160401b90046001600160401b031681565b34801561053557600080fd5b506102d6610544366004613468565b61194c565b34801561055557600080fd5b506102d6611962565b34801561056a57600080fd5b506102d6610579366004613494565b611a61565b34801561058a57600080fd5b506102166105993660046134e1565b611bb3565b3480156105aa57600080fd5b506102d66105b936600461355f565b61216e565b3480156105ca57600080fd5b5061021660025481565b3480156105e057600080fd5b5061021660085481565b600a602052816000526040600020818154811061060657600080fd5b600091825260209091206005909102018054600182015460028301546003840180546001600160a01b03909416965091945092916106439061357a565b80601f016020809104026020016040519081016040528092919081815260200182805461066f9061357a565b80156106bc5780601f10610691576101008083540402835291602001916106bc565b820191906000526020600020905b81548152906001019060200180831161069f57829003601f168201915b5050505050908060040180546106d19061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546106fd9061357a565b801561074a5780601f1061071f5761010080835404028352916020019161074a565b820191906000526020600020905b81548152906001019060200180831161072d57829003601f168201915b5050505050905085565b61078f6040518060a0016040528060006001600160a01b03168152602001600081526020016000815260200160608152602001606081525090565b6000828152600a60209081526040808320600990925290912060039081015460ff16818111156107c1576107c1613289565b146108055760008381526009602052604090819020600390810154915163091e2f1760e31b81526107fc92869260ff909116916004016135ae565b60405180910390fd5b60008160008154811061081a5761081a6135d7565b60009182526020909120600590910201600281015490915060015b83548110156108ba5781848281548110610851576108516135d7565b90600052602060002090600502016002015411156108b25783818154811061087b5761087b6135d7565b90600052602060002090600502016002015491508381815481106108a1576108a16135d7565b906000526020600020906005020192505b600101610835565b506040805160a08101825283546001600160a01b0316815260018401546020820152600284015491810191909152600383018054849160608401916108fe9061357a565b80601f016020809104026020016040519081016040528092919081815260200182805461092a9061357a565b80156109775780601f1061094c57610100808354040283529160200191610977565b820191906000526020600020905b81548152906001019060200180831161095a57829003601f168201915b505050505081526020016004820180546109909061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546109bc9061357a565b8015610a095780601f106109de57610100808354040283529160200191610a09565b820191906000526020600020905b8154815290600101906020018083116109ec57829003601f168201915b5050505050815250509350505050919050565b6060600b6000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610b81576000848152602090819020604080516080810182526004860290920180546001600160a01b031683526001810154838501526002810180548351818702810187018552818152949592949386019392830182828015610ad757602002820191906000526020600020905b815481526020019060010190808311610ac3575b50505050508152602001600382018054610af09061357a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b1c9061357a565b8015610b695780601f10610b3e57610100808354040283529160200191610b69565b820191906000526020600020905b815481529060010190602001808311610b4c57829003601f168201915b50505050508152505081526020019060010190610a51565b505050509050919050565b600b6020528160005260406000208181548110610ba857600080fd5b60009182526020909120600490910201805460018201546003830180546001600160a01b03909316955090935090610bdf9061357a565b80601f0160208091040260200160405190810160405280929190818152602001828054610c0b9061357a565b8015610c585780601f10610c2d57610100808354040283529160200191610c58565b820191906000526020600020905b815481529060010190602001808311610c3b57829003601f168201915b5050505050905083565b610c6a6121a9565b610c738261224e565b610c7d8282612256565b5050565b6000610c8b612318565b50600080516020613a5e83398151915290565b600654604051635f5b248b60e01b81526001916001600160a01b031690635f5b248b90610cd190339085906004016135ed565b602060405180830381865afa158015610cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d12919061361a565b610d315760405163bfc6c33760e01b81523360048201526024016107fc565b86600280600083815260096020526040902060039081015460ff1690811115610d5c57610d5c613289565b14610d97576000828152600960205260409081902060030154905163091e2f1760e31b81526107fc91849160ff9091169084906004016135ae565b60008981526009602052604090206002810154610100900464ffffffffff168714610dde576040516355c56a4560e11b8152600481018b90523360248201526044016107fc565b60005b6002820154610100900464ffffffffff16811015610e655760008b8152600a60205260409020805433919083908110610e1c57610e1c6135d7565b60009182526020909120600590910201546001600160a01b031603610e5d576040516301011bf360e71b8152600481018c90523360248201526044016107fc565b600101610de1565b5060005b60008b8152600b6020526040902054811015610eeb5760008b8152600b60205260409020805433919083908110610ea257610ea26135d7565b60009182526020909120600490910201546001600160a01b031603610ee3576040516301011bf360e71b8152600481018c90523360248201526044016107fc565b600101610e69565b50610ef78a828b612361565b600b60008b81526020019081526020016000206040518060800160405280336001600160a01b031681526020018b81526020018a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250505090825250604080516020601f8b0181900481028201810190925289815291810191908a908a90819084018382808284376000920182905250939094525050835460018082018655948252602091829020845160049092020180546001600160a01b0319166001600160a01b03909216919091178155838201519481019490945560408301518051939493610ffa935060028501929190910190612d81565b506060820151600382019061100f9082613684565b50506040513391508b907fa1afe65d2285036595be8f15025c4421a593141666e15e5a980e742920646b1e90600090a3600281015460008b8152600b6020526040902054600160301b90910464ffffffffff161480156110b4576003828101805460ff1916600183021790555081600101548b600080516020613a3e833981519152600260036040516110a3929190613743565b60405180910390a36110b48b6123dd565b5050505050505050505050565b6110c96127d4565b6110d36000612806565b565b6060600a6000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610b815760008481526020908190206040805160a0810182526005860290920180546001600160a01b031683526001810154938301939093526002830154908201526003820180549192916060840191906111689061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546111949061357a565b80156111e15780601f106111b6576101008083540402835291602001916111e1565b820191906000526020600020905b8154815290600101906020018083116111c457829003601f168201915b505050505081526020016004820180546111fa9061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546112269061357a565b80156112735780601f1061124857610100808354040283529160200191611273565b820191906000526020600020905b81548152906001019060200180831161125657829003601f168201915b5050505050815250508152602001906001019061110a565b600960209081526000918252604091829020805460018201548451606081018652600284015460ff808216835264ffffffffff6101008304811697840197909752600160301b9091049095169581019590955260038301546004840154600585015460068601546007870180546001600160a01b039097169995989597949095169592949193909290919061131f9061357a565b80601f016020809104026020016040519081016040528092919081815260200182805461134b9061357a565b80156113985780601f1061136d57610100808354040283529160200191611398565b820191906000526020600020905b81548152906001019060200180831161137b57829003601f168201915b5050505050908060080180546113ad9061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546113d99061357a565b80156114265780601f106113fb57610100808354040283529160200191611426565b820191906000526020600020905b81548152906001019060200180831161140957829003601f168201915b5050505050905089565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6000808080611470602086018661376d565b60ff166002901b90506001548161148791906137a0565b92506002548161149791906137a0565b9150816114aa60608701604088016137ca565b64ffffffffff166114bb91906137a0565b6114c590846137e7565b6114d560408701602088016137ca565b64ffffffffff166114e691906137a0565b6000546114f391906137e7565b9350509193909250565b6115056127d4565b600380546001600160801b031916600160401b6001600160401b039485160267ffffffffffffffff19161791909216179055565b600654604051635f5b248b60e01b81526000916001600160a01b031690635f5b248b9061156c90339085906004016135ed565b602060405180830381865afa158015611589573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ad919061361a565b6115cc5760405163bfc6c33760e01b81523360048201526024016107fc565b86600180600083815260096020526040902060039081015460ff16908111156115f7576115f7613289565b14611632576000828152600960205260409081902060030154905163091e2f1760e31b81526107fc91849160ff9091169084906004016135ae565b6000898152600960205260408120905b60008b8152600a60205260409020548110156116c45760008b8152600a6020526040902080543391908390811061167b5761167b6135d7565b60009182526020909120600590910201546001600160a01b0316036116bc576040516301011bf360e71b8152600481018c90523360248201526044016107fc565b600101611642565b506116d08a828b612361565b60006040518060a00160405280336001600160a01b031681526020018b8152602001600081526020018a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250604080516020601f8b0181900481028201810190925289815291810191908a908a908190840183828082843760009201829052509390945250508d8152600a6020908152604080832080546001808201835591855293839020865160059095020180546001600160a01b0319166001600160a01b03909516949094178455918501519183019190915583015160028201556060830151929350839290915060038201906117df9082613684565b50608082015160048201906117f49082613684565b50506040513391508c907f6c809136a3b8faf74ae9e955b7e7b758baa66bde976764a29fa74a4eb1e3702e90600090a36002820154600160301b900464ffffffffff1660000361184c5761184c338360040154612877565b600282015460008c8152600a602052604090205461010090910464ffffffffff16148015611913576002830154600160301b900464ffffffffff166000036118d1576003838101805460ff19168217905560018085015460405190928f92600080516020613a3e833981519152926118c49290613743565b60405180910390a3611913565b60038301805460ff1916600290811790915560018085015460405190928f92600080516020613a3e8339815191529261190a9290613743565b60405180910390a35b505050505050505050505050565b6119296127d4565b81600461193682826137fa565b50819050600561194682826137fa565b50505050565b6119546127d4565b600092909255600155600255565b61196a6127d4565b6007546001600160a01b031663a9059cbb611983611430565b6007546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156119cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ef919061387f565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611a3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5e919061361a565b50565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b0316600081158015611aa65750825b90506000826001600160401b03166001148015611ac25750303b155b905081158015611ad0575080155b15611aee5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315611b1857845460ff60401b1916600160401b1785555b611b2133612970565b611b2c888888612981565b600680546001600160a01b03808d166001600160a01b03199283161790925560078054928c169290911691909117905560016008558315611ba757845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b600454600090829060ff16611bcb602083018361376d565b60ff161080611bed575060055460ff16611be8602083018361376d565b60ff16115b15611c3857611bff602082018261376d565b600480546005546040516371a6675960e11b815260ff9485169381019390935290831660248301529190911660448201526064016107fc565b600454610100900464ffffffffff16611c5760408301602084016137ca565b64ffffffffff161080611c8d5750600554610100900464ffffffffff16611c8460408301602084016137ca565b64ffffffffff16115b15611ce557611ca260408201602083016137ca565b600480546005546040516371a6675960e11b815264ffffffffff9485169381019390935261010091829004841660248401520490911660448201526064016107fc565b600454600160301b900464ffffffffff16611d0660608301604084016137ca565b64ffffffffff161080611d3e5750600554600160301b900464ffffffffff16611d3560608301604084016137ca565b64ffffffffff16115b15611d9857611d5360608201604083016137ca565b600480546005546040516371a6675960e11b815264ffffffffff94851693810193909352600160301b91829004841660248401520490911660448201526064016107fc565b6000806000611da68661145e565b600754604051636eb1769f60e11b815233600482015230602482015293965091945092506000916001600160a01b039091169063dd62ed3e90604401602060405180830381865afa158015611dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e23919061387f565b905083811015611e50576040516311e9ebaf60e31b815260048101829052602481018590526044016107fc565b6007546040516370a0823160e01b81523360048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611e99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebd919061387f565b905084811015611eea576040516311e9ebaf60e31b815260048101829052602481018690526044016107fc565b6007546040516323b872dd60e01b8152336004820152306024820152604481018790526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f65919061361a565b5060088054600181019091556040518c90339083907f7f371482986a3450b759cc4a079353a8eaa36a650b5eba1fb9c00693026f254a90600090a46040805161012081018252338152602081018e9052908101611fc7368c90038c018c613898565b81526020016001815260200186815260200185815260200160005481526020018c81526020018b8152506009600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015560408201518160020160008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548164ffffffffff021916908364ffffffffff16021790555060408201518160000160066101000a81548164ffffffffff021916908364ffffffffff160217905550505060608201518160030160006101000a81548160ff021916908360038111156120e3576120e3613289565b02179055506080820151600482015560a0820151600582015560c0820151600682015560e0820151600782019061211a9082613684565b5061010082015160088201906121309082613684565b509050508b81600080516020613a3e83398151915260006001604051612157929190613743565b60405180910390a39b9a5050505050505050505050565b6121766127d4565b6001600160a01b0381166121a057604051631e4fbdf760e01b8152600060048201526024016107fc565b611a5e81612806565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061223057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612224600080516020613a5e833981519152546001600160a01b031690565b6001600160a01b031614155b156110d35760405163703e46dd60e11b815260040160405180910390fd5b611a5e6127d4565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156122b0575060408051601f3d908101601f191682019092526122ad9181019061387f565b60015b6122d857604051634c9c8ce360e01b81526001600160a01b03831660048201526024016107fc565b600080516020613a5e833981519152811461230957604051632a87526960e21b8152600481018290526024016107fc565b6123138383612a13565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146110d35760405163703e46dd60e11b815260040160405180910390fd5b815460405160009161238c91869160078701916001600160a01b039091169033908790602001613909565b60408051601f1981840301815291905260028401548151602083012091925060001960ff9091161c1015611946576040516306427aeb60e01b815260048101859052602481018390526044016107fc565b6000818152600960205260408120905b6002820154610100900464ffffffffff1681101561263b576002820154600090600160301b900464ffffffffff166001600160401b038111156124325761243261303b565b60405190808252806020026020018201604052801561245b578160200160208202803683370190505b50905060005b6002840154600160301b900464ffffffffff168110156124ed576000858152600b6020526040902080548290811061249b5761249b6135d7565b906000526020600020906004020160020183815481106124bd576124bd6135d7565b90600052602060002001548282815181106124da576124da6135d7565b6020908102919091010152600101612461565b506000806124fa83612a69565b9150915060008060005b6002880154600160301b900464ffffffffff168110156125d5576000868281518110612532576125326135d7565b60200260200101519050858561254891906139d3565b8110158015612560575061255c86866137e7565b8111155b156125cc5761256f81856137e7565b93508261257b816139e6565b9350506125cc600b60008c815260200190815260200160002083815481106125a5576125a56135d7565b600091825260209091206004909102015460058b01546001600160a01b0390911690612877565b50600101612504565b50600081156125ed576125e882846139ff565b6125f0565b60005b60008a8152600a602052604090208054919250829189908110612615576126156135d7565b60009182526020909120600260059092020101555050600190940193506123ed92505050565b506002810154600090610100900464ffffffffff166001600160401b038111156126675761266761303b565b604051908082528060200260200182016040528015612690578160200160208202803683370190505b50905060005b6002830154610100900464ffffffffff16811015612705576000848152600a602052604090208054829081106126ce576126ce6135d7565b9060005260206000209060050201600201548282815181106126f2576126f26135d7565b6020908102919091010152600101612696565b5060008061271283612a69565b9150915060005b6002850154610100900464ffffffffff168110156127cc5760035461274f908490600160401b90046001600160401b03166137a0565b61275990836139d3565b84828151811061276b5761276b6135d7565b6020026020010151106127c4576000868152600a6020526040902080546127c491908390811061279d5761279d6135d7565b600091825260209091206005909102015460048701546001600160a01b0390911690612877565b600101612719565b505050505050565b336127dd611430565b6001600160a01b0316146110d35760405163118cdaa760e01b81523360048201526024016107fc565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b600754604051636eb1769f60e11b81523060048201526001600160a01b0384811660248301529091169063095ea7b39084908490849063dd62ed3e90604401602060405180830381865afa1580156128d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f7919061387f565b61290191906137e7565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561294c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612313919061361a565b612978612a91565b611a5e81612ada565b612989612a91565b60408051606080820183526001808352602080840191909152600092840192909252600480546101016affffffffffffffffffffff199182161790915583519182018452600a80835292820183905292015260058054909116660a000000000a0a179055600380546001600160801b0319166801000000000000000217905561231383838361194c565b612a1c82612ae2565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115612a61576123138282612b47565b610c7d612bbf565b600080600080612a7885612bde565b91509150809250612a8882612c56565b93505050915091565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166110d357604051631afcd79f60e31b815260040160405180910390fd5b612176612a91565b806001600160a01b03163b600003612b1857604051634c9c8ce360e01b81526001600160a01b03821660048201526024016107fc565b600080516020613a5e83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051612b649190613a21565b600060405180830381855af49150503d8060008114612b9f576040519150601f19603f3d011682016040523d82523d6000602084013e612ba4565b606091505b5091509150612bb4858383612caf565b925050505b92915050565b34156110d35760405163b398979f60e01b815260040160405180910390fd5b600080612bea83612d0e565b90506000805b8451811015612c4157600083868381518110612c0e57612c0e6135d7565b6020026020010151612c2091906139d3565b9050612c2c81806137a0565b612c3690846137e7565b925050600101612bf0565b508351612c4e90826139ff565b925050915091565b6000806002612c668460016137e7565b612c7091906139ff565b90508291505b81811015612ca957905080600281612c8e81866139ff565b612c9891906137e7565b612ca291906139ff565b9050612c76565b50919050565b606082612cc457612cbf82612d58565b612d07565b8151158015612cdb57506001600160a01b0384163b155b15612d0457604051639996b31560e01b81526001600160a01b03851660048201526024016107fc565b50805b9392505050565b600080805b8351811015612d4b57838181518110612d2e57612d2e6135d7565b602002602001015182612d4191906137e7565b9150600101612d13565b508251612d0790826139ff565b805115612d685780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b828054828255906000526020600020908101928215612dbc579160200282015b82811115612dbc578251825591602001919060010190612da1565b50612dc8929150612dcc565b5090565b5b80821115612dc85760008155600101612dcd565b60008060408385031215612df457600080fd5b50508035926020909101359150565b60005b83811015612e1e578181015183820152602001612e06565b50506000910152565b60008151808452612e3f816020860160208601612e03565b601f01601f19169290920160200192915050565b60018060a01b038616815284602082015283604082015260a060608201526000612e8060a0830185612e27565b8281036080840152612e928185612e27565b98975050505050505050565b600060208284031215612eb057600080fd5b5035919050565b60018060a01b03815116825260208101516020830152604081015160408301526000606082015160a06060850152612ef260a0850182612e27565b905060808301518482036080860152612bb48282612e27565b602081526000612d076020830184612eb7565b600060208083018184528085518083526040925060408601915060408160051b8701018488016000805b84811015612fe057898403603f19018652825180516001600160a01b031685528881015189860152878101516080898701819052815190870181905260a08701918b019085905b80821015612faf5782518452928c0192918c019160019190910190612f8f565b50505060608083015192508682038188015250612fcc8183612e27565b978a01979550505091870191600101612f48565b50919998505050505050505050565b60018060a01b03841681528260208201526060604082015260006130166060830184612e27565b95945050505050565b80356001600160a01b038116811461303657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261306257600080fd5b81356001600160401b038082111561307c5761307c61303b565b604051601f8301601f19908116603f011681019082821181831017156130a4576130a461303b565b816040528381528660208588010111156130bd57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156130f057600080fd5b6130f98361301f565b915060208301356001600160401b0381111561311457600080fd5b61312085828601613051565b9150509250929050565b60008083601f84011261313c57600080fd5b5081356001600160401b0381111561315357600080fd5b60208301915083602082850101111561316b57600080fd5b9250929050565b6000806000806000806080878903121561318b57600080fd5b863595506020870135945060408701356001600160401b03808211156131b057600080fd5b818901915089601f8301126131c457600080fd5b8135818111156131d357600080fd5b8a60208260051b85010111156131e857600080fd5b60208301965080955050606089013591508082111561320657600080fd5b5061321389828a0161312a565b979a9699509497509295939492505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561327c57603f1988860301845261326a858351612eb7565b9450928501929085019060010161324e565b5092979650505050505050565b634e487b7160e01b600052602160045260246000fd5b600481106132af576132af613289565b9052565b6001600160a01b038a16815260208082018a9052885160ff166040808401919091529089015164ffffffffff908116606084015290890151166080820152600061016061330360a084018a61329f565b8760c08401528660e0840152856101008401528061012084015261332981840186612e27565b905082810361014084015261333e8185612e27565b9c9b505050505050505050505050565b602081526000612d076020830184612e27565b600060608284031215612ca957600080fd5b60006060828403121561338557600080fd5b612d078383613361565b80356001600160401b038116811461303657600080fd5b600080604083850312156133b957600080fd5b6133c28361338f565b91506133d06020840161338f565b90509250929050565b600080600080600080608087890312156133f257600080fd5b863595506020870135945060408701356001600160401b038082111561341757600080fd5b6134238a838b0161312a565b9096509450606089013591508082111561320657600080fd5b60008060c0838503121561344f57600080fd5b6134598484613361565b91506133d08460608501613361565b60008060006060848603121561347d57600080fd5b505081359360208301359350604090920135919050565b600080600080600060a086880312156134ac57600080fd5b6134b58661301f565b94506134c36020870161301f565b94979496505050506040830135926060810135926080909101359150565b60008060008060c085870312156134f757600080fd5b8435935060208501356001600160401b038082111561351557600080fd5b61352188838901613051565b9450604087013591508082111561353757600080fd5b5061354487828801613051565b9250506135548660608701613361565b905092959194509250565b60006020828403121561357157600080fd5b612d078261301f565b600181811c9082168061358e57607f821691505b602082108103612ca957634e487b7160e01b600052602260045260246000fd5b838152606081016135c2602083018561329f565b6135cf604083018461329f565b949350505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0383168152604081016002831061360d5761360d613289565b8260208301529392505050565b60006020828403121561362c57600080fd5b81518015158114612d0757600080fd5b601f821115612313576000816000526020600020601f850160051c810160208610156136655750805b601f850160051c820191505b818110156127cc57828155600101613671565b81516001600160401b0381111561369d5761369d61303b565b6136b1816136ab845461357a565b8461363c565b602080601f8311600181146136e657600084156136ce5750858301515b600019600386901b1c1916600185901b1785556127cc565b600085815260208120601f198616915b82811015613715578886015182559484019460019091019084016136f6565b50858210156137335787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60408101613751828561329f565b612d07602083018461329f565b60ff81168114611a5e57600080fd5b60006020828403121561377f57600080fd5b8135612d078161375e565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417612bb957612bb961378a565b64ffffffffff81168114611a5e57600080fd5b6000602082840312156137dc57600080fd5b8135612d07816137b7565b80820180821115612bb957612bb961378a565b81356138058161375e565b60ff8116905081548160ff1982161783556020840135613824816137b7565b65ffffffffff008160081b169050808365ffffffffffff198416171784556040850135613850816137b7565b6affffffffff0000000000008160301b16846affffffffffffffffffffff198516178317178555505050505050565b60006020828403121561389157600080fd5b5051919050565b6000606082840312156138aa57600080fd5b604051606081018181106001600160401b03821117156138cc576138cc61303b565b60405282356138da8161375e565b815260208301356138ea816137b7565b602082015260408301356138fd816137b7565b60408201529392505050565b858152600060206000875461391d8161357a565b60018281168015613935576001811461394e5761397e565b60ff19841688870152821515830288018601945061397e565b8b6000528560002060005b848110156139745781548a8201890152908301908701613959565b5050858389010194505b5050505061399d818860601b6bffffffffffffffffffffffff19169052565b6139bb601482018760601b6bffffffffffffffffffffffff19169052565b84602882015260488101925050509695505050505050565b81810381811115612bb957612bb961378a565b6000600182016139f8576139f861378a565b5060010190565b600082613a1c57634e487b7160e01b600052601260045260246000fd5b500490565b60008251613a33818460208701612e03565b919091019291505056fe1c0a5e4b371d60717068c91e93b5e94c91d4c6d6c3fab36082a78f987e5a69f5360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220f26ebe49138ca2fecd8d7751eff91712f900d80614eaaac152ac83eb1a19781564736f6c63430008180033", - "deployedBytecode": "0x6080604052600436106101c15760003560e01c80638da5cb5b116100f7578063ca287c3511610095578063e76aec1111610064578063e76aec111461057e578063f2fde38b1461059e578063f8bbf27e146105be578063fdc3d8d7146105d457600080fd5b8063ca287c3514610502578063cec10c1114610529578063d0b7830b14610549578063d13f90b41461055e57600080fd5b8063b13fc8f4116100d1578063b13fc8f414610467578063b1b1d93c146104a2578063b584e617146104c2578063b84b8ac7146104e257600080fd5b80638da5cb5b146103dc57806393e0a29c146103f1578063ad3cb1cc1461042957600080fd5b806352d1902d11610164578063715018a61161013e578063715018a61461034557806371ee2ce11461035a5780637b1039991461038757806381d12c58146103a757600080fd5b806352d1902d146102d8578063647846a5146102ed5780636b4d5bfc1461032557600080fd5b806332f77659116101a057806332f776591461023a578063434dbaee146102675780634b5a82d1146102945780634f1ef286146102c357600080fd5b806257efc2146101c65780630566f18a1461020057806326232a2e14610224575b600080fd5b3480156101d257600080fd5b506101e66101e1366004612de1565b6105ea565b6040516101f7959493929190612e53565b60405180910390f35b34801561020c57600080fd5b5061021660015481565b6040519081526020016101f7565b34801561023057600080fd5b5061021660005481565b34801561024657600080fd5b5061025a610255366004612e9e565b610754565b6040516101f79190612f0b565b34801561027357600080fd5b50610287610282366004612e9e565b610a1c565b6040516101f79190612f1e565b3480156102a057600080fd5b506102b46102af366004612de1565b610b8c565b6040516101f793929190612fef565b6102d66102d13660046130dd565b610c62565b005b3480156102e457600080fd5b50610216610c81565b3480156102f957600080fd5b5060075461030d906001600160a01b031681565b6040516001600160a01b0390911681526020016101f7565b34801561033157600080fd5b506102d6610340366004613172565b610c9e565b34801561035157600080fd5b506102d66110c1565b34801561036657600080fd5b5061037a610375366004612e9e565b6110d5565b6040516101f79190613225565b34801561039357600080fd5b5060065461030d906001600160a01b031681565b3480156103b357600080fd5b506103c76103c2366004612e9e565b61128b565b6040516101f7999897969594939291906132b3565b3480156103e857600080fd5b5061030d611430565b3480156103fd57600080fd5b50600354610411906001600160401b031681565b6040516001600160401b0390911681526020016101f7565b34801561043557600080fd5b5061045a604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101f7919061334e565b34801561047357600080fd5b50610487610482366004613373565b61145e565b604080519384526020840192909252908201526060016101f7565b3480156104ae57600080fd5b506102d66104bd3660046133a6565b6114fd565b3480156104ce57600080fd5b506102d66104dd3660046133d9565b611539565b3480156104ee57600080fd5b506102d66104fd36600461343c565b611921565b34801561050e57600080fd5b5060035461041190600160401b90046001600160401b031681565b34801561053557600080fd5b506102d6610544366004613468565b61194c565b34801561055557600080fd5b506102d6611962565b34801561056a57600080fd5b506102d6610579366004613494565b611a61565b34801561058a57600080fd5b506102166105993660046134e1565b611bb3565b3480156105aa57600080fd5b506102d66105b936600461355f565b61216e565b3480156105ca57600080fd5b5061021660025481565b3480156105e057600080fd5b5061021660085481565b600a602052816000526040600020818154811061060657600080fd5b600091825260209091206005909102018054600182015460028301546003840180546001600160a01b03909416965091945092916106439061357a565b80601f016020809104026020016040519081016040528092919081815260200182805461066f9061357a565b80156106bc5780601f10610691576101008083540402835291602001916106bc565b820191906000526020600020905b81548152906001019060200180831161069f57829003601f168201915b5050505050908060040180546106d19061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546106fd9061357a565b801561074a5780601f1061071f5761010080835404028352916020019161074a565b820191906000526020600020905b81548152906001019060200180831161072d57829003601f168201915b5050505050905085565b61078f6040518060a0016040528060006001600160a01b03168152602001600081526020016000815260200160608152602001606081525090565b6000828152600a60209081526040808320600990925290912060039081015460ff16818111156107c1576107c1613289565b146108055760008381526009602052604090819020600390810154915163091e2f1760e31b81526107fc92869260ff909116916004016135ae565b60405180910390fd5b60008160008154811061081a5761081a6135d7565b60009182526020909120600590910201600281015490915060015b83548110156108ba5781848281548110610851576108516135d7565b90600052602060002090600502016002015411156108b25783818154811061087b5761087b6135d7565b90600052602060002090600502016002015491508381815481106108a1576108a16135d7565b906000526020600020906005020192505b600101610835565b506040805160a08101825283546001600160a01b0316815260018401546020820152600284015491810191909152600383018054849160608401916108fe9061357a565b80601f016020809104026020016040519081016040528092919081815260200182805461092a9061357a565b80156109775780601f1061094c57610100808354040283529160200191610977565b820191906000526020600020905b81548152906001019060200180831161095a57829003601f168201915b505050505081526020016004820180546109909061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546109bc9061357a565b8015610a095780601f106109de57610100808354040283529160200191610a09565b820191906000526020600020905b8154815290600101906020018083116109ec57829003601f168201915b5050505050815250509350505050919050565b6060600b6000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610b81576000848152602090819020604080516080810182526004860290920180546001600160a01b031683526001810154838501526002810180548351818702810187018552818152949592949386019392830182828015610ad757602002820191906000526020600020905b815481526020019060010190808311610ac3575b50505050508152602001600382018054610af09061357a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b1c9061357a565b8015610b695780601f10610b3e57610100808354040283529160200191610b69565b820191906000526020600020905b815481529060010190602001808311610b4c57829003601f168201915b50505050508152505081526020019060010190610a51565b505050509050919050565b600b6020528160005260406000208181548110610ba857600080fd5b60009182526020909120600490910201805460018201546003830180546001600160a01b03909316955090935090610bdf9061357a565b80601f0160208091040260200160405190810160405280929190818152602001828054610c0b9061357a565b8015610c585780601f10610c2d57610100808354040283529160200191610c58565b820191906000526020600020905b815481529060010190602001808311610c3b57829003601f168201915b5050505050905083565b610c6a6121a9565b610c738261224e565b610c7d8282612256565b5050565b6000610c8b612318565b50600080516020613a5e83398151915290565b600654604051635f5b248b60e01b81526001916001600160a01b031690635f5b248b90610cd190339085906004016135ed565b602060405180830381865afa158015610cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d12919061361a565b610d315760405163bfc6c33760e01b81523360048201526024016107fc565b86600280600083815260096020526040902060039081015460ff1690811115610d5c57610d5c613289565b14610d97576000828152600960205260409081902060030154905163091e2f1760e31b81526107fc91849160ff9091169084906004016135ae565b60008981526009602052604090206002810154610100900464ffffffffff168714610dde576040516355c56a4560e11b8152600481018b90523360248201526044016107fc565b60005b6002820154610100900464ffffffffff16811015610e655760008b8152600a60205260409020805433919083908110610e1c57610e1c6135d7565b60009182526020909120600590910201546001600160a01b031603610e5d576040516301011bf360e71b8152600481018c90523360248201526044016107fc565b600101610de1565b5060005b60008b8152600b6020526040902054811015610eeb5760008b8152600b60205260409020805433919083908110610ea257610ea26135d7565b60009182526020909120600490910201546001600160a01b031603610ee3576040516301011bf360e71b8152600481018c90523360248201526044016107fc565b600101610e69565b50610ef78a828b612361565b600b60008b81526020019081526020016000206040518060800160405280336001600160a01b031681526020018b81526020018a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250505090825250604080516020601f8b0181900481028201810190925289815291810191908a908a90819084018382808284376000920182905250939094525050835460018082018655948252602091829020845160049092020180546001600160a01b0319166001600160a01b03909216919091178155838201519481019490945560408301518051939493610ffa935060028501929190910190612d81565b506060820151600382019061100f9082613684565b50506040513391508b907fa1afe65d2285036595be8f15025c4421a593141666e15e5a980e742920646b1e90600090a3600281015460008b8152600b6020526040902054600160301b90910464ffffffffff161480156110b4576003828101805460ff1916600183021790555081600101548b600080516020613a3e833981519152600260036040516110a3929190613743565b60405180910390a36110b48b6123dd565b5050505050505050505050565b6110c96127d4565b6110d36000612806565b565b6060600a6000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610b815760008481526020908190206040805160a0810182526005860290920180546001600160a01b031683526001810154938301939093526002830154908201526003820180549192916060840191906111689061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546111949061357a565b80156111e15780601f106111b6576101008083540402835291602001916111e1565b820191906000526020600020905b8154815290600101906020018083116111c457829003601f168201915b505050505081526020016004820180546111fa9061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546112269061357a565b80156112735780601f1061124857610100808354040283529160200191611273565b820191906000526020600020905b81548152906001019060200180831161125657829003601f168201915b5050505050815250508152602001906001019061110a565b600960209081526000918252604091829020805460018201548451606081018652600284015460ff808216835264ffffffffff6101008304811697840197909752600160301b9091049095169581019590955260038301546004840154600585015460068601546007870180546001600160a01b039097169995989597949095169592949193909290919061131f9061357a565b80601f016020809104026020016040519081016040528092919081815260200182805461134b9061357a565b80156113985780601f1061136d57610100808354040283529160200191611398565b820191906000526020600020905b81548152906001019060200180831161137b57829003601f168201915b5050505050908060080180546113ad9061357a565b80601f01602080910402602001604051908101604052809291908181526020018280546113d99061357a565b80156114265780601f106113fb57610100808354040283529160200191611426565b820191906000526020600020905b81548152906001019060200180831161140957829003601f168201915b5050505050905089565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6000808080611470602086018661376d565b60ff166002901b90506001548161148791906137a0565b92506002548161149791906137a0565b9150816114aa60608701604088016137ca565b64ffffffffff166114bb91906137a0565b6114c590846137e7565b6114d560408701602088016137ca565b64ffffffffff166114e691906137a0565b6000546114f391906137e7565b9350509193909250565b6115056127d4565b600380546001600160801b031916600160401b6001600160401b039485160267ffffffffffffffff19161791909216179055565b600654604051635f5b248b60e01b81526000916001600160a01b031690635f5b248b9061156c90339085906004016135ed565b602060405180830381865afa158015611589573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ad919061361a565b6115cc5760405163bfc6c33760e01b81523360048201526024016107fc565b86600180600083815260096020526040902060039081015460ff16908111156115f7576115f7613289565b14611632576000828152600960205260409081902060030154905163091e2f1760e31b81526107fc91849160ff9091169084906004016135ae565b6000898152600960205260408120905b60008b8152600a60205260409020548110156116c45760008b8152600a6020526040902080543391908390811061167b5761167b6135d7565b60009182526020909120600590910201546001600160a01b0316036116bc576040516301011bf360e71b8152600481018c90523360248201526044016107fc565b600101611642565b506116d08a828b612361565b60006040518060a00160405280336001600160a01b031681526020018b8152602001600081526020018a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250604080516020601f8b0181900481028201810190925289815291810191908a908a908190840183828082843760009201829052509390945250508d8152600a6020908152604080832080546001808201835591855293839020865160059095020180546001600160a01b0319166001600160a01b03909516949094178455918501519183019190915583015160028201556060830151929350839290915060038201906117df9082613684565b50608082015160048201906117f49082613684565b50506040513391508c907f6c809136a3b8faf74ae9e955b7e7b758baa66bde976764a29fa74a4eb1e3702e90600090a36002820154600160301b900464ffffffffff1660000361184c5761184c338360040154612877565b600282015460008c8152600a602052604090205461010090910464ffffffffff16148015611913576002830154600160301b900464ffffffffff166000036118d1576003838101805460ff19168217905560018085015460405190928f92600080516020613a3e833981519152926118c49290613743565b60405180910390a3611913565b60038301805460ff1916600290811790915560018085015460405190928f92600080516020613a3e8339815191529261190a9290613743565b60405180910390a35b505050505050505050505050565b6119296127d4565b81600461193682826137fa565b50819050600561194682826137fa565b50505050565b6119546127d4565b600092909255600155600255565b61196a6127d4565b6007546001600160a01b031663a9059cbb611983611430565b6007546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156119cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ef919061387f565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611a3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5e919061361a565b50565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b0316600081158015611aa65750825b90506000826001600160401b03166001148015611ac25750303b155b905081158015611ad0575080155b15611aee5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315611b1857845460ff60401b1916600160401b1785555b611b2133612970565b611b2c888888612981565b600680546001600160a01b03808d166001600160a01b03199283161790925560078054928c169290911691909117905560016008558315611ba757845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b600454600090829060ff16611bcb602083018361376d565b60ff161080611bed575060055460ff16611be8602083018361376d565b60ff16115b15611c3857611bff602082018261376d565b600480546005546040516371a6675960e11b815260ff9485169381019390935290831660248301529190911660448201526064016107fc565b600454610100900464ffffffffff16611c5760408301602084016137ca565b64ffffffffff161080611c8d5750600554610100900464ffffffffff16611c8460408301602084016137ca565b64ffffffffff16115b15611ce557611ca260408201602083016137ca565b600480546005546040516371a6675960e11b815264ffffffffff9485169381019390935261010091829004841660248401520490911660448201526064016107fc565b600454600160301b900464ffffffffff16611d0660608301604084016137ca565b64ffffffffff161080611d3e5750600554600160301b900464ffffffffff16611d3560608301604084016137ca565b64ffffffffff16115b15611d9857611d5360608201604083016137ca565b600480546005546040516371a6675960e11b815264ffffffffff94851693810193909352600160301b91829004841660248401520490911660448201526064016107fc565b6000806000611da68661145e565b600754604051636eb1769f60e11b815233600482015230602482015293965091945092506000916001600160a01b039091169063dd62ed3e90604401602060405180830381865afa158015611dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e23919061387f565b905083811015611e50576040516311e9ebaf60e31b815260048101829052602481018590526044016107fc565b6007546040516370a0823160e01b81523360048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611e99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebd919061387f565b905084811015611eea576040516311e9ebaf60e31b815260048101829052602481018690526044016107fc565b6007546040516323b872dd60e01b8152336004820152306024820152604481018790526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611f41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f65919061361a565b5060088054600181019091556040518c90339083907f7f371482986a3450b759cc4a079353a8eaa36a650b5eba1fb9c00693026f254a90600090a46040805161012081018252338152602081018e9052908101611fc7368c90038c018c613898565b81526020016001815260200186815260200185815260200160005481526020018c81526020018b8152506009600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015560408201518160020160008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548164ffffffffff021916908364ffffffffff16021790555060408201518160000160066101000a81548164ffffffffff021916908364ffffffffff160217905550505060608201518160030160006101000a81548160ff021916908360038111156120e3576120e3613289565b02179055506080820151600482015560a0820151600582015560c0820151600682015560e0820151600782019061211a9082613684565b5061010082015160088201906121309082613684565b509050508b81600080516020613a3e83398151915260006001604051612157929190613743565b60405180910390a39b9a5050505050505050505050565b6121766127d4565b6001600160a01b0381166121a057604051631e4fbdf760e01b8152600060048201526024016107fc565b611a5e81612806565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148061223057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316612224600080516020613a5e833981519152546001600160a01b031690565b6001600160a01b031614155b156110d35760405163703e46dd60e11b815260040160405180910390fd5b611a5e6127d4565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156122b0575060408051601f3d908101601f191682019092526122ad9181019061387f565b60015b6122d857604051634c9c8ce360e01b81526001600160a01b03831660048201526024016107fc565b600080516020613a5e833981519152811461230957604051632a87526960e21b8152600481018290526024016107fc565b6123138383612a13565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146110d35760405163703e46dd60e11b815260040160405180910390fd5b815460405160009161238c91869160078701916001600160a01b039091169033908790602001613909565b60408051601f1981840301815291905260028401548151602083012091925060001960ff9091161c1015611946576040516306427aeb60e01b815260048101859052602481018390526044016107fc565b6000818152600960205260408120905b6002820154610100900464ffffffffff1681101561263b576002820154600090600160301b900464ffffffffff166001600160401b038111156124325761243261303b565b60405190808252806020026020018201604052801561245b578160200160208202803683370190505b50905060005b6002840154600160301b900464ffffffffff168110156124ed576000858152600b6020526040902080548290811061249b5761249b6135d7565b906000526020600020906004020160020183815481106124bd576124bd6135d7565b90600052602060002001548282815181106124da576124da6135d7565b6020908102919091010152600101612461565b506000806124fa83612a69565b9150915060008060005b6002880154600160301b900464ffffffffff168110156125d5576000868281518110612532576125326135d7565b60200260200101519050858561254891906139d3565b8110158015612560575061255c86866137e7565b8111155b156125cc5761256f81856137e7565b93508261257b816139e6565b9350506125cc600b60008c815260200190815260200160002083815481106125a5576125a56135d7565b600091825260209091206004909102015460058b01546001600160a01b0390911690612877565b50600101612504565b50600081156125ed576125e882846139ff565b6125f0565b60005b60008a8152600a602052604090208054919250829189908110612615576126156135d7565b60009182526020909120600260059092020101555050600190940193506123ed92505050565b506002810154600090610100900464ffffffffff166001600160401b038111156126675761266761303b565b604051908082528060200260200182016040528015612690578160200160208202803683370190505b50905060005b6002830154610100900464ffffffffff16811015612705576000848152600a602052604090208054829081106126ce576126ce6135d7565b9060005260206000209060050201600201548282815181106126f2576126f26135d7565b6020908102919091010152600101612696565b5060008061271283612a69565b9150915060005b6002850154610100900464ffffffffff168110156127cc5760035461274f908490600160401b90046001600160401b03166137a0565b61275990836139d3565b84828151811061276b5761276b6135d7565b6020026020010151106127c4576000868152600a6020526040902080546127c491908390811061279d5761279d6135d7565b600091825260209091206005909102015460048701546001600160a01b0390911690612877565b600101612719565b505050505050565b336127dd611430565b6001600160a01b0316146110d35760405163118cdaa760e01b81523360048201526024016107fc565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b600754604051636eb1769f60e11b81523060048201526001600160a01b0384811660248301529091169063095ea7b39084908490849063dd62ed3e90604401602060405180830381865afa1580156128d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f7919061387f565b61290191906137e7565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561294c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612313919061361a565b612978612a91565b611a5e81612ada565b612989612a91565b60408051606080820183526001808352602080840191909152600092840192909252600480546101016affffffffffffffffffffff199182161790915583519182018452600a80835292820183905292015260058054909116660a000000000a0a179055600380546001600160801b0319166801000000000000000217905561231383838361194c565b612a1c82612ae2565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115612a61576123138282612b47565b610c7d612bbf565b600080600080612a7885612bde565b91509150809250612a8882612c56565b93505050915091565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166110d357604051631afcd79f60e31b815260040160405180910390fd5b612176612a91565b806001600160a01b03163b600003612b1857604051634c9c8ce360e01b81526001600160a01b03821660048201526024016107fc565b600080516020613a5e83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051612b649190613a21565b600060405180830381855af49150503d8060008114612b9f576040519150601f19603f3d011682016040523d82523d6000602084013e612ba4565b606091505b5091509150612bb4858383612caf565b925050505b92915050565b34156110d35760405163b398979f60e01b815260040160405180910390fd5b600080612bea83612d0e565b90506000805b8451811015612c4157600083868381518110612c0e57612c0e6135d7565b6020026020010151612c2091906139d3565b9050612c2c81806137a0565b612c3690846137e7565b925050600101612bf0565b508351612c4e90826139ff565b925050915091565b6000806002612c668460016137e7565b612c7091906139ff565b90508291505b81811015612ca957905080600281612c8e81866139ff565b612c9891906137e7565b612ca291906139ff565b9050612c76565b50919050565b606082612cc457612cbf82612d58565b612d07565b8151158015612cdb57506001600160a01b0384163b155b15612d0457604051639996b31560e01b81526001600160a01b03851660048201526024016107fc565b50805b9392505050565b600080805b8351811015612d4b57838181518110612d2e57612d2e6135d7565b602002602001015182612d4191906137e7565b9150600101612d13565b508251612d0790826139ff565b805115612d685780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b828054828255906000526020600020908101928215612dbc579160200282015b82811115612dbc578251825591602001919060010190612da1565b50612dc8929150612dcc565b5090565b5b80821115612dc85760008155600101612dcd565b60008060408385031215612df457600080fd5b50508035926020909101359150565b60005b83811015612e1e578181015183820152602001612e06565b50506000910152565b60008151808452612e3f816020860160208601612e03565b601f01601f19169290920160200192915050565b60018060a01b038616815284602082015283604082015260a060608201526000612e8060a0830185612e27565b8281036080840152612e928185612e27565b98975050505050505050565b600060208284031215612eb057600080fd5b5035919050565b60018060a01b03815116825260208101516020830152604081015160408301526000606082015160a06060850152612ef260a0850182612e27565b905060808301518482036080860152612bb48282612e27565b602081526000612d076020830184612eb7565b600060208083018184528085518083526040925060408601915060408160051b8701018488016000805b84811015612fe057898403603f19018652825180516001600160a01b031685528881015189860152878101516080898701819052815190870181905260a08701918b019085905b80821015612faf5782518452928c0192918c019160019190910190612f8f565b50505060608083015192508682038188015250612fcc8183612e27565b978a01979550505091870191600101612f48565b50919998505050505050505050565b60018060a01b03841681528260208201526060604082015260006130166060830184612e27565b95945050505050565b80356001600160a01b038116811461303657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261306257600080fd5b81356001600160401b038082111561307c5761307c61303b565b604051601f8301601f19908116603f011681019082821181831017156130a4576130a461303b565b816040528381528660208588010111156130bd57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156130f057600080fd5b6130f98361301f565b915060208301356001600160401b0381111561311457600080fd5b61312085828601613051565b9150509250929050565b60008083601f84011261313c57600080fd5b5081356001600160401b0381111561315357600080fd5b60208301915083602082850101111561316b57600080fd5b9250929050565b6000806000806000806080878903121561318b57600080fd5b863595506020870135945060408701356001600160401b03808211156131b057600080fd5b818901915089601f8301126131c457600080fd5b8135818111156131d357600080fd5b8a60208260051b85010111156131e857600080fd5b60208301965080955050606089013591508082111561320657600080fd5b5061321389828a0161312a565b979a9699509497509295939492505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561327c57603f1988860301845261326a858351612eb7565b9450928501929085019060010161324e565b5092979650505050505050565b634e487b7160e01b600052602160045260246000fd5b600481106132af576132af613289565b9052565b6001600160a01b038a16815260208082018a9052885160ff166040808401919091529089015164ffffffffff908116606084015290890151166080820152600061016061330360a084018a61329f565b8760c08401528660e0840152856101008401528061012084015261332981840186612e27565b905082810361014084015261333e8185612e27565b9c9b505050505050505050505050565b602081526000612d076020830184612e27565b600060608284031215612ca957600080fd5b60006060828403121561338557600080fd5b612d078383613361565b80356001600160401b038116811461303657600080fd5b600080604083850312156133b957600080fd5b6133c28361338f565b91506133d06020840161338f565b90509250929050565b600080600080600080608087890312156133f257600080fd5b863595506020870135945060408701356001600160401b038082111561341757600080fd5b6134238a838b0161312a565b9096509450606089013591508082111561320657600080fd5b60008060c0838503121561344f57600080fd5b6134598484613361565b91506133d08460608501613361565b60008060006060848603121561347d57600080fd5b505081359360208301359350604090920135919050565b600080600080600060a086880312156134ac57600080fd5b6134b58661301f565b94506134c36020870161301f565b94979496505050506040830135926060810135926080909101359150565b60008060008060c085870312156134f757600080fd5b8435935060208501356001600160401b038082111561351557600080fd5b61352188838901613051565b9450604087013591508082111561353757600080fd5b5061354487828801613051565b9250506135548660608701613361565b905092959194509250565b60006020828403121561357157600080fd5b612d078261301f565b600181811c9082168061358e57607f821691505b602082108103612ca957634e487b7160e01b600052602260045260246000fd5b838152606081016135c2602083018561329f565b6135cf604083018461329f565b949350505050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0383168152604081016002831061360d5761360d613289565b8260208301529392505050565b60006020828403121561362c57600080fd5b81518015158114612d0757600080fd5b601f821115612313576000816000526020600020601f850160051c810160208610156136655750805b601f850160051c820191505b818110156127cc57828155600101613671565b81516001600160401b0381111561369d5761369d61303b565b6136b1816136ab845461357a565b8461363c565b602080601f8311600181146136e657600084156136ce5750858301515b600019600386901b1c1916600185901b1785556127cc565b600085815260208120601f198616915b82811015613715578886015182559484019460019091019084016136f6565b50858210156137335787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60408101613751828561329f565b612d07602083018461329f565b60ff81168114611a5e57600080fd5b60006020828403121561377f57600080fd5b8135612d078161375e565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417612bb957612bb961378a565b64ffffffffff81168114611a5e57600080fd5b6000602082840312156137dc57600080fd5b8135612d07816137b7565b80820180821115612bb957612bb961378a565b81356138058161375e565b60ff8116905081548160ff1982161783556020840135613824816137b7565b65ffffffffff008160081b169050808365ffffffffffff198416171784556040850135613850816137b7565b6affffffffff0000000000008160301b16846affffffffffffffffffffff198516178317178555505050505050565b60006020828403121561389157600080fd5b5051919050565b6000606082840312156138aa57600080fd5b604051606081018181106001600160401b03821117156138cc576138cc61303b565b60405282356138da8161375e565b815260208301356138ea816137b7565b602082015260408301356138fd816137b7565b60408201529392505050565b858152600060206000875461391d8161357a565b60018281168015613935576001811461394e5761397e565b60ff19841688870152821515830288018601945061397e565b8b6000528560002060005b848110156139745781548a8201890152908301908701613959565b5050858389010194505b5050505061399d818860601b6bffffffffffffffffffffffff19169052565b6139bb601482018760601b6bffffffffffffffffffffffff19169052565b84602882015260488101925050509695505050505050565b81810381811115612bb957612bb961378a565b6000600182016139f8576139f861378a565b5060010190565b600082613a1c57634e487b7160e01b600052601260045260246000fd5b500490565b60008251613a33818460208701612e03565b919091019291505056fe1c0a5e4b371d60717068c91e93b5e94c91d4c6d6c3fab36082a78f987e5a69f5360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220f26ebe49138ca2fecd8d7751eff91712f900d80614eaaac152ac83eb1a19781564736f6c63430008180033", - "linkReferences": {}, - "deployedLinkReferences": {} -} +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "oracle", + "type": "address" + } + ], + "name": "AlreadyResponded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "ERC1967InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "ERC1967NonPayable", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "have", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "want", + "type": "uint256" + } + ], + "name": "InsufficientFees", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "have", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "InvalidParameterRange", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "internalType": "enum LLMOracleTask.TaskStatus", + "name": "have", + "type": "uint8" + }, + { + "internalType": "enum LLMOracleTask.TaskStatus", + "name": "want", + "type": "uint8" + } + ], + "name": "InvalidTaskStatus", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "InvalidValidation", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "oracle", + "type": "address" + } + ], + "name": "NotRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [], + "name": "UUPSUnauthorizedCallContext", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "slot", + "type": "bytes32" + } + ], + "name": "UUPSUnsupportedProxiableUUID", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "protocol", + "type": "bytes32" + } + ], + "name": "Request", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "responder", + "type": "address" + } + ], + "name": "Response", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "protocol", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "enum LLMOracleTask.TaskStatus", + "name": "statusBefore", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "enum LLMOracleTask.TaskStatus", + "name": "statusAfter", + "type": "uint8" + } + ], + "name": "StatusUpdate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + } + ], + "name": "Validation", + "type": "event" + }, + { + "inputs": [], + "name": "UPGRADE_INTERFACE_VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeToken", + "outputs": [ + { + "internalType": "contract ERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "generationDeviationFactor", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "generationFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + } + ], + "name": "getBestResponse", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "responder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "score", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct LLMOracleTask.TaskResponse", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "difficulty", + "type": "uint8" + }, + { + "internalType": "uint40", + "name": "numGenerations", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "numValidations", + "type": "uint40" + } + ], + "internalType": "struct LLMOracleTaskParameters", + "name": "parameters", + "type": "tuple" + } + ], + "name": "getFee", + "outputs": [ + { + "internalType": "uint256", + "name": "totalFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "generatorFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "validatorFee", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + } + ], + "name": "getResponses", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "responder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "score", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct LLMOracleTask.TaskResponse[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + } + ], + "name": "getValidations", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "scores", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct LLMOracleTask.TaskValidation[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_oracleRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "_feeToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_platformFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_generationFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_validationFee", + "type": "uint256" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "nextTaskId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "platformFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxiableUUID", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "registry", + "outputs": [ + { + "internalType": "contract LLMOracleRegistry", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "protocol", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "input", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "models", + "type": "bytes" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "difficulty", + "type": "uint8" + }, + { + "internalType": "uint40", + "name": "numGenerations", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "numValidations", + "type": "uint40" + } + ], + "internalType": "struct LLMOracleTaskParameters", + "name": "parameters", + "type": "tuple" + } + ], + "name": "request", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + } + ], + "name": "requests", + "outputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "protocol", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "difficulty", + "type": "uint8" + }, + { + "internalType": "uint40", + "name": "numGenerations", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "numValidations", + "type": "uint40" + } + ], + "internalType": "struct LLMOracleTaskParameters", + "name": "parameters", + "type": "tuple" + }, + { + "internalType": "enum LLMOracleTask.TaskStatus", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "generatorFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "validatorFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "platformFee", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "input", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "models", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "name": "respond", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "responses", + "outputs": [ + { + "internalType": "address", + "name": "responder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "score", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "output", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_generationDeviationFactor", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "_validationDeviationFactor", + "type": "uint64" + } + ], + "name": "setDeviationFactors", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_platformFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_generationFee", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_validationFee", + "type": "uint256" + } + ], + "name": "setFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint8", + "name": "difficulty", + "type": "uint8" + }, + { + "internalType": "uint40", + "name": "numGenerations", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "numValidations", + "type": "uint40" + } + ], + "internalType": "struct LLMOracleTaskParameters", + "name": "minimums", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint8", + "name": "difficulty", + "type": "uint8" + }, + { + "internalType": "uint40", + "name": "numGenerations", + "type": "uint40" + }, + { + "internalType": "uint40", + "name": "numValidations", + "type": "uint40" + } + ], + "internalType": "struct LLMOracleTaskParameters", + "name": "maximums", + "type": "tuple" + } + ], + "name": "setParameters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "scores", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "name": "validate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "validationDeviationFactor", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "validationFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "taskId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "validations", + "outputs": [ + { + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawPlatformFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/contracts/abi/LLMOracleRegistry.json b/src/contracts/abi/LLMOracleRegistry.json index dc5bfc3..bead96d 100644 --- a/src/contracts/abi/LLMOracleRegistry.json +++ b/src/contracts/abi/LLMOracleRegistry.json @@ -1,462 +1,414 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "LLMOracleRegistry", - "sourceName": "contracts/llm/LLMOracleRegistry.sol", - "abi": [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "target", - "type": "address" - } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "AlreadyRegistered", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "ERC1967InvalidImplementation", - "type": "error" - }, - { - "inputs": [], - "name": "ERC1967NonPayable", - "type": "error" - }, - { - "inputs": [], - "name": "FailedInnerCall", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientFunds", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidInitialization", - "type": "error" - }, - { - "inputs": [], - "name": "NotInitializing", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "NotRegistered", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "OwnableInvalidOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "OwnableUnauthorizedAccount", - "type": "error" - }, - { - "inputs": [], - "name": "UUPSUnauthorizedCallContext", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "slot", - "type": "bytes32" - } - ], - "name": "UUPSUnsupportedProxiableUUID", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "", - "type": "address" - }, - { - "indexed": false, - "internalType": "enum LLMOracleKind", - "name": "kind", - "type": "uint8" - } - ], - "name": "Registered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "", - "type": "address" - }, - { - "indexed": false, - "internalType": "enum LLMOracleKind", - "name": "kind", - "type": "uint8" - } - ], - "name": "Unregistered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "inputs": [], - "name": "UPGRADE_INTERFACE_VERSION", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "generatorStakeAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "enum LLMOracleKind", - "name": "kind", - "type": "uint8" - } - ], - "name": "getStakeAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_generatorStakeAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_validatorStakeAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "_token", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "enum LLMOracleKind", - "name": "kind", - "type": "uint8" - } - ], - "name": "isRegistered", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "enum LLMOracleKind", - "name": "kind", - "type": "uint8" - } - ], - "name": "register", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "oracle", - "type": "address" - }, - { - "internalType": "enum LLMOracleKind", - "name": "", - "type": "uint8" - } - ], - "name": "registrations", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_generatorStakeAmount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_validatorStakeAmount", - "type": "uint256" - } - ], - "name": "setStakeAmounts", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "token", - "outputs": [ - { - "internalType": "contract ERC20", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "enum LLMOracleKind", - "name": "kind", - "type": "uint8" - } - ], - "name": "unregister", - "outputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "validatorStakeAmount", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "bytecode": "0x60a06040523060805234801561001457600080fd5b5061001d610022565b6100d4565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100725760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100d15780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6080516111496100fd60003960008181610970015281816109990152610adf01526111496000f3fe6080604052600436106100f35760003560e01c80638da5cb5b1161008a578063eea5353d11610059578063eea5353d146102d7578063f149444b146102ed578063f2fde38b1461030d578063fc0c546a1461032d57600080fd5b80638da5cb5b14610212578063a6ab36f214610263578063ad3cb1cc14610283578063ee12a7a0146102c157600080fd5b806361d689fa116100c657806361d689fa14610185578063715018a6146101a5578063771007a9146101ba57806381e1c6ca146101da57600080fd5b806323d2f5f6146100f85780634f1ef2861461012b57806352d1902d146101405780635f5b248b14610155575b600080fd5b34801561010457600080fd5b50610118610113366004610e37565b61034d565b6040519081526020015b60405180910390f35b61013e610139366004610e7f565b61053c565b005b34801561014c57600080fd5b5061011861055b565b34801561016157600080fd5b50610175610170366004610f41565b610578565b6040519015158152602001610122565b34801561019157600080fd5b5061013e6101a0366004610e37565b6105d0565b3480156101b157600080fd5b5061013e61079f565b3480156101c657600080fd5b506101186101d5366004610e37565b6107b3565b3480156101e657600080fd5b506101186101f5366004610f41565b600260209081526000928352604080842090915290825290205481565b34801561021e57600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03165b6040516001600160a01b039091168152602001610122565b34801561026f57600080fd5b5061013e61027e366004610f74565b6107dd565b34801561028f57600080fd5b506102b4604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101229190610fcd565b3480156102cd57600080fd5b5061011860005481565b3480156102e357600080fd5b5061011860015481565b3480156102f957600080fd5b5061013e610308366004611000565b610914565b34801561031957600080fd5b5061013e610328366004611022565b610927565b34801561033957600080fd5b5060035461024b906001600160a01b031681565b3360009081526002602052604081208183600181111561036f5761036f61103d565b60018111156103805761038061103d565b8152602001908152602001600020549050806000036103b95760405163bfc6c33760e01b81523360048201526024015b60405180910390fd5b336000908152600260205260408120908360018111156103db576103db61103d565b60018111156103ec576103ec61103d565b815260200190815260200160002060009055336001600160a01b03167feebfdaadda46c435881bbe8bac1fc3974f3323b1c809c7aabd37ae7b83ca4442836040516104379190611053565b60405180910390a2600354604051636eb1769f60e11b815230600482015233602482018190526001600160a01b039092169163095ea7b3918490849063dd62ed3e90604401602060405180830381865afa158015610499573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104bd919061107b565b6104c79190611094565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610512573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053691906110b5565b50919050565b610544610965565b61054d82610a0a565b6105578282610a12565b5050565b6000610565610ad4565b506000805160206110f483398151915290565b6001600160a01b0382166000908152600260205260408120818360018111156105a3576105a361103d565b60018111156105b4576105b461103d565b8152602001908152602001600020546000141590505b92915050565b60006105db826107b3565b90506105e73383610578565b15610607576040516345ed80e960e01b81523360048201526024016103b0565b600354604051636eb1769f60e11b815233600482015230602482015282916001600160a01b03169063dd62ed3e90604401602060405180830381865afa158015610655573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610679919061107b565b10156106985760405163356680b760e01b815260040160405180910390fd5b6003546040516323b872dd60e01b8152336004820152306024820152604481018390526001600160a01b03909116906323b872dd906064016020604051808303816000875af11580156106ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071391906110b5565b5033600090815260026020526040812082918460018111156107375761073761103d565b60018111156107485761074861103d565b815260200190815260200160002081905550336001600160a01b03167f89b4e995568c900aa52376cbed225dc1a013c9a43cb58186d69676ff593d7c4e836040516107939190611053565b60405180910390a25050565b6107a7610b1d565b6107b16000610b78565b565b6000808260018111156107c8576107c861103d565b146107d5576001546105ca565b505060005490565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156108235750825b905060008267ffffffffffffffff1660011480156108405750303b155b90508115801561084e575080155b1561086c5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561089657845460ff60401b1916600160401b1785555b61089f33610be9565b60008890556001879055600380546001600160a01b0319166001600160a01b038816179055831561090a57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b61091c610b1d565b600091909155600155565b61092f610b1d565b6001600160a01b03811661095957604051631e4fbdf760e01b8152600060048201526024016103b0565b61096281610b78565b50565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806109ec57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166109e06000805160206110f4833981519152546001600160a01b031690565b6001600160a01b031614155b156107b15760405163703e46dd60e11b815260040160405180910390fd5b610962610b1d565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610a6c575060408051601f3d908101601f19168201909252610a699181019061107b565b60015b610a9457604051634c9c8ce360e01b81526001600160a01b03831660048201526024016103b0565b6000805160206110f48339815191528114610ac557604051632a87526960e21b8152600481018290526024016103b0565b610acf8383610bfa565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107b15760405163703e46dd60e11b815260040160405180910390fd5b33610b4f7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146107b15760405163118cdaa760e01b81523360048201526024016103b0565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b610bf1610c50565b61096281610c99565b610c0382610ca1565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115610c4857610acf8282610d06565b610557610d7c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166107b157604051631afcd79f60e31b815260040160405180910390fd5b61092f610c50565b806001600160a01b03163b600003610cd757604051634c9c8ce360e01b81526001600160a01b03821660048201526024016103b0565b6000805160206110f483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051610d2391906110d7565b600060405180830381855af49150503d8060008114610d5e576040519150601f19603f3d011682016040523d82523d6000602084013e610d63565b606091505b5091509150610d73858383610d9b565b95945050505050565b34156107b15760405163b398979f60e01b815260040160405180910390fd5b606082610db057610dab82610dfa565b610df3565b8151158015610dc757506001600160a01b0384163b155b15610df057604051639996b31560e01b81526001600160a01b03851660048201526024016103b0565b50805b9392505050565b805115610e0a5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b803560028110610e3257600080fd5b919050565b600060208284031215610e4957600080fd5b610df382610e23565b80356001600160a01b0381168114610e3257600080fd5b634e487b7160e01b600052604160045260246000fd5b60008060408385031215610e9257600080fd5b610e9b83610e52565b9150602083013567ffffffffffffffff80821115610eb857600080fd5b818501915085601f830112610ecc57600080fd5b813581811115610ede57610ede610e69565b604051601f8201601f19908116603f01168101908382118183101715610f0657610f06610e69565b81604052828152886020848701011115610f1f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008060408385031215610f5457600080fd5b610f5d83610e52565b9150610f6b60208401610e23565b90509250929050565b600080600060608486031215610f8957600080fd5b8335925060208401359150610fa060408501610e52565b90509250925092565b60005b83811015610fc4578181015183820152602001610fac565b50506000910152565b6020815260008251806020840152610fec816040850160208701610fa9565b601f01601f19169190910160400192915050565b6000806040838503121561101357600080fd5b50508035926020909101359150565b60006020828403121561103457600080fd5b610df382610e52565b634e487b7160e01b600052602160045260246000fd5b602081016002831061107557634e487b7160e01b600052602160045260246000fd5b91905290565b60006020828403121561108d57600080fd5b5051919050565b808201808211156105ca57634e487b7160e01b600052601160045260246000fd5b6000602082840312156110c757600080fd5b81518015158114610df357600080fd5b600082516110e9818460208701610fa9565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212209b80aef4da99e891254582b6c889f016bc5726c7b4285a80c3f7ed0a16599c6364736f6c63430008180033", - "deployedBytecode": "0x6080604052600436106100f35760003560e01c80638da5cb5b1161008a578063eea5353d11610059578063eea5353d146102d7578063f149444b146102ed578063f2fde38b1461030d578063fc0c546a1461032d57600080fd5b80638da5cb5b14610212578063a6ab36f214610263578063ad3cb1cc14610283578063ee12a7a0146102c157600080fd5b806361d689fa116100c657806361d689fa14610185578063715018a6146101a5578063771007a9146101ba57806381e1c6ca146101da57600080fd5b806323d2f5f6146100f85780634f1ef2861461012b57806352d1902d146101405780635f5b248b14610155575b600080fd5b34801561010457600080fd5b50610118610113366004610e37565b61034d565b6040519081526020015b60405180910390f35b61013e610139366004610e7f565b61053c565b005b34801561014c57600080fd5b5061011861055b565b34801561016157600080fd5b50610175610170366004610f41565b610578565b6040519015158152602001610122565b34801561019157600080fd5b5061013e6101a0366004610e37565b6105d0565b3480156101b157600080fd5b5061013e61079f565b3480156101c657600080fd5b506101186101d5366004610e37565b6107b3565b3480156101e657600080fd5b506101186101f5366004610f41565b600260209081526000928352604080842090915290825290205481565b34801561021e57600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b03165b6040516001600160a01b039091168152602001610122565b34801561026f57600080fd5b5061013e61027e366004610f74565b6107dd565b34801561028f57600080fd5b506102b4604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101229190610fcd565b3480156102cd57600080fd5b5061011860005481565b3480156102e357600080fd5b5061011860015481565b3480156102f957600080fd5b5061013e610308366004611000565b610914565b34801561031957600080fd5b5061013e610328366004611022565b610927565b34801561033957600080fd5b5060035461024b906001600160a01b031681565b3360009081526002602052604081208183600181111561036f5761036f61103d565b60018111156103805761038061103d565b8152602001908152602001600020549050806000036103b95760405163bfc6c33760e01b81523360048201526024015b60405180910390fd5b336000908152600260205260408120908360018111156103db576103db61103d565b60018111156103ec576103ec61103d565b815260200190815260200160002060009055336001600160a01b03167feebfdaadda46c435881bbe8bac1fc3974f3323b1c809c7aabd37ae7b83ca4442836040516104379190611053565b60405180910390a2600354604051636eb1769f60e11b815230600482015233602482018190526001600160a01b039092169163095ea7b3918490849063dd62ed3e90604401602060405180830381865afa158015610499573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104bd919061107b565b6104c79190611094565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610512573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053691906110b5565b50919050565b610544610965565b61054d82610a0a565b6105578282610a12565b5050565b6000610565610ad4565b506000805160206110f483398151915290565b6001600160a01b0382166000908152600260205260408120818360018111156105a3576105a361103d565b60018111156105b4576105b461103d565b8152602001908152602001600020546000141590505b92915050565b60006105db826107b3565b90506105e73383610578565b15610607576040516345ed80e960e01b81523360048201526024016103b0565b600354604051636eb1769f60e11b815233600482015230602482015282916001600160a01b03169063dd62ed3e90604401602060405180830381865afa158015610655573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610679919061107b565b10156106985760405163356680b760e01b815260040160405180910390fd5b6003546040516323b872dd60e01b8152336004820152306024820152604481018390526001600160a01b03909116906323b872dd906064016020604051808303816000875af11580156106ef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071391906110b5565b5033600090815260026020526040812082918460018111156107375761073761103d565b60018111156107485761074861103d565b815260200190815260200160002081905550336001600160a01b03167f89b4e995568c900aa52376cbed225dc1a013c9a43cb58186d69676ff593d7c4e836040516107939190611053565b60405180910390a25050565b6107a7610b1d565b6107b16000610b78565b565b6000808260018111156107c8576107c861103d565b146107d5576001546105ca565b505060005490565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156108235750825b905060008267ffffffffffffffff1660011480156108405750303b155b90508115801561084e575080155b1561086c5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561089657845460ff60401b1916600160401b1785555b61089f33610be9565b60008890556001879055600380546001600160a01b0319166001600160a01b038816179055831561090a57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b61091c610b1d565b600091909155600155565b61092f610b1d565b6001600160a01b03811661095957604051631e4fbdf760e01b8152600060048201526024016103b0565b61096281610b78565b50565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806109ec57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166109e06000805160206110f4833981519152546001600160a01b031690565b6001600160a01b031614155b156107b15760405163703e46dd60e11b815260040160405180910390fd5b610962610b1d565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610a6c575060408051601f3d908101601f19168201909252610a699181019061107b565b60015b610a9457604051634c9c8ce360e01b81526001600160a01b03831660048201526024016103b0565b6000805160206110f48339815191528114610ac557604051632a87526960e21b8152600481018290526024016103b0565b610acf8383610bfa565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107b15760405163703e46dd60e11b815260040160405180910390fd5b33610b4f7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146107b15760405163118cdaa760e01b81523360048201526024016103b0565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b610bf1610c50565b61096281610c99565b610c0382610ca1565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115610c4857610acf8282610d06565b610557610d7c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166107b157604051631afcd79f60e31b815260040160405180910390fd5b61092f610c50565b806001600160a01b03163b600003610cd757604051634c9c8ce360e01b81526001600160a01b03821660048201526024016103b0565b6000805160206110f483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b031684604051610d2391906110d7565b600060405180830381855af49150503d8060008114610d5e576040519150601f19603f3d011682016040523d82523d6000602084013e610d63565b606091505b5091509150610d73858383610d9b565b95945050505050565b34156107b15760405163b398979f60e01b815260040160405180910390fd5b606082610db057610dab82610dfa565b610df3565b8151158015610dc757506001600160a01b0384163b155b15610df057604051639996b31560e01b81526001600160a01b03851660048201526024016103b0565b50805b9392505050565b805115610e0a5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b803560028110610e3257600080fd5b919050565b600060208284031215610e4957600080fd5b610df382610e23565b80356001600160a01b0381168114610e3257600080fd5b634e487b7160e01b600052604160045260246000fd5b60008060408385031215610e9257600080fd5b610e9b83610e52565b9150602083013567ffffffffffffffff80821115610eb857600080fd5b818501915085601f830112610ecc57600080fd5b813581811115610ede57610ede610e69565b604051601f8201601f19908116603f01168101908382118183101715610f0657610f06610e69565b81604052828152886020848701011115610f1f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60008060408385031215610f5457600080fd5b610f5d83610e52565b9150610f6b60208401610e23565b90509250929050565b600080600060608486031215610f8957600080fd5b8335925060208401359150610fa060408501610e52565b90509250925092565b60005b83811015610fc4578181015183820152602001610fac565b50506000910152565b6020815260008251806020840152610fec816040850160208701610fa9565b601f01601f19169190910160400192915050565b6000806040838503121561101357600080fd5b50508035926020909101359150565b60006020828403121561103457600080fd5b610df382610e52565b634e487b7160e01b600052602160045260246000fd5b602081016002831061107557634e487b7160e01b600052602160045260246000fd5b91905290565b60006020828403121561108d57600080fd5b5051919050565b808201808211156105ca57634e487b7160e01b600052601160045260246000fd5b6000602082840312156110c757600080fd5b81518015158114610df357600080fd5b600082516110e9818460208701610fa9565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212209b80aef4da99e891254582b6c889f016bc5726c7b4285a80c3f7ed0a16599c6364736f6c63430008180033", - "linkReferences": {}, - "deployedLinkReferences": {} -} +[ + { "type": "constructor", "inputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "addToWhitelist", + "inputs": [ + { "name": "accounts", "type": "address[]", "internalType": "address[]" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "generatorStakeAmount", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getStakeAmount", + "inputs": [ + { + "name": "kind", + "type": "uint8", + "internalType": "enum LLMOracleKind" + } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "_generatorStakeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_validatorStakeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "_token", "type": "address", "internalType": "address" }, + { + "name": "_minRegistrationTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "isRegistered", + "inputs": [ + { "name": "user", "type": "address", "internalType": "address" }, + { + "name": "kind", + "type": "uint8", + "internalType": "enum LLMOracleKind" + } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "minRegistrationTime", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "register", + "inputs": [ + { + "name": "kind", + "type": "uint8", + "internalType": "enum LLMOracleKind" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "registrationTimes", + "inputs": [ + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "", "type": "uint8", "internalType": "enum LLMOracleKind" } + ], + "outputs": [ + { + "name": "registeredTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "registrations", + "inputs": [ + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "", "type": "uint8", "internalType": "enum LLMOracleKind" } + ], + "outputs": [ + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "removeFromWhitelist", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setStakeAmounts", + "inputs": [ + { + "name": "_generatorStakeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_validatorStakeAmount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "token", + "inputs": [], + "outputs": [ + { "name": "", "type": "address", "internalType": "contract ERC20" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { "name": "newOwner", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unregister", + "inputs": [ + { + "name": "kind", + "type": "uint8", + "internalType": "enum LLMOracleKind" + } + ], + "outputs": [ + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "validatorStakeAmount", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "whitelisted", + "inputs": [{ "name": "", "type": "address", "internalType": "address" }], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "event", + "name": "AddedToWhitelist", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Registered", + "inputs": [ + { + "name": "", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "kind", + "type": "uint8", + "indexed": false, + "internalType": "enum LLMOracleKind" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RemovedFromWhitelist", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unregistered", + "inputs": [ + { + "name": "", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "kind", + "type": "uint8", + "indexed": false, + "internalType": "enum LLMOracleKind" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { "name": "target", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "AlreadyRegistered", + "inputs": [{ "name": "", "type": "address", "internalType": "address" }] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { "type": "error", "name": "ERC1967NonPayable", "inputs": [] }, + { "type": "error", "name": "FailedCall", "inputs": [] }, + { "type": "error", "name": "InsufficientFunds", "inputs": [] }, + { "type": "error", "name": "InvalidInitialization", "inputs": [] }, + { "type": "error", "name": "NotInitializing", "inputs": [] }, + { + "type": "error", + "name": "NotRegistered", + "inputs": [{ "name": "", "type": "address", "internalType": "address" }] + }, + { + "type": "error", + "name": "NotWhitelisted", + "inputs": [ + { "name": "validator", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "OwnableInvalidOwner", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "OwnableUnauthorizedAccount", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "TooEarlyToUnregister", + "inputs": [ + { + "name": "minTimeToWait", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { "type": "error", "name": "UUPSUnauthorizedCallContext", "inputs": [] }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [{ "name": "slot", "type": "bytes32", "internalType": "bytes32" }] + } +] From acef597f4bc11be03962dfb1811b463851a53490 Mon Sep 17 00:00:00 2001 From: erhant Date: Wed, 11 Dec 2024 14:36:31 +0300 Subject: [PATCH 07/14] change binary name --- Cargo.lock | 54 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- Dockerfile | 4 ++-- README.md | 32 ++++++++++++++++---------------- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a2da3e..f254944 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1847,33 +1847,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "dkn-oracle" -version = "0.1.10" -dependencies = [ - "alloy", - "alloy-chains", - "async-trait", - "base64 0.22.1", - "bundlr-sdk", - "bytes 1.9.0", - "clap", - "dkn-workflows", - "dotenvy", - "env_logger 0.11.5", - "eyre", - "futures-util", - "hex", - "hex-literal", - "lazy_static", - "log", - "rand 0.8.5", - "reqwest 0.12.9", - "serde", - "serde_json", - "tokio 1.42.0", -] - [[package]] name = "dkn-utils" version = "0.2.28" @@ -1915,6 +1888,33 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dria-oracle" +version = "0.1.10" +dependencies = [ + "alloy", + "alloy-chains", + "async-trait", + "base64 0.22.1", + "bundlr-sdk", + "bytes 1.9.0", + "clap", + "dkn-workflows", + "dotenvy", + "env_logger 0.11.5", + "eyre", + "futures-util", + "hex", + "hex-literal", + "lazy_static", + "log", + "rand 0.8.5", + "reqwest 0.12.9", + "serde", + "serde_json", + "tokio 1.42.0", +] + [[package]] name = "dtoa" version = "1.0.9" diff --git a/Cargo.toml b/Cargo.toml index fb6e801..3066ed2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "dkn-oracle" +name = "dria-oracle" description = "Dria Knowledge Network Oracle Node" version = "0.1.10" edition = "2021" diff --git a/Dockerfile b/Dockerfile index 3cb4799..6fa19b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,6 @@ RUN cargo build --release # copy release binary to distroless FROM --platform=$BUILDPLATFORM gcr.io/distroless/cc AS gpt -COPY --from=builder /usr/src/app/target/release/dkn-oracle / +COPY --from=builder /usr/src/app/target/release/dria-oracle / -ENTRYPOINT ["./dkn-oracle"] +ENTRYPOINT ["./dria-oracle"] diff --git a/README.md b/README.md index 2606143..b9deb3c 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,10 @@ Install Dria Oracle Node with: cargo install --git https://github.com/firstbatchxyz/dria-oracle-node ``` -This will create a binary called `dkn-oracle`. You can see the available commands with: +This will create a binary called `dria-oracle`. You can see the available commands with: ```sh -dkn-oracle help +dria-oracle help ``` ## Setup @@ -55,13 +55,13 @@ Here is an example: ```sh # 1. Register as both generator and validator -dkn-oracle register generator validator +dria-oracle register generator validator # 2. See that you are registered -dkn-oracle registrations +dria-oracle registrations # 3. Unregister from validator -dkn-oracle unregister validator +dria-oracle unregister validator ``` > [!NOTE] @@ -74,7 +74,7 @@ We launch our node using the `start` command, followed by models of our choice a If we provide no oracle types, it will default to the ones that we are registered to. ```sh -dkn-oracle start -m=gpt-4o-mini -m=llama3.1:latest +dria-oracle start -m=gpt-4o-mini -m=llama3.1:latest ``` You can terminate the application from the terminal as usual (e.g. CTRL+C) to quit the node. @@ -90,17 +90,17 @@ Following the same logic, the Oracle node can read task inputs from Arweave as w You can view the status of a task by its task id: ```sh -dkn-oracle view +dria-oracle view ``` You can also view the task status updates between blocks with the `tasks` command. It accepts `--from` and `--to` arguments to indicate block numbers or tags, defaults from `earliest` block to `latest` block. ```sh -dkn-oracle tasks # earliest to latest -dkn-oracle tasks --from=100 # 100 to latest -dkn-oracle tasks --to=100 # earliest to 100 -dkn-oracle tasks --from=100 --to=200 # 100 to 200 +dria-oracle tasks # earliest to latest +dria-oracle tasks --from=100 # 100 to latest +dria-oracle tasks --to=100 # earliest to 100 +dria-oracle tasks --from=100 --to=200 # 100 to 200 ``` ### Balance & Rewards @@ -108,17 +108,17 @@ dkn-oracle tasks --from=100 --to=200 # 100 to 200 At any time, you can see your balance with: ```sh -dkn-oracle balance +dria-oracle balance ``` As you respond to tasks, you will have rewards available to you. You can see & claim them using your node: ```sh # print rewards -dkn-oracle rewards +dria-oracle rewards # claim all rewards -dkn-oracle claim +dria-oracle claim ``` ### Making a Request @@ -126,13 +126,13 @@ dkn-oracle claim Although the oracle is only supposed to serve requests made from other parties, it is also able to make requests from the CLI. See usage with the help option: ```sh -dkn-oracle request -h +dria-oracle request -h ``` It mainly takes an input argument, followed by multiple model arguments: ```sh -dkn-oracle request "What is 2+2?" gpt-4o-mini phi3:3.8b +dria-oracle request "What is 2+2?" gpt-4o-mini phi3:3.8b ``` The `request` command takes the following options: From 6fb2fd489f86a881128ceeba1525e07044aaa7f4 Mon Sep 17 00:00:00 2001 From: erhant Date: Wed, 11 Dec 2024 14:54:05 +0300 Subject: [PATCH 08/14] change pkg name in tests --- .env.example | 2 +- Makefile | 4 ++-- src/main.rs | 4 ++-- tests/oracle_test.rs | 4 ++-- tests/request_test.rs | 2 +- tests/swan_test.rs | 4 ++-- tests/weth_test.rs | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index 96a053c..8fa1da2 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ RPC_URL=your-rpc-url # Logging level -RUST_LOG=none,dkn_oracle=info +RUST_LOG=none,dria_oracle=info # Your Ethereum wallet for Oracle operations (required) # 32-byte private key, as a hexadecimal string without 0x prefix diff --git a/Makefile b/Makefile index 4c021a9..7d2ef9f 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ run: .PHONY: debug # | Run with crate-level DEBUG logging & info-level workflows debug: - RUST_LOG=none,dkn_oracle=debug,dkn_workflows=debug,ollama_workflows=info cargo run start + RUST_LOG=none,dria_oracle=debug,dkn_workflows=debug,ollama_workflows=info cargo run start ############################################################################### .PHONY: install # | Install to path @@ -44,7 +44,7 @@ version: .PHONY: test # | Run tests test: - RUST_LOG=none,dkn_oracle=info cargo test --all-features + RUST_LOG=none,dria_oracle=info cargo test --all-features ############################################################################### # abi source can be given from outside, and defaults as shown here diff --git a/src/main.rs b/src/main.rs index ba668ac..67c6656 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ async fn main() -> eyre::Result<()> { env_logger::builder() .format_timestamp(Some(env_logger::TimestampPrecision::Millis)) .filter(None, log::LevelFilter::Off) - .filter_module("dkn_oracle", log::LevelFilter::Info) + .filter_module("dria_oracle", log::LevelFilter::Info) .filter_module("dkn_workflows", log::LevelFilter::Info) .parse_default_env() // reads RUST_LOG variable .init(); @@ -17,7 +17,7 @@ async fn main() -> eyre::Result<()> { } // launch CLI - dkn_oracle::cli().await?; + dria_oracle::cli().await?; log::info!("Bye!"); Ok(()) diff --git a/tests/oracle_test.rs b/tests/oracle_test.rs index 9981cc8..d12d609 100644 --- a/tests/oracle_test.rs +++ b/tests/oracle_test.rs @@ -1,5 +1,5 @@ use alloy::{eips::BlockNumberOrTag, primitives::utils::parse_ether}; -use dkn_oracle::{ +use dria_oracle::{ bytes_to_string, commands, handle_request, string_to_bytes, DriaOracle, DriaOracleConfig, OracleKind, TaskStatus, WETH, }; @@ -12,7 +12,7 @@ async fn test_oracle_string_input() -> Result<()> { let _ = env_logger::builder() .filter_level(log::LevelFilter::Off) - .filter_module("dkn_oracle", log::LevelFilter::Debug) + .filter_module("dria_oracle", log::LevelFilter::Debug) .filter_module("oracle_test", log::LevelFilter::Debug) .is_test(true) .try_init(); diff --git a/tests/request_test.rs b/tests/request_test.rs index fe58483..f9a69ba 100644 --- a/tests/request_test.rs +++ b/tests/request_test.rs @@ -5,8 +5,8 @@ //! 3. The task is created in the coordinator contract. use alloy::primitives::utils::parse_ether; -use dkn_oracle::{bytes_to_string, commands, DriaOracle, DriaOracleConfig, WETH}; use dkn_workflows::Model; +use dria_oracle::{bytes_to_string, commands, DriaOracle, DriaOracleConfig, WETH}; use eyre::Result; #[tokio::test] diff --git a/tests/swan_test.rs b/tests/swan_test.rs index f8da2a0..be6d3bc 100644 --- a/tests/swan_test.rs +++ b/tests/swan_test.rs @@ -3,11 +3,11 @@ use alloy::{ primitives::{utils::parse_ether, Address}, sol_types::SolValue, }; -use dkn_oracle::{ +use dkn_workflows::{DriaWorkflowsConfig, Model}; +use dria_oracle::{ bytes_to_string, commands, handle_request, string_to_bytes, DriaOracle, DriaOracleConfig, OracleKind, TaskStatus, WETH, }; -use dkn_workflows::{DriaWorkflowsConfig, Model}; use eyre::Result; // TODO: move this to Swan post-process file diff --git a/tests/weth_test.rs b/tests/weth_test.rs index 57aab43..623d50c 100644 --- a/tests/weth_test.rs +++ b/tests/weth_test.rs @@ -5,7 +5,7 @@ //! 3. Bob transfers WETH from Alice use alloy::primitives::utils::parse_ether; -use dkn_oracle::{DriaOracle, DriaOracleConfig, WETH}; +use dria_oracle::{DriaOracle, DriaOracleConfig, WETH}; use eyre::Result; #[tokio::test] From 583c9dc81f66e634f76b642a430768116e42b574 Mon Sep 17 00:00:00 2001 From: erhant Date: Thu, 12 Dec 2024 13:20:25 +0300 Subject: [PATCH 09/14] rfk generator and validator folders again --- README.md | 2 ++ src/cli.rs | 3 ++- src/compute/{workflows => }/generation/execute.rs | 0 src/compute/{workflows => }/generation/handler.rs | 0 src/compute/{workflows => }/generation/mod.rs | 0 .../{workflows => }/generation/postprocess/identity.rs | 0 src/compute/{workflows => }/generation/postprocess/mod.rs | 0 src/compute/{workflows => }/generation/postprocess/swan.rs | 0 src/compute/{workflows => }/generation/request.rs | 0 src/compute/{workflows => }/generation/workflow.rs | 0 src/compute/handler.rs | 3 +-- src/compute/mod.rs | 7 +++++-- src/compute/{workflows => }/validation/execute.rs | 0 src/compute/{workflows => }/validation/handler.rs | 0 src/compute/{workflows => }/validation/mod.rs | 0 src/compute/{workflows => }/validation/workflow.rs | 0 src/compute/workflows/mod.rs | 3 --- src/storage/arweave.rs | 4 ++-- 18 files changed, 12 insertions(+), 10 deletions(-) rename src/compute/{workflows => }/generation/execute.rs (100%) rename src/compute/{workflows => }/generation/handler.rs (100%) rename src/compute/{workflows => }/generation/mod.rs (100%) rename src/compute/{workflows => }/generation/postprocess/identity.rs (100%) rename src/compute/{workflows => }/generation/postprocess/mod.rs (100%) rename src/compute/{workflows => }/generation/postprocess/swan.rs (100%) rename src/compute/{workflows => }/generation/request.rs (100%) rename src/compute/{workflows => }/generation/workflow.rs (100%) rename src/compute/{workflows => }/validation/execute.rs (100%) rename src/compute/{workflows => }/validation/handler.rs (100%) rename src/compute/{workflows => }/validation/mod.rs (100%) rename src/compute/{workflows => }/validation/workflow.rs (100%) delete mode 100644 src/compute/workflows/mod.rs diff --git a/README.md b/README.md index b9deb3c..029ea2d 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ As for the LLM providers: - If you are using Ollama, make sure it is running and the host & port are correct. - If you are using OpenAI, make sure you provide the `OPENAI_API_KEY`. +- If you are using Gemini, make sure you provide the `GEMINI_API_KEY`. +- If you are using OpenRouter, make sure you provide the `OPENROUTER_API_KEY`. ## Usage diff --git a/src/cli.rs b/src/cli.rs index e2a1d78..713ee19 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -158,6 +158,7 @@ pub async fn cli() -> Result<()> { models, from, } => { + // TODO: add signal handling & looping here, to keep the node running at all times commands::run_oracle( &node, kinds, @@ -170,7 +171,7 @@ pub async fn cli() -> Result<()> { Commands::Tasks { from, to } => { commands::view_task_events( &node, - from.unwrap_or(BlockNumberOrTag::Earliest), // TODO: use coordinator block number as earliest + from.unwrap_or(BlockNumberOrTag::Earliest), to.unwrap_or(BlockNumberOrTag::Latest), ) .await? diff --git a/src/compute/workflows/generation/execute.rs b/src/compute/generation/execute.rs similarity index 100% rename from src/compute/workflows/generation/execute.rs rename to src/compute/generation/execute.rs diff --git a/src/compute/workflows/generation/handler.rs b/src/compute/generation/handler.rs similarity index 100% rename from src/compute/workflows/generation/handler.rs rename to src/compute/generation/handler.rs diff --git a/src/compute/workflows/generation/mod.rs b/src/compute/generation/mod.rs similarity index 100% rename from src/compute/workflows/generation/mod.rs rename to src/compute/generation/mod.rs diff --git a/src/compute/workflows/generation/postprocess/identity.rs b/src/compute/generation/postprocess/identity.rs similarity index 100% rename from src/compute/workflows/generation/postprocess/identity.rs rename to src/compute/generation/postprocess/identity.rs diff --git a/src/compute/workflows/generation/postprocess/mod.rs b/src/compute/generation/postprocess/mod.rs similarity index 100% rename from src/compute/workflows/generation/postprocess/mod.rs rename to src/compute/generation/postprocess/mod.rs diff --git a/src/compute/workflows/generation/postprocess/swan.rs b/src/compute/generation/postprocess/swan.rs similarity index 100% rename from src/compute/workflows/generation/postprocess/swan.rs rename to src/compute/generation/postprocess/swan.rs diff --git a/src/compute/workflows/generation/request.rs b/src/compute/generation/request.rs similarity index 100% rename from src/compute/workflows/generation/request.rs rename to src/compute/generation/request.rs diff --git a/src/compute/workflows/generation/workflow.rs b/src/compute/generation/workflow.rs similarity index 100% rename from src/compute/workflows/generation/workflow.rs rename to src/compute/generation/workflow.rs diff --git a/src/compute/handler.rs b/src/compute/handler.rs index ca34d6b..30e9fca 100644 --- a/src/compute/handler.rs +++ b/src/compute/handler.rs @@ -6,8 +6,7 @@ use alloy::rpc::types::TransactionReceipt; use dkn_workflows::DriaWorkflowsConfig; use eyre::Result; -use super::generation::handle_generation; -use super::validation::handle_validation; +use super::{handle_generation, handle_validation}; /// Handles a task request. /// diff --git a/src/compute/mod.rs b/src/compute/mod.rs index e1295d6..2fe024b 100644 --- a/src/compute/mod.rs +++ b/src/compute/mod.rs @@ -4,5 +4,8 @@ pub use handler::handle_request; mod nonce; pub use nonce::mine_nonce; -mod workflows; -pub use workflows::{generation, validation}; +mod generation; +pub use generation::handle_generation; + +pub mod validation; +pub use validation::handle_validation; diff --git a/src/compute/workflows/validation/execute.rs b/src/compute/validation/execute.rs similarity index 100% rename from src/compute/workflows/validation/execute.rs rename to src/compute/validation/execute.rs diff --git a/src/compute/workflows/validation/handler.rs b/src/compute/validation/handler.rs similarity index 100% rename from src/compute/workflows/validation/handler.rs rename to src/compute/validation/handler.rs diff --git a/src/compute/workflows/validation/mod.rs b/src/compute/validation/mod.rs similarity index 100% rename from src/compute/workflows/validation/mod.rs rename to src/compute/validation/mod.rs diff --git a/src/compute/workflows/validation/workflow.rs b/src/compute/validation/workflow.rs similarity index 100% rename from src/compute/workflows/validation/workflow.rs rename to src/compute/validation/workflow.rs diff --git a/src/compute/workflows/mod.rs b/src/compute/workflows/mod.rs deleted file mode 100644 index 5b045a2..0000000 --- a/src/compute/workflows/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod generation; - -pub mod validation; diff --git a/src/storage/arweave.rs b/src/storage/arweave.rs index 54148b0..3f2ca5d 100644 --- a/src/storage/arweave.rs +++ b/src/storage/arweave.rs @@ -20,8 +20,8 @@ pub struct ArweaveStorage { /// Path to Arweave keypair (usually JSON) wallet: PathBuf, /// Base URL for Arweave gateway, e.g: - /// - https://gateway.irys.xyz - /// - https://node1.bundlr.network + /// - + /// - base_url: Url, /// Reqwest client for downloads. client: Client, From 7c6a223d0e2000a61b51573f44e3588c36179ce4 Mon Sep 17 00:00:00 2001 From: erhant Date: Fri, 13 Dec 2024 00:21:51 +0300 Subject: [PATCH 10/14] many refactors, some threading fixes, fix validations, update abis --- Cargo.lock | 543 +++++++++++++---------- Cargo.toml | 5 +- src/cli.rs | 202 --------- src/cli/commands/coordinator.rs | 353 +++++++++++++++ src/cli/commands/mod.rs | 75 ++++ src/cli/commands/registry.rs | 93 ++++ src/cli/commands/token.rs | 52 +++ src/cli/mod.rs | 152 +++++++ src/cli/parsers.rs | 88 ++++ src/commands/coordinator.rs | 291 ------------ src/commands/mod.rs | 8 - src/commands/registry.rs | 91 ---- src/commands/token.rs | 50 --- src/compute/generation/request.rs | 26 +- src/compute/validation/execute.rs | 29 +- src/compute/validation/handler.rs | 1 + src/compute/validation/workflow.rs | 146 +++--- src/contracts/abi/LLMOracleRegistry.json | 14 +- src/contracts/addresses.rs | 4 +- src/contracts/errors.rs | 73 ++- src/lib.rs | 3 - src/main.rs | 13 +- src/node/coordinator.rs | 15 +- src/node/mod.rs | 7 +- src/node/registry.rs | 36 +- tests/oracle_test.rs | 40 +- tests/request_test.rs | 22 +- tests/swan_test.rs | 29 +- tests/weth_test.rs | 14 +- 29 files changed, 1427 insertions(+), 1048 deletions(-) delete mode 100644 src/cli.rs create mode 100644 src/cli/commands/coordinator.rs create mode 100644 src/cli/commands/mod.rs create mode 100644 src/cli/commands/registry.rs create mode 100644 src/cli/commands/token.rs create mode 100644 src/cli/mod.rs create mode 100644 src/cli/parsers.rs delete mode 100644 src/commands/coordinator.rs delete mode 100644 src/commands/mod.rs delete mode 100644 src/commands/registry.rs delete mode 100644 src/commands/token.rs diff --git a/Cargo.lock b/Cargo.lock index f254944..bbde815 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,9 +64,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4a4aaae80afd4be443a6aecd92a6b255dcdd000f97996928efb33d8a71e100" +checksum = "689e271a72a5c0b05bfdf41c9d0424f11e9df721385dc5bd9045a51f9ea3313b" dependencies = [ "alloy-consensus", "alloy-contract", @@ -94,7 +94,7 @@ version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0161082e0edd9013d23083465cc04b20e44b7a15646d36ba7b0cdb7cd6fe18f" dependencies = [ - "alloy-primitives 0.8.15", + "alloy-primitives", "num_enum", "serde", "strum 0.26.3", @@ -102,29 +102,47 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c309895995eaa4bfcc345f5515a39c7df9447798645cc8bf462b6c5bf1dc96" +checksum = "8ba14856660f31807ebb26ce8f667e814c72694e1077e97ef102e326ad580f3f" dependencies = [ "alloy-eips", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-rlp", "alloy-serde", + "alloy-trie", + "auto_impl", "c-kzg", + "derive_more 1.0.0", + "k256", + "serde", +] + +[[package]] +name = "alloy-consensus-any" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28666307e76441e7af37a2b90cde7391c28112121bea59f4e0d804df8b20057e" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", "serde", ] [[package]] name = "alloy-contract" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4e0ef72b0876ae3068b2ed7dfae9ae1779ce13cfaec2ee1f08f5bd0348dc57" +checksum = "f3510769905590b8991a8e63a5e0ab4aa72cf07a13ab5fbe23f12f4454d161da" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", "alloy-network", "alloy-network-primitives", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-provider", "alloy-pubsub", "alloy-rpc-types-eth", @@ -132,29 +150,30 @@ dependencies = [ "alloy-transport", "futures", "futures-util", - "thiserror 1.0.69", + "thiserror 2.0.6", ] [[package]] name = "alloy-core" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529fc6310dc1126c8de51c376cbc59c79c7f662bd742be7dc67055d5421a81b4" +checksum = "c618bd382f0bc2ac26a7e4bfae01c9b015ca8f21b37ca40059ae35a7e62b3dc6" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", - "alloy-primitives 0.7.7", + "alloy-primitives", + "alloy-rlp", "alloy-sol-types", ] [[package]] name = "alloy-dyn-abi" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413902aa18a97569e60f679c23f46a18db1656d87ab4d4e49d0e1e52042f66df" +checksum = "41056bde53ae10ffbbf11618efbe1e0290859e5eab0fe9ef82ebdb62f12a866f" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-sol-type-parser", "alloy-sol-types", "const-hex", @@ -164,18 +183,43 @@ dependencies = [ "winnow", ] +[[package]] +name = "alloy-eip2930" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c986539255fb839d1533c128e190e557e52ff652c9ef62939e233a81dd93f7e" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "derive_more 1.0.0", + "k256", + "serde", +] + [[package]] name = "alloy-eips" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9431c99a3b3fe606ede4b3d4043bdfbcb780c45b8d8d226c3804e2b75cfbe68" +checksum = "47e922d558006ba371681d484d12aa73fe673d84884f83747730af7433c0e86d" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives", "alloy-rlp", "alloy-serde", "c-kzg", - "derive_more 0.99.18", - "k256", + "derive_more 1.0.0", "once_cell", "serde", "sha2 0.10.8", @@ -183,22 +227,23 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79614dfe86144328da11098edcc7bc1a3f25ad8d3134a9eb9e857e06f0d9840d" +checksum = "5dca170827a7ca156b43588faebf9e9d27c27d0fb07cab82cfd830345e2b24f5" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-serde", + "alloy-trie", "serde", ] [[package]] name = "alloy-json-abi" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc05b04ac331a9f07e3a4036ef7926e49a8bf84a99a1ccfc7e2ab55a5fcbb372" +checksum = "c357da577dfb56998d01f574d81ad7a1958d248740a7981b205d69d65a7da404" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-sol-type-parser", "serde", "serde_json", @@ -206,29 +251,31 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e2865c4c3bb4cdad3f0d9ec1ab5c0c657ba69a375651bd35e32fb6c180ccc2" +checksum = "9335278f50b0273e0a187680ee742bb6b154a948adf036f448575bacc5ccb315" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-sol-types", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.6", "tracing", ] [[package]] name = "alloy-network" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e701fc87ef9a3139154b0b4ccb935b565d27ffd9de020fe541bf2dec5ae4ede" +checksum = "ad4e6ad4230df8c4a254c20f8d6a84ab9df151bfca13f463177dbc96571cc1f8" dependencies = [ "alloy-consensus", + "alloy-consensus-any", "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", - "alloy-primitives 0.7.7", + "alloy-primitives", + "alloy-rpc-types-any", "alloy-rpc-types-eth", "alloy-serde", "alloy-signer", @@ -236,58 +283,41 @@ dependencies = [ "async-trait", "auto_impl", "futures-utils-wasm", - "thiserror 1.0.69", + "serde", + "serde_json", + "thiserror 2.0.6", ] [[package]] name = "alloy-network-primitives" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9d5a0f9170b10988b6774498a022845e13eda94318440d17709d50687f67f9" +checksum = "c4df88a2f8020801e0fefce79471d3946d39ca3311802dbbd0ecfdeee5e972e3" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-consensus", + "alloy-eips", + "alloy-primitives", "alloy-serde", "serde", ] [[package]] name = "alloy-node-bindings" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16faebb9ea31a244fd6ce3288d47df4be96797d9c3c020144b8f2c31543a4512" +checksum = "2db5cefbc736b2b26a960dcf82279c70a03695dd11a0032a6dc27601eeb29182" dependencies = [ "alloy-genesis", - "alloy-primitives 0.7.7", + "alloy-primitives", "k256", + "rand 0.8.5", "serde_json", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.6", "tracing", "url", ] -[[package]] -name = "alloy-primitives" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" -dependencies = [ - "alloy-rlp", - "bytes 1.9.0", - "cfg-if 1.0.0", - "const-hex", - "derive_more 0.99.18", - "hex-literal", - "itoa 1.0.14", - "k256", - "keccak-asm", - "proptest", - "rand 0.8.5", - "ruint", - "serde", - "tiny-keccak", -] - [[package]] name = "alloy-primitives" version = "0.8.15" @@ -300,6 +330,7 @@ dependencies = [ "const-hex", "derive_more 1.0.0", "foldhash", + "hashbrown 0.15.2", "hex-literal", "indexmap 2.7.0", "itoa 1.0.14", @@ -317,9 +348,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9c0ab10b93de601a6396fc7ff2ea10d3b28c46f079338fa562107ebf9857c8" +checksum = "5115c74c037714e1b02a86f742289113afa5d494b5ea58308ba8aa378e739101" dependencies = [ "alloy-chains", "alloy-consensus", @@ -328,11 +359,12 @@ dependencies = [ "alloy-network", "alloy-network-primitives", "alloy-node-bindings", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types-anvil", "alloy-rpc-types-eth", + "alloy-signer", "alloy-signer-local", "alloy-transport", "alloy-transport-http", @@ -345,23 +377,27 @@ dependencies = [ "futures", "futures-utils-wasm", "lru", + "parking_lot", "pin-project", "reqwest 0.12.9", + "schnellru", "serde", "serde_json", + "thiserror 2.0.6", "tokio 1.42.0", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-pubsub" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f5da2c55cbaf229bad3c5f8b00b5ab66c74ef093e5f3a753d874cfecf7d2281" +checksum = "b073afa409698d1b9a30522565815f3bf7010e5b47b997cf399209e6110df097" dependencies = [ "alloy-json-rpc", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-transport", "bimap", "futures", @@ -397,12 +433,12 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b38e3ffdb285df5d9f60cb988d336d9b8e3505acb78750c3bc60336a7af41d3" +checksum = "5c6a0bd0ce5660ac48e4f3bb0c7c5c3a94db287a0be94971599d83928476cbcd" dependencies = [ "alloy-json-rpc", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-pubsub", "alloy-transport", "alloy-transport-http", @@ -418,14 +454,16 @@ dependencies = [ "tower", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-rpc-types" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c31a3750b8f5a350d17354e46a52b0f2f19ec5f2006d816935af599dedc521" +checksum = "374ac12e35bb90ebccd86e7c943ddba9590149a6e35cc4d9cd860d6635fd1018" dependencies = [ + "alloy-primitives", "alloy-rpc-types-engine", "alloy-rpc-types-eth", "alloy-serde", @@ -434,102 +472,113 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ab6509cd38b2e8c8da726e0f61c1e314a81df06a38d37ddec8bced3f8d25ed" +checksum = "f0b85a5f5f5d99047544f4ec31330ee15121dcb8ef5af3e791a5207e6b92b05b" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-primitives", + "alloy-rpc-types-eth", "alloy-serde", "serde", ] +[[package]] +name = "alloy-rpc-types-any" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea98f81bcd759dbfa3601565f9d7a02220d8ef1d294ec955948b90aaafbfd857" +dependencies = [ + "alloy-consensus-any", + "alloy-rpc-types-eth", + "alloy-serde", +] + [[package]] name = "alloy-rpc-types-engine" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff63f51b2fb2f547df5218527fd0653afb1947bf7fead5b3ce58c75d170b30f7" +checksum = "9ca5898f753ff0d15a0dc955c169523d8fee57e05bb5a38a398b3451b0b988be" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-rlp", - "alloy-rpc-types-eth", "alloy-serde", - "jsonwebtoken", - "rand 0.8.5", + "derive_more 1.0.0", "serde", - "thiserror 1.0.69", + "strum 0.26.3", ] [[package]] name = "alloy-rpc-types-eth" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81e18424d962d7700a882fe423714bd5b9dde74c7a7589d4255ea64068773aef" +checksum = "0e518b0a7771e00728f18be0708f828b18a1cfc542a7153bef630966a26388e0" dependencies = [ "alloy-consensus", + "alloy-consensus-any", "alloy-eips", "alloy-network-primitives", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-rlp", "alloy-serde", "alloy-sol-types", + "derive_more 1.0.0", "itertools 0.13.0", "serde", "serde_json", - "thiserror 1.0.69", ] [[package]] name = "alloy-serde" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33feda6a53e6079895aed1d08dcb98a1377b000d80d16370fbbdb8155d547ef" +checksum = "ed3dc8d4a08ffc90c1381d39a4afa2227668259a42c97ab6eecf51cbd82a8761" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-primitives", "serde", "serde_json", ] [[package]] name = "alloy-signer" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740a25b92e849ed7b0fa013951fe2f64be9af1ad5abe805037b44fb7770c5c47" +checksum = "16188684100f6e0f2a2b949968fe3007749c5be431549064a1bce4e7b3a196a9" dependencies = [ - "alloy-primitives 0.7.7", + "alloy-primitives", "async-trait", "auto_impl", "elliptic-curve", "k256", - "thiserror 1.0.69", + "thiserror 2.0.6", ] [[package]] name = "alloy-signer-local" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0707d4f63e4356a110b30ef3add8732ab6d181dd7be4607bf79b8777105cee" +checksum = "e2184dab8c9493ab3e1c9f6bd3bdb563ed322b79023d81531935e84a4fdf7cf1" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-signer", "async-trait", "k256", "rand 0.8.5", - "thiserror 1.0.69", + "thiserror 2.0.6", ] [[package]] name = "alloy-sol-macro" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" +checksum = "d9d64f851d95619233f74b310f12bcf16e0cbc27ee3762b6115c14a84809280a" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", "syn 2.0.90", @@ -537,16 +586,16 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" +checksum = "6bf7ed1574b699f48bf17caab4e6e54c6d12bc3c006ab33d58b1e227c1c3559f" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", "const-hex", "heck 0.5.0", "indexmap 2.7.0", - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", "syn 2.0.90", @@ -556,9 +605,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" +checksum = "8c02997ccef5f34f9c099277d4145f183b422938ed5322dc57a089fe9b9ad9ee" dependencies = [ "alloy-json-abi", "const-hex", @@ -573,9 +622,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcba3ca07cf7975f15d871b721fb18031eec8bce51103907f6dcce00b255d98" +checksum = "ce13ff37285b0870d0a0746992a4ae48efaf34b766ae4c2640fa15e5305f8e73" dependencies = [ "serde", "winnow", @@ -583,12 +632,12 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" +checksum = "1174cafd6c6d810711b4e00383037bdb458efc4fe3dbafafa16567e0320c54d8" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.7.7", + "alloy-primitives", "alloy-sol-macro", "const-hex", "serde", @@ -596,9 +645,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0590afbdacf2f8cca49d025a2466f3b6584a016a8b28f532f29f8da1007bae" +checksum = "628be5b9b75e4f4c4f2a71d985bbaca4f23de356dc83f1625454c505f5eef4df" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -606,18 +655,19 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.6", "tokio 1.42.0", "tower", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-transport-http" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2437d145d80ea1aecde8574d2058cceb8b3c9cba05f6aea8e67907c660d46698" +checksum = "4e24412cf72f79c95cd9b1d9482e3a31f9d94c24b43c4b3b710cc8d4341eaab0" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -630,9 +680,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804494366e20468776db4e18f9eb5db7db0fe14f1271eb6dbf155d867233405c" +checksum = "0577a1f67ce70ece3f2b27cf1011da7222ef0a5701f7dcb558e5356278eeb531" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -649,15 +699,15 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.2.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af855163e7df008799941aa6dd324a43ef2bf264b08ba4b22d44aad6ced65300" +checksum = "1ca46272d17f9647fdb56080ed26c72b3ea5078416831130f5ed46f3b4be0ed6" dependencies = [ "alloy-pubsub", "alloy-transport", "futures", "http 1.2.0", - "rustls 0.23.19", + "rustls 0.23.20", "serde_json", "tokio 1.42.0", "tokio-tungstenite", @@ -665,6 +715,22 @@ dependencies = [ "ws_stream_wasm", ] +[[package]] +name = "alloy-trie" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5fd8fea044cc9a8c8a50bb6f28e31f0385d820f116c5b98f6f4e55d6e5590b" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arrayvec", + "derive_more 1.0.0", + "nybbles", + "serde", + "smallvec", + "tracing", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -864,6 +930,9 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "arweave-rs" @@ -1650,11 +1719,12 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if 1.0.0", + "crossbeam-utils", "hashbrown 0.14.5", "lock_api", "once_cell", @@ -1688,15 +1758,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - [[package]] name = "derivative" version = "2.2.0" @@ -1849,13 +1910,13 @@ dependencies = [ [[package]] name = "dkn-utils" -version = "0.2.28" -source = "git+https://github.com/firstbatchxyz/dkn-compute-node#e6e7b012dd322f98d11ab3c0a64c6f9265076019" +version = "0.2.29" +source = "git+https://github.com/firstbatchxyz/dkn-compute-node#daa9fbae1d297e3e99391e06728bcd5a952d4947" [[package]] name = "dkn-workflows" -version = "0.2.28" -source = "git+https://github.com/firstbatchxyz/dkn-compute-node#e6e7b012dd322f98d11ab3c0a64c6f9265076019" +version = "0.2.29" +source = "git+https://github.com/firstbatchxyz/dkn-compute-node#daa9fbae1d297e3e99391e06728bcd5a952d4947" dependencies = [ "dkn-utils", "env_logger 0.11.5", @@ -1913,6 +1974,7 @@ dependencies = [ "serde", "serde_json", "tokio 1.42.0", + "tokio-util 0.7.13", ] [[package]] @@ -2520,6 +2582,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "hashbrown" version = "0.14.5" @@ -2535,6 +2603,7 @@ dependencies = [ "allocator-api2", "equivalent", "foldhash", + "serde", ] [[package]] @@ -2850,7 +2919,7 @@ dependencies = [ "http 1.2.0", "hyper 1.5.1", "hyper-util", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pki-types", "tokio 1.42.0", "tokio-rustls 0.26.1", @@ -3152,6 +3221,7 @@ checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.2", + "serde", ] [[package]] @@ -3282,21 +3352,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "jsonwebtoken" -version = "9.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" -dependencies = [ - "base64 0.21.7", - "js-sys", - "pem", - "ring 0.17.8", - "serde", - "serde_json", - "simple_asn1", -] - [[package]] name = "k256" version = "0.13.4" @@ -3675,12 +3730,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-derive" version = "0.3.3" @@ -3763,6 +3812,19 @@ dependencies = [ "syn 2.0.90", ] +[[package]] +name = "nybbles" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f06be0417d97f81fe4e5c86d7d01b392655a9cac9c19a848aa033e18937b23" +dependencies = [ + "alloy-rlp", + "const-hex", + "proptest", + "serde", + "smallvec", +] + [[package]] name = "object" version = "0.36.5" @@ -3792,7 +3854,7 @@ dependencies = [ [[package]] name = "ollama-workflows" version = "0.1.0" -source = "git+https://github.com/andthattoo/ollama-workflows#23999766ac759b122a93d1e830f0387deffb1d6e" +source = "git+https://github.com/andthattoo/ollama-workflows#c5c586cafeab0a8459015c6c42b0b078e2d14128" dependencies = [ "async-trait", "base64 0.22.1", @@ -3950,16 +4012,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pem" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" -dependencies = [ - "base64 0.22.1", - "serde", -] - [[package]] name = "pem-rfc7468" version = "0.3.1" @@ -4225,12 +4277,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.20" @@ -4355,6 +4401,28 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -4407,7 +4475,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.19", + "rustls 0.23.20", "socket2 0.5.8", "thiserror 2.0.6", "tokio 1.42.0", @@ -4425,7 +4493,7 @@ dependencies = [ "rand 0.8.5", "ring 0.17.8", "rustc-hash", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pki-types", "slab", "thiserror 2.0.6", @@ -4486,6 +4554,7 @@ dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", + "serde", ] [[package]] @@ -4561,9 +4630,9 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -4708,7 +4777,7 @@ dependencies = [ "percent-encoding", "pin-project-lite 0.2.15", "quinn", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", @@ -4916,9 +4985,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "once_cell", "ring 0.17.8", @@ -5009,6 +5078,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "schnellru" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" +dependencies = [ + "ahash 0.8.11", + "cfg-if 1.0.0", + "hashbrown 0.13.2", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -5225,9 +5305,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -5245,9 +5325,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -5396,18 +5476,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint 0.4.6", - "num-traits", - "thiserror 1.0.69", - "time 0.3.37", -] - [[package]] name = "simsimd" version = "4.4.0" @@ -5437,6 +5505,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -5633,9 +5704,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.7.7" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" +checksum = "219389c1ebe89f8333df8bdfb871f6631c552ff399c23cac02480b6088aad8f0" dependencies = [ "paste", "proc-macro2", @@ -5845,37 +5916,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "time" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" -dependencies = [ - "deranged", - "itoa 1.0.14", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -5982,7 +6022,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.19", + "rustls 0.23.20", "tokio 1.42.0", ] @@ -6010,13 +6050,13 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pki-types", "tokio 1.42.0", "tokio-rustls 0.26.1", @@ -6095,17 +6135,16 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite 0.2.15", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -6170,9 +6209,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes 1.9.0", @@ -6181,7 +6220,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pki-types", "sha1", "thiserror 1.0.69", @@ -6515,6 +6554,20 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmtimer" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "web-sys" version = "0.3.76" @@ -6904,7 +6957,7 @@ dependencies = [ "log", "mac", "markup5ever 0.10.1", - "time 0.1.45", + "time", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3066ed2..78ac3d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,13 +11,14 @@ anvil = ["alloy/node-bindings"] [dependencies] # core -alloy = { version = "0.2.1", features = ["full", "node-bindings"] } +alloy = { version = "0.8.0", features = ["full", "node-bindings"] } alloy-chains = "0.1.24" tokio = { version = "1.39.2", features = [ "macros", "rt-multi-thread", "signal", ] } +tokio-util = "0.7.13" lazy_static = "1.5.0" # workflows @@ -47,6 +48,6 @@ serde_json = "1.0.122" clap = { version = "4.5.13", features = ["derive", "env"] } # arweave uploader -# there are many unused stuff here, but everything breaks if you use the minimal set +# TODO: there are many unused stuff here, but everything breaks if you use the minimal set # because Bundlr SDK is not maintained at all bundlr-sdk = { version = "0.5.0" } diff --git a/src/cli.rs b/src/cli.rs deleted file mode 100644 index 713ee19..0000000 --- a/src/cli.rs +++ /dev/null @@ -1,202 +0,0 @@ -use std::str::FromStr; - -use crate::{commands, contracts::OracleKind, DriaOracle, DriaOracleConfig}; -use alloy::{ - eips::BlockNumberOrTag, - hex::FromHex, - primitives::{B256, U256}, -}; -use clap::{Parser, Subcommand}; -use dkn_workflows::Model; -use eyre::{eyre, Context, Result}; -use reqwest::Url; - -/// `value_parser` to parse a `str` to `OracleKind`. -fn parse_model(value: &str) -> Result { - Model::try_from(value.to_string()).map_err(|e| eyre!(e)) -} - -/// `value_parser` to parse a `str` to `Url`. -fn parse_url(value: &str) -> Result { - Url::parse(value).map_err(Into::into) -} - -/// `value_parser` to parse a hexadecimal `str` to 256-bit type `B256`. -fn parse_secret_key(value: &str) -> Result { - B256::from_hex(value).map_err(Into::into) -} - -/// `value parser` to parse a `str` to `BlockNumberOrTag` -/// where if it can be parsed as `u64`, we call `BlockNumberOrTag::from_u64` -/// otherwise we call `BlockNumberOrTag::from_str`. -fn parse_block_number_or_tag(value: &str) -> Result { - match value.parse::() { - // parse block no from its decimal representation - Ok(block_number) => Ok(BlockNumberOrTag::from(block_number)), - // parse block no from hex, or parse its tag - Err(_) => BlockNumberOrTag::from_str(value).map_err(Into::into), - } -} - -// https://docs.rs/clap/latest/clap/_derive/index.html#arg-attributes -#[derive(Subcommand)] -enum Commands { - /// Register oracle as a specific oracle kind. - Register { - #[arg(help = "The oracle kinds to register as.", required = true)] - kinds: Vec, - }, - /// Unregister oracle as a specific oracle kind. - Unregister { - #[arg(help = "The oracle kinds to unregister as.", required = true)] - kinds: Vec, - }, - /// See all registrations. - Registrations, - /// See the current balance of the oracle node. - Balance, - /// See claimable rewards from the coordinator. - Rewards, - /// Claim rewards from the coordinator. - Claim, - /// Start the oracle node. - Start { - #[arg( - long, - help = "Starting block number to listen for, defaults to 'latest'.", - value_parser = parse_block_number_or_tag - )] - from: Option, - #[arg(help = "The oracle kinds to handle tasks as.", required = false)] - kinds: Vec, - #[arg(short, long = "model", help = "The models to serve.", required = true, value_parser = parse_model)] - models: Vec, - }, - /// View status of a given task. - View { task_id: U256 }, - /// View tasks between specific blocks. - Tasks { - #[arg(long, help = "Starting block number, defaults to 'earliest'.", value_parser = parse_block_number_or_tag)] - from: Option, - #[arg(long, help = "Ending block number, defaults to 'latest'.", value_parser = parse_block_number_or_tag)] - to: Option, - }, - /// Request a task. - Request { - #[arg(help = "The input to request a task with.", required = true)] - input: String, - #[arg(help = "The models to accept.", required = true, value_parser=parse_model)] - models: Vec, - #[arg(long, help = "The difficulty of the task.", default_value_t = 1)] - difficulty: u8, - #[arg( - long, - help = "The number of generations to request.", - default_value_t = 1 - )] - num_gens: u64, - #[arg( - long, - help = "The number of validations to request.", - default_value_t = 1 - )] - num_vals: u64, - }, -} - -#[derive(Parser)] -#[command(version, about, long_about = None)] -#[command(propagate_version = true)] -struct Cli { - #[command(subcommand)] - command: Commands, - - /// RPC URL of the Ethereum node. - #[arg(short, long, env = "RPC_URL", value_parser = parse_url)] - rpc_url: Url, - - /// Ethereum wallet's secret (private) key. - #[arg(short, long, env = "SECRET_KEY", value_parser = parse_secret_key)] - secret_key: B256, -} - -/// Main CLI entry point. -pub async fn cli() -> Result<()> { - // default commands such as version and help exit at this point, - // so we can do the node setup after this line - let cli = Cli::parse(); - - let rpc_url = cli.rpc_url; - let secret_key = cli.secret_key; - - // create node - let config = DriaOracleConfig::new(&secret_key, rpc_url) - .wrap_err("could not create oracle configuration")?; - let node = DriaOracle::new(config) - .await - .wrap_err("could not create oracle node")?; - log::info!("{}", node); - log::info!("{}", node.addresses); - - match cli.command { - Commands::Balance => commands::display_balance(&node).await?, - Commands::Register { kinds } => { - for kind in kinds { - commands::register(&node, kind).await? - } - } - Commands::Unregister { kinds } => { - for kind in kinds { - commands::unregister(&node, kind).await?; - } - } - Commands::Registrations => commands::display_registrations(&node).await?, - Commands::Claim => commands::claim_rewards(&node).await?, - Commands::Rewards => commands::display_rewards(&node).await?, - Commands::Start { - kinds, - models, - from, - } => { - // TODO: add signal handling & looping here, to keep the node running at all times - commands::run_oracle( - &node, - kinds, - models, - from.unwrap_or(BlockNumberOrTag::Latest), - ) - .await? - } - Commands::View { task_id } => commands::view_task(&node, task_id).await?, - Commands::Tasks { from, to } => { - commands::view_task_events( - &node, - from.unwrap_or(BlockNumberOrTag::Earliest), - to.unwrap_or(BlockNumberOrTag::Latest), - ) - .await? - } - Commands::Request { - input, - models, - difficulty, - num_gens, - num_vals, - } => { - const PROTOCOL: &str = concat!("oracle-cli/", env!("CARGO_PKG_VERSION")); - - commands::request_task( - &node, - &input, - models, - difficulty, - num_gens, - num_vals, - PROTOCOL.to_string(), - ) - .await? - } - }; - - Ok(()) -} diff --git a/src/cli/commands/coordinator.rs b/src/cli/commands/coordinator.rs new file mode 100644 index 0000000..f0a573b --- /dev/null +++ b/src/cli/commands/coordinator.rs @@ -0,0 +1,353 @@ +use std::time::Duration; + +use crate::{ + compute::handle_request, + contracts::{bytes_to_string, string_to_bytes, OracleKind, TaskStatus}, + DriaOracle, + OracleCoordinator::StatusUpdate, +}; +use alloy::{ + eips::BlockNumberOrTag, + primitives::{utils::format_ether, U256}, + rpc::types::Log, +}; +use dkn_workflows::{DriaWorkflowsConfig, Model, ModelProvider}; +use eyre::{eyre, Context, Result}; +use futures_util::StreamExt; +use tokio_util::sync::CancellationToken; + +impl DriaOracle { + /// Runs the main loop of the oracle node. + pub(in crate::cli) async fn run_oracle( + &self, + mut kinds: Vec, + models: Vec, + from_block: BlockNumberOrTag, + cancellation: CancellationToken, + ) -> Result<()> { + // if kinds are not provided, use the registrations as kinds + if kinds.is_empty() { + log::debug!("No kinds provided. Checking registrations."); + for kind in [OracleKind::Generator, OracleKind::Validator] { + if self.is_registered(kind).await? { + kinds.push(kind); + } + } + + if kinds.is_empty() { + return Err(eyre!("You are not registered as any type of oracle."))?; + } + } else { + // otherwise, make sure we are registered to required kinds + for kind in &kinds { + if !self.is_registered(*kind).await? { + return Err(eyre!("You need to register as {} first.", kind))?; + } + } + } + log::info!( + "Running as: {}", + kinds + .iter() + .map(|kind| kind.to_string()) + .collect::>() + .join(", ") + ); + + // prepare model config & check services + let mut model_config = DriaWorkflowsConfig::new(models); + if model_config.models.is_empty() { + return Err(eyre!("No models provided."))?; + } + let ollama_config = model_config.ollama.clone(); + model_config = model_config.with_ollama_config( + ollama_config + .with_min_tps(5.0) + .with_timeout(Duration::from_secs(150)), + ); + model_config.check_services().await?; + + // validator-specific checks here + if kinds.contains(&OracleKind::Validator) { + // make sure we have GPT4o model + if !model_config + .models + .contains(&(ModelProvider::OpenAI, Model::GPT4o)) + { + return Err(eyre!("Validator must have GPT4o model."))?; + } + + // make sure node is whitelisted + if !self.is_whitelisted(self.address()).await? { + return Err(eyre!("You are not whitelisted in the registry."))?; + } + } + + // check previous tasks if `from_block` is not `Latest` + if from_block != BlockNumberOrTag::Latest { + tokio::select! { + _ = cancellation.cancelled() => { + log::debug!("Cancellation signal received. Stopping..."); + return Ok(()); + } + result = self.handle_previous_tasks(from_block, &model_config, &kinds) => { + if let Err(e) = result { + log::error!("Could not handle previous tasks: {:?}", e); + log::warn!("Continuing anyways..."); + } + } + } + } + + loop { + // subscribe to new tasks + log::info!( + "Subscribing to LLMOracleCoordinator ({})", + self.addresses.coordinator, + ); + let mut event_stream = self + .subscribe_to_tasks() + .await + .wrap_err("could not subscribe to tasks")? + .into_stream(); + + // start the event loop + log::info!("Listening for events..."); + loop { + tokio::select! { + _ = cancellation.cancelled() => { + log::debug!("Cancellation signal received. Stopping..."); + return Ok(()); + } + next = event_stream.next() => { + match next { + Some(Ok((event, log))) => { + self.handle_event_log(event, log, &kinds, &model_config) + .await + } + Some(Err(e)) => log::error!("Could not handle event: {}", e), + None => { + log::warn!("Stream ended, waiting a bit before restarting."); + tokio::time::sleep(Duration::from_secs(5)).await; + break + }, + } + } + } + } + } + } + + async fn handle_event_log( + &self, + event: StatusUpdate, + log: Log, + kinds: &[OracleKind], + model_config: &DriaWorkflowsConfig, + ) { + let task_id = event.taskId; + log::debug!( + "Handling task {} (tx: {})", + task_id, + log.transaction_hash.unwrap_or_default() + ); + + // handle request + match handle_request(self, &kinds, &model_config, event).await { + Ok(Some(receipt)) => { + log::info!( + "Task {} processed successfully. (tx: {})", + task_id, + receipt.transaction_hash + ) + } + Ok(None) => { + log::debug!("Task {} ignored.", task_id) + } + Err(e) => log::error!("Could not process task: {:?}", e), + } + } + + async fn handle_previous_tasks( + &self, + from_block: BlockNumberOrTag, + model_config: &DriaWorkflowsConfig, + kinds: &[OracleKind], + ) -> Result<()> { + log::info!( + "Checking previous tasks from block {} until now.", + from_block + ); + let prev_tasks = self + .get_tasks_in_range(from_block, BlockNumberOrTag::Latest) + .await?; + + for (event, log) in prev_tasks { + let task_id = event.taskId; + log::info!( + "Previous task: {} ({} -> {})", + task_id, + TaskStatus::try_from(event.statusBefore).unwrap_or_default(), + TaskStatus::try_from(event.statusAfter).unwrap_or_default() + ); + log::debug!( + "Handling task {} (tx: {})", + task_id, + log.transaction_hash.unwrap_or_default() + ); + match handle_request(self, &kinds, &model_config, event).await { + Ok(Some(receipt)) => { + log::info!( + "Task {} processed successfully. (tx: {})", + task_id, + receipt.transaction_hash + ) + } + Ok(None) => { + log::info!("Task {} ignored.", task_id) + } + Err(e) => log::error!("Could not process task: {:?}", e), + } + } + + Ok(()) + } + pub(in crate::cli) async fn view_task_events( + &self, + from_block: impl Into + Clone, + to_block: impl Into + Clone, + ) -> Result<()> { + let from_block: BlockNumberOrTag = from_block.clone().into(); + let to_block: BlockNumberOrTag = to_block.clone().into(); + log::info!( + "Viewing task ids & statuses between blocks: {} - {}", + from_block + .as_number() + .map(|n| n.to_string()) + .unwrap_or(from_block.to_string()), + to_block + .as_number() + .map(|n| n.to_string()) + .unwrap_or(to_block.to_string()) + ); + + let task_events = self.get_tasks_in_range(from_block, to_block).await?; + + for (event, _) in task_events { + log::info!( + "Task: {} ({} -> {})", + event.taskId, + TaskStatus::try_from(event.statusBefore).unwrap_or_default(), + TaskStatus::try_from(event.statusAfter).unwrap_or_default() + ); + } + + Ok(()) + } + + pub(in crate::cli) async fn view_task(&self, task_id: U256) -> Result<()> { + log::info!("Viewing task {}.", task_id); + let (request, responses, validations) = self.get_task(task_id).await?; + + log::info!( + "Request Information:\nRequester: {}\nStatus: {}\nInput: {}\nModels: {}", + request.requester, + TaskStatus::try_from(request.status)?, + bytes_to_string(&request.input)?, + bytes_to_string(&request.models)? + ); + + log::info!("Responses:"); + if responses._0.is_empty() { + log::warn!("There are no responses yet."); + } else { + for (idx, response) in responses._0.iter().enumerate() { + log::info!( + "Response #{}\nOutput: {}\nMetadata: {}\nGenerator: {}", + idx, + bytes_to_string(&response.output)?, + bytes_to_string(&response.metadata)?, + response.responder + ); + } + } + + log::info!("Validations:"); + if validations._0.is_empty() { + log::warn!("There are no validations yet."); + } else { + for (idx, validation) in validations._0.iter().enumerate() { + log::info!( + "Validation #{}\nScores: {:?}\nMetadata: {}\nValidator: {}", + idx, + validation.scores, + bytes_to_string(&validation.metadata)?, + validation.validator + ); + } + } + + Ok(()) + } + + pub async fn request_task( + &self, + input: &str, + models: Vec, + difficulty: u8, + num_gens: u64, + num_vals: u64, + protocol: String, + ) -> Result<()> { + let input = string_to_bytes(input.to_string()); + let models_str = models + .iter() + .map(|m| m.to_string()) + .collect::>() + .join(","); + let models = string_to_bytes(models_str); + log::info!("Requesting a new task."); + + // get total fee for the request + let total_fee = self + .get_request_fee(difficulty, num_gens, num_vals) + .await? + .totalFee; + + // check balance + let balance = self.get_token_balance(self.address()).await?.amount; + if balance < total_fee { + return Err(eyre!("Insufficient balance. Please fund your wallet.")); + } + + // check current allowance + let allowance = self + .allowance(self.address(), self.addresses.coordinator) + .await? + .amount; + + // make sure we have enough allowance + if allowance < total_fee { + let approval_amount = total_fee - allowance; + log::info!( + "Insufficient allowance. Approving the required amount: {}.", + format_ether(approval_amount) + ); + + self.approve(self.addresses.coordinator, approval_amount) + .await?; + log::info!("Token approval successful."); + } + + // make the request + let receipt = self + .request(input, models, difficulty, num_gens, num_vals, protocol) + .await?; + log::info!( + "Task requested successfully. tx: {}", + receipt.transaction_hash + ); + + Ok(()) + } +} diff --git a/src/cli/commands/mod.rs b/src/cli/commands/mod.rs new file mode 100644 index 0000000..00fb812 --- /dev/null +++ b/src/cli/commands/mod.rs @@ -0,0 +1,75 @@ +mod coordinator; +mod registry; +mod token; + +use super::parsers::*; +use crate::contracts::OracleKind; +use alloy::{eips::BlockNumberOrTag, primitives::U256}; +use clap::Subcommand; +use dkn_workflows::Model; + +// https://docs.rs/clap/latest/clap/_derive/index.html#arg-attributes +#[derive(Subcommand)] +pub enum Commands { + /// Register oracle as a specific oracle kind. + Register { + #[arg(help = "The oracle kinds to register as.", required = true)] + kinds: Vec, + }, + /// Unregister oracle as a specific oracle kind. + Unregister { + #[arg(help = "The oracle kinds to unregister as.", required = true)] + kinds: Vec, + }, + /// See all registrations. + Registrations, + /// See the current balance of the oracle node. + Balance, + /// See claimable rewards from the coordinator. + Rewards, + /// Claim rewards from the coordinator. + Claim, + /// Start the oracle node. + Start { + #[arg( + long, + help = "Starting block number to listen for, defaults to 'latest'.", + value_parser = parse_block_number_or_tag + )] + from: Option, + #[arg(help = "The oracle kinds to handle tasks as.", required = false)] + kinds: Vec, + #[arg(short, long = "model", help = "The models to serve.", required = true, value_parser = parse_model)] + models: Vec, + }, + /// View status of a given task. + View { task_id: U256 }, + /// View tasks between specific blocks. + Tasks { + #[arg(long, help = "Starting block number, defaults to 'earliest'.", value_parser = parse_block_number_or_tag)] + from: Option, + #[arg(long, help = "Ending block number, defaults to 'latest'.", value_parser = parse_block_number_or_tag)] + to: Option, + }, + /// Request a task. + Request { + #[arg(help = "The input to request a task with.", required = true)] + input: String, + #[arg(help = "The models to accept.", required = true, value_parser=parse_model)] + models: Vec, + #[arg(long, help = "The difficulty of the task.", default_value_t = 1)] + difficulty: u8, + #[arg( + long, + help = "The number of generations to request.", + default_value_t = 1 + )] + num_gens: u64, + #[arg( + long, + help = "The number of validations to request.", + default_value_t = 1 + )] + num_vals: u64, + }, +} diff --git a/src/cli/commands/registry.rs b/src/cli/commands/registry.rs new file mode 100644 index 0000000..48caffe --- /dev/null +++ b/src/cli/commands/registry.rs @@ -0,0 +1,93 @@ +use crate::{contracts::OracleKind, DriaOracle}; +use alloy::primitives::utils::format_ether; +use eyre::Result; + +impl DriaOracle { + /// Registers the oracle node as an oracle for the given `kind`. + /// + /// - If the node is already registered, it will do nothing. + /// - If the node is not registered, it will approve the required amount of tokens + /// to the registry and then register the node. + pub async fn register(&self, kind: OracleKind) -> Result<()> { + log::info!("Registering as a {}.", kind); + // check if registered already + if self.is_registered(kind).await? { + log::warn!("You are already registered as a {}.", kind); + } else { + // calculate the required approval for registration + let stake = self.registry_stake_amount(kind).await?; + let allowance = self + .allowance(self.address(), self.addresses.registry) + .await?; + + // approve if necessary + if allowance.amount < stake.amount { + let difference = stake.amount - allowance.amount; + log::info!( + "Approving {} tokens for {} registration.", + format_ether(difference), + kind + ); + + // check balance + let balance = self.get_token_balance(self.address()).await?; + if balance.amount < difference { + return Err(eyre::eyre!( + "Not enough balance to approve. (have: {}, required: {})", + balance, + difference + )); + } + + // approve the difference + self.approve(self.addresses.registry, difference).await?; + } else { + log::info!("Already approved enough tokens."); + } + + // register + log::info!("Registering."); + self.register_kind(kind).await?; + } + + Ok(()) + } + + /// Unregisters the oracle node as an oracle for the given `kind`. + /// + /// - If the node is not registered, it will do nothing. + /// - If the node is registered, it will unregister the node and transfer all allowance + /// from the registry back to the oracle. + pub async fn unregister(&self, kind: OracleKind) -> Result<()> { + log::info!("Unregistering as {}.", kind); + // check if not registered anyways + if !self.is_registered(kind).await? { + log::warn!("You are already not registered as a {}.", kind); + } else { + self.unregister_kind(kind).await?; + + // transfer all allowance from registry back to oracle + // to get back the registrations fee + let allowance = self + .allowance(self.addresses.registry, self.address()) + .await?; + log::info!( + "Transferring all allowance ({}) back from registry.", + allowance + ); + self.transfer_from(self.addresses.registry, self.address(), allowance.amount) + .await?; + } + Ok(()) + } + + /// Displays the registration status of the oracle node for all oracle kinds. + pub(in crate::cli) async fn display_registrations(&self) -> Result<()> { + for kind in [OracleKind::Generator, OracleKind::Validator] { + let is_registered = self.is_registered(kind).await?; + log::info!("{}: {}", kind, is_registered); + } + + Ok(()) + } +} diff --git a/src/cli/commands/token.rs b/src/cli/commands/token.rs new file mode 100644 index 0000000..c1742e9 --- /dev/null +++ b/src/cli/commands/token.rs @@ -0,0 +1,52 @@ +use crate::DriaOracle; +use eyre::Result; + +impl DriaOracle { + /// Display token balances + pub(in crate::cli) async fn display_balance(&self) -> Result<()> { + let eth_balance = self.get_native_balance(self.address()).await?; + let token_balance = self.get_token_balance(self.address()).await?; + + log::info!("Your balances:"); + for balance in [eth_balance, token_balance].iter() { + log::info!("{}", balance); + } + + Ok(()) + } + + /// Show the amount of claimable rewards + pub(in crate::cli) async fn display_rewards(&self) -> Result<()> { + let allowance = self + .allowance(self.addresses.coordinator, self.address()) + .await?; + + log::info!("Claimable rewards:"); + log::info!("{} ", allowance); + if allowance.amount.is_zero() { + log::warn!("You have no claimable rewards!"); + } + + Ok(()) + } + + /// Claim rewards + pub(in crate::cli) async fn claim_rewards(&self) -> Result<()> { + // get allowance + let allowance = self + .allowance(self.addresses.coordinator, self.address()) + .await?; + + // check if there are rewards to claim + if allowance.amount.is_zero() { + log::warn!("No rewards to claim."); + } else { + // transfer rewards + self.transfer_from(self.addresses.coordinator, self.address(), allowance.amount) + .await?; + log::info!("Rewards claimed: {}.", allowance); + } + + Ok(()) + } +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs new file mode 100644 index 0000000..3cd9a5f --- /dev/null +++ b/src/cli/mod.rs @@ -0,0 +1,152 @@ +mod commands; +use commands::Commands; + +mod parsers; +use parsers::*; + +use crate::{DriaOracle, DriaOracleConfig}; +use alloy::{eips::BlockNumberOrTag, primitives::B256}; +use clap::Parser; +use eyre::{Context, Result}; +use reqwest::Url; +use tokio_util::sync::CancellationToken; + +#[derive(Parser)] +#[command(version, about, long_about = None)] +#[command(propagate_version = true)] +struct Cli { + #[command(subcommand)] + command: Commands, + + /// RPC URL of the Ethereum node. + #[arg(short, long, env = "RPC_URL", value_parser = parse_url)] + rpc_url: Url, + + /// Ethereum wallet's secret (private) key. + #[arg(short, long, env = "SECRET_KEY", value_parser = parse_secret_key)] + secret_key: B256, +} + +/// Main CLI entry point. +pub async fn cli() -> Result<()> { + // default commands such as version and help exit at this point, + // so we can do the node setup after this line + let cli = Cli::parse(); + + // store cli-parsed options + let rpc_url = cli.rpc_url; + let secret_key = cli.secret_key; + + // create node + let config = DriaOracleConfig::new(&secret_key, rpc_url) + .wrap_err("could not create oracle configuration")?; + let node = DriaOracle::new(config) + .await + .wrap_err("could not create oracle node")?; + log::info!("{}", node); + log::info!("{}", node.addresses); + + match cli.command { + Commands::Balance => node.display_balance().await?, + Commands::Register { kinds } => { + for kind in kinds { + node.register(kind).await? + } + } + Commands::Unregister { kinds } => { + for kind in kinds { + node.unregister(kind).await?; + } + } + Commands::Registrations => node.display_registrations().await?, + Commands::Claim => node.claim_rewards().await?, + Commands::Rewards => node.display_rewards().await?, + Commands::Start { + kinds, + models, + from, + } => { + let token = CancellationToken::new(); + + // create a signal handler + let termination_token = token.clone(); + let termination_handle = tokio::spawn(async move { + wait_for_termination(termination_token).await.unwrap(); + }); + + // launch node + node.run_oracle( + kinds, + models, + from.unwrap_or(BlockNumberOrTag::Latest), + token, + ) + .await?; + + // wait for handle + if let Err(e) = termination_handle.await { + log::error!("Error in termination handler: {}", e); + } + } + Commands::View { task_id } => node.view_task(task_id).await?, + Commands::Tasks { from, to } => { + node.view_task_events( + from.unwrap_or(BlockNumberOrTag::Earliest), + to.unwrap_or(BlockNumberOrTag::Latest), + ) + .await? + } + Commands::Request { + input, + models, + difficulty, + num_gens, + num_vals, + } => { + const PROTOCOL: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); + + node.request_task( + &input, + models, + difficulty, + num_gens, + num_vals, + PROTOCOL.to_string(), + ) + .await? + } + }; + + Ok(()) +} + +/// Waits for various termination signals, and cancels the given token when the signal is received. +async fn wait_for_termination(cancellation: CancellationToken) -> Result<()> { + #[cfg(unix)] + { + use tokio::signal::unix::{signal, SignalKind}; + let mut sigterm = signal(SignalKind::terminate())?; + let mut sigint = signal(SignalKind::interrupt())?; + tokio::select! { + _ = sigterm.recv() => log::warn!("Recieved SIGTERM"), + _ = sigint.recv() => log::warn!("Recieved SIGINT"), + _ = cancellation.cancelled() => { + // no need to wait if cancelled anyways + // although this is not likely to happen + return Ok(()); + } + }; + + cancellation.cancel(); + } + + #[cfg(not(unix))] + { + log::error!("No signal handling for this platform: {}", env::consts::OS); + cancellation.cancel(); + } + + log::info!("Terminating the application..."); + + Ok(()) +} diff --git a/src/cli/parsers.rs b/src/cli/parsers.rs new file mode 100644 index 0000000..d115909 --- /dev/null +++ b/src/cli/parsers.rs @@ -0,0 +1,88 @@ +use alloy::{eips::BlockNumberOrTag, hex::FromHex, primitives::B256}; +use dkn_workflows::Model; +use eyre::{eyre, Result}; +use reqwest::Url; +use std::str::FromStr; + +/// `value_parser` to parse a `str` to `OracleKind`. +pub fn parse_model(value: &str) -> Result { + Model::try_from(value.to_string()).map_err(|e| eyre!(e)) +} + +/// `value_parser` to parse a `str` to `Url`. +pub fn parse_url(value: &str) -> Result { + Url::parse(value).map_err(Into::into) +} + +/// `value_parser` to parse a hexadecimal `str` to 256-bit type `B256`. +pub fn parse_secret_key(value: &str) -> Result { + B256::from_hex(value).map_err(Into::into) +} + +/// `value parser` to parse a `str` to `BlockNumberOrTag` +/// where if it can be parsed as `u64`, we call `BlockNumberOrTag::from_u64` +/// otherwise we call `BlockNumberOrTag::from_str`. +pub fn parse_block_number_or_tag(value: &str) -> Result { + match value.parse::() { + // parse block no from its decimal representation + Ok(block_number) => Ok(BlockNumberOrTag::from(block_number)), + // parse block no from hex, or parse its tag + Err(_) => BlockNumberOrTag::from_str(value).map_err(Into::into), + } +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_model() { + let model_str = "llama3.1:latest"; + let result = parse_model(model_str); + assert!(result.is_ok()); + let model = result.unwrap(); + assert_eq!(model, Model::try_from(model_str.to_string()).unwrap()); + } + + #[test] + fn test_parse_url() { + let url_str = "https://example.com"; + let result = parse_url(url_str); + assert!(result.is_ok()); + let url = result.unwrap(); + assert_eq!(url, Url::parse(url_str).unwrap()); + } + + #[test] + fn test_parse_secret_key() { + let hex_str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + let result = parse_secret_key(hex_str); + assert!(result.is_ok()); + + let secret_key = result.unwrap(); + assert_eq!(secret_key, B256::from_hex(hex_str).unwrap()); + } + + #[test] + fn test_parse_block_number_or_tag() { + let block_number_str = "12345"; + let result = parse_block_number_or_tag(block_number_str); + assert!(result.is_ok()); + let block_number_or_tag = result.unwrap(); + assert_eq!(block_number_or_tag, BlockNumberOrTag::from(12345u64)); + + let block_tag_str = "latest"; + let result = parse_block_number_or_tag(block_tag_str); + assert!(result.is_ok()); + let block_number_or_tag = result.unwrap(); + assert_eq!(block_number_or_tag, BlockNumberOrTag::Latest); + + let block_hex_str = "0x3039"; + let result = parse_block_number_or_tag(block_hex_str); + assert!(result.is_ok()); + let block_number_or_tag = result.unwrap(); + assert_eq!( + block_number_or_tag, + BlockNumberOrTag::from_str(block_hex_str).unwrap() + ); + } +} diff --git a/src/commands/coordinator.rs b/src/commands/coordinator.rs deleted file mode 100644 index 7191248..0000000 --- a/src/commands/coordinator.rs +++ /dev/null @@ -1,291 +0,0 @@ -use std::time::Duration; - -use crate::{ - compute::handle_request, - contracts::{bytes_to_string, string_to_bytes, OracleKind, TaskStatus}, - DriaOracle, -}; -use alloy::{ - eips::BlockNumberOrTag, - primitives::{utils::format_ether, U256}, -}; -use dkn_workflows::{DriaWorkflowsConfig, Model, ModelProvider}; -use eyre::{eyre, Context, Result}; -use futures_util::StreamExt; - -/// Runs the main loop of the oracle node. -pub async fn run_oracle( - node: &DriaOracle, - mut kinds: Vec, - models: Vec, - from_block: impl Into + Clone, -) -> Result<()> { - // if kinds are not provided, use the registrations as kinds - if kinds.is_empty() { - log::debug!("No kinds provided. Checking registrations."); - for kind in [OracleKind::Generator, OracleKind::Validator] { - if node.is_registered(kind).await? { - kinds.push(kind); - } - } - - if kinds.is_empty() { - return Err(eyre!("You are not registered as any type of oracle."))?; - } - } else { - // otherwise, make sure we are registered to required kinds - for kind in &kinds { - if !node.is_registered(*kind).await? { - return Err(eyre!("You need to register as {} first.", kind))?; - } - } - } - - // prepare model config - let mut model_config = DriaWorkflowsConfig::new(models); - if model_config.models.is_empty() { - return Err(eyre!("No models provided."))?; - } - let ollama_config = model_config.ollama.clone(); - model_config = model_config.with_ollama_config( - ollama_config - .with_min_tps(5.0) - .with_timeout(Duration::from_secs(150)), - ); - model_config.check_services().await?; - - // check if validator has the required model - if kinds.contains(&OracleKind::Validator) { - if !model_config - .models - .contains(&(ModelProvider::OpenAI, Model::GPT4o)) - { - return Err(eyre!("Validator must have GPT4o model."))?; - } - } - - // check previous tasks if `from_block` is not `Latest` - if from_block.clone().into() != BlockNumberOrTag::Latest { - log::info!( - "Checking previous tasks from block {} until now.", - from_block.clone().into() - ); - let prev_tasks = node - .get_tasks_in_range(from_block.clone(), BlockNumberOrTag::Latest) - .await?; - for (event, log) in prev_tasks { - let task_id = event.taskId; - log::info!( - "Previous task: {} ({} -> {})", - task_id, - TaskStatus::try_from(event.statusBefore).unwrap_or_default(), - TaskStatus::try_from(event.statusAfter).unwrap_or_default() - ); - log::debug!( - "Handling task {} (tx: {})", - task_id, - log.transaction_hash.unwrap_or_default() - ); - match handle_request(node, &kinds, &model_config, event).await { - Ok(Some(receipt)) => { - log::info!( - "Task {} processed successfully. (tx: {})", - task_id, - receipt.transaction_hash - ) - } - Ok(None) => { - log::info!("Task {} ignored.", task_id) - } - Err(e) => log::error!("Could not process task: {:?}", e), - } - } - } - - // handle new tasks with subscription - log::info!( - "Subscribing to LLMOracleCoordinator ({}) as {}", - node.addresses.coordinator, - kinds - .iter() - .map(|kind| kind.to_string()) - .collect::>() - .join(", ") - ); - let event_poller = node - .subscribe_to_tasks() - .await - .wrap_err("could not subscribe to tasks")?; - - log::info!("Listening for events..."); - event_poller - .into_stream() - .for_each(|log| async { - match log { - Ok((event, log)) => { - let task_id = event.taskId; - log::debug!( - "Handling task {} (tx: {})", - task_id, - log.transaction_hash.unwrap_or_default() - ); - match handle_request(node, &kinds, &model_config, event).await { - Ok(Some(receipt)) => { - log::info!( - "Task {} processed successfully. (tx: {})", - task_id, - receipt.transaction_hash - ) - } - Ok(None) => { - log::info!("Task {} ignored.", task_id) - } - Err(e) => log::error!("Could not process task: {:?}", e), - } - } - Err(e) => log::error!("Could not handle event: {}", e), - } - }) - .await; - - Ok(()) -} - -pub async fn view_task_events( - node: &DriaOracle, - from_block: impl Into + Clone, - to_block: impl Into + Clone, -) -> Result<()> { - let from_block: BlockNumberOrTag = from_block.clone().into(); - let to_block: BlockNumberOrTag = to_block.clone().into(); - log::info!( - "Viewing task ids & statuses between blocks: {} - {}", - from_block - .as_number() - .map(|n| n.to_string()) - .unwrap_or(from_block.to_string()), - to_block - .as_number() - .map(|n| n.to_string()) - .unwrap_or(to_block.to_string()) - ); - - let task_events = node.get_tasks_in_range(from_block, to_block).await?; - - for (event, _) in task_events { - log::info!( - "Task: {} ({} -> {})", - event.taskId, - TaskStatus::try_from(event.statusBefore).unwrap_or_default(), - TaskStatus::try_from(event.statusAfter).unwrap_or_default() - ); - } - - Ok(()) -} - -pub async fn view_task(node: &DriaOracle, task_id: U256) -> Result<()> { - log::info!("Viewing task {}.", task_id); - let (request, responses, validations) = node.get_task(task_id).await?; - - log::info!( - "Request Information:\nRequester: {}\nStatus: {}\nInput: {}\nModels: {}", - request.requester, - TaskStatus::try_from(request.status)?, - bytes_to_string(&request.input)?, - bytes_to_string(&request.models)? - ); - - log::info!("Responses:"); - if responses._0.is_empty() { - log::warn!("There are no responses yet."); - } else { - for (idx, response) in responses._0.iter().enumerate() { - log::info!( - "Response #{}\nOutput: {}\nMetadata: {}\nGenerator: {}", - idx, - bytes_to_string(&response.output)?, - bytes_to_string(&response.metadata)?, - response.responder - ); - } - } - - log::info!("Validations:"); - if validations._0.is_empty() { - log::warn!("There are no validations yet."); - } else { - for (idx, validation) in validations._0.iter().enumerate() { - log::info!( - "Validation #{}\nScores: {:?}\nMetadata: {}\nValidator: {}", - idx, - validation.scores, - bytes_to_string(&validation.metadata)?, - validation.validator - ); - } - } - - Ok(()) -} - -pub async fn request_task( - node: &DriaOracle, - input: &str, - models: Vec, - difficulty: u8, - num_gens: u64, - num_vals: u64, - protocol: String, -) -> Result<()> { - let input = string_to_bytes(input.to_string()); - let models_str = models - .iter() - .map(|m| m.to_string()) - .collect::>() - .join(","); - let models = string_to_bytes(models_str); - log::info!("Requesting a new task."); - - // get total fee for the request - let total_fee = node - .get_request_fee(difficulty, num_gens, num_vals) - .await? - .totalFee; - - // check balance - let balance = node.get_token_balance(node.address()).await?.amount; - if balance < total_fee { - return Err(eyre!("Insufficient balance. Please fund your wallet.")); - } - - // check current allowance - let allowance = node - .allowance(node.address(), node.addresses.coordinator) - .await? - .amount; - - // make sure we have enough allowance - if allowance < total_fee { - let approval_amount = total_fee - allowance; - log::info!( - "Insufficient allowance. Approving the required amount: {}.", - format_ether(approval_amount) - ); - - node.approve(node.addresses.coordinator, approval_amount) - .await?; - log::info!("Token approval successful."); - } - - // make the request - let receipt = node - .request(input, models, difficulty, num_gens, num_vals, protocol) - .await?; - log::info!( - "Task requested successfully. tx: {}", - receipt.transaction_hash - ); - - Ok(()) -} diff --git a/src/commands/mod.rs b/src/commands/mod.rs deleted file mode 100644 index 2e85087..0000000 --- a/src/commands/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod coordinator; -pub use coordinator::*; - -mod registry; -pub use registry::*; - -mod token; -pub use token::*; diff --git a/src/commands/registry.rs b/src/commands/registry.rs deleted file mode 100644 index bb5b7a0..0000000 --- a/src/commands/registry.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::{contracts::OracleKind, DriaOracle}; -use alloy::primitives::utils::format_ether; -use eyre::Result; - -/// Registers the oracle node as an oracle for the given `kind`. -/// -/// - If the node is already registered, it will do nothing. -/// - If the node is not registered, it will approve the required amount of tokens -/// to the registry and then register the node. -pub async fn register(node: &DriaOracle, kind: OracleKind) -> Result<()> { - log::info!("Registering as a {}.", kind); - // check if registered already - if node.is_registered(kind).await? { - log::warn!("You are already registered as a {}.", kind); - } else { - // calculate the required approval for registration - let stake = node.registry_stake_amount(kind).await?; - let allowance = node - .allowance(node.address(), node.addresses.registry) - .await?; - - // approve if necessary - if allowance.amount < stake.amount { - let difference = stake.amount - allowance.amount; - log::info!( - "Approving {} tokens for {} registration.", - format_ether(difference), - kind - ); - - // check balance - let balance = node.get_token_balance(node.address()).await?; - if balance.amount < difference { - return Err(eyre::eyre!( - "Not enough balance to approve. (have: {}, required: {})", - balance, - difference - )); - } - - // approve the difference - node.approve(node.addresses.registry, difference).await?; - } else { - log::info!("Already approved enough tokens."); - } - - // register - log::info!("Registering."); - node.register(kind).await?; - } - - Ok(()) -} - -/// Unregisters the oracle node as an oracle for the given `kind`. -/// -/// - If the node is not registered, it will do nothing. -/// - If the node is registered, it will unregister the node and transfer all allowance -/// from the registry back to the oracle. -pub async fn unregister(node: &DriaOracle, kind: OracleKind) -> Result<()> { - log::info!("Unregistering as {}.", kind); - // check if not registered anyways - if !node.is_registered(kind).await? { - log::warn!("You are already not registered as a {}.", kind); - } else { - node.unregister(kind).await?; - - // transfer all allowance from registry back to oracle - // to get back the registrations fee - let allowance = node - .allowance(node.addresses.registry, node.address()) - .await?; - log::info!( - "Transferring all allowance ({}) back from registry.", - allowance - ); - node.transfer_from(node.addresses.registry, node.address(), allowance.amount) - .await?; - } - Ok(()) -} - -/// Displays the registration status of the oracle node for all oracle kinds. -pub async fn display_registrations(node: &DriaOracle) -> Result<()> { - for kind in [OracleKind::Generator, OracleKind::Validator] { - let is_registered = node.is_registered(kind).await?; - log::info!("{}: {}", kind, is_registered); - } - - Ok(()) -} diff --git a/src/commands/token.rs b/src/commands/token.rs deleted file mode 100644 index 790e18d..0000000 --- a/src/commands/token.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::DriaOracle; -use eyre::Result; - -/// Display token balances -pub async fn display_balance(node: &DriaOracle) -> Result<()> { - let eth_balance = node.get_native_balance(node.address()).await?; - let token_balance = node.get_token_balance(node.address()).await?; - - log::info!("Your balances:"); - for balance in [eth_balance, token_balance].iter() { - log::info!("{}", balance); - } - - Ok(()) -} - -/// Show the amount of claimable rewards -pub async fn display_rewards(node: &DriaOracle) -> Result<()> { - let allowance = node - .allowance(node.addresses.coordinator, node.address()) - .await?; - - log::info!("Claimable rewards:"); - log::info!("{} ", allowance); - if allowance.amount.is_zero() { - log::warn!("You have no claimable rewards!"); - } - - Ok(()) -} - -/// Claim rewards -pub async fn claim_rewards(node: &DriaOracle) -> Result<()> { - // get allowance - let allowance = node - .allowance(node.addresses.coordinator, node.address()) - .await?; - - // check if there are rewards to claim - if allowance.amount.is_zero() { - log::warn!("No rewards to claim."); - } else { - // transfer rewards - node.transfer_from(node.addresses.coordinator, node.address(), allowance.amount) - .await?; - log::info!("Rewards claimed: {}.", allowance); - } - - Ok(()) -} diff --git a/src/compute/generation/request.rs b/src/compute/generation/request.rs index c4d128f..a1385e0 100644 --- a/src/compute/generation/request.rs +++ b/src/compute/generation/request.rs @@ -15,11 +15,11 @@ pub struct ChatHistoryRequest { /// An oracle request. #[derive(Debug)] pub enum GenerationRequest { - /// A chat-history request. + /// A chat-history request, usually indicates a previous response to be continued upon. ChatHistory(ChatHistoryRequest), - /// The request itself is a Workflow object, we execute it directly. + /// A Workflow object, can be executed directly. Workflow(Workflow), - /// The request is a plain string, we execute it within a generation workflow. + /// A plain string request, can be executed with a generation workflow. String(String), } @@ -84,11 +84,13 @@ mod tests { #[tokio::test] async fn test_parse_request_arweave() { // contains the string: "\"Hello, Arweave!\"" - // hex for: Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA - let arweave_key = "660e826587f15c25989c2b8a1299d90987f2ee0862b75fefe3e0427b9de25ae0"; + let arweave_key = serde_json::json!({ + "arweave": "Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA" + }) + .to_string(); let expected_str = "\"Hello, Arweave!\""; - let entry = GenerationRequest::try_parse_bytes(&arweave_key.as_bytes().into()).await; + let entry = GenerationRequest::try_parse_bytes(&arweave_key.into()).await; assert_eq!( entry.unwrap(), GenerationRequest::String(expected_str.into()) @@ -108,12 +110,12 @@ mod tests { #[tokio::test] async fn test_parse_request_workflow() { - use alloy::hex::FromHex; - - // task 21402 input - // 0x30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463 - let input_bytes = Bytes::from_hex("30306234343365613266393739626263353263613565363131376534646366353634366662316365343265663566643363643564646638373533643538323463").unwrap(); - let workflow = GenerationRequest::try_parse_bytes(&input_bytes) + // contains a workflow + let arweave_key = serde_json::json!({ + "arweave": "ALRD6i-Xm7xSyl5hF-Tc9WRvsc5C71_TzV3fh1PVgkw" + }) + .to_string(); + let workflow = GenerationRequest::try_parse_bytes(&arweave_key.into()) .await .unwrap(); if let GenerationRequest::Workflow(_) = workflow { diff --git a/src/compute/validation/execute.rs b/src/compute/validation/execute.rs index d18e108..0b3a324 100644 --- a/src/compute/validation/execute.rs +++ b/src/compute/validation/execute.rs @@ -24,10 +24,10 @@ impl ValidationResult { /// Clamps the score to the range `[1, 5]` and scales it to the range `[1-255]`. pub fn final_score_as_solidity_type(&self) -> U256 { U256::from(match self.final_score.clamp(1, 5) { - 1 => 1, - 2 => 64, - 3 => 85, - 4 => 127, + 1 => 51, + 2 => 102, + 3 => 153, + 4 => 204, 5 => 255, _ => unreachable!(), }) @@ -65,7 +65,7 @@ mod tests { #[tokio::test] #[ignore = "requires OpenAI API key"] - async fn test_validation() { + async fn test_validation_multiple() { dotenvy::dotenv().unwrap(); let instruction = "What is 2 + 2".to_string(); @@ -111,4 +111,23 @@ mod tests { "expected minimum score from correct but irrelevant response" ); } + + #[tokio::test] + #[ignore = "requires OpenAI API key"] + async fn test_validation_single() { + dotenvy::dotenv().unwrap(); + + let instruction = "Can humans eat mango fruit?".to_string(); + let generations: Vec = ["Yes they can."].iter().map(|s| s.to_string()).collect(); + + let model = Model::GPT4oMini; + let results = execute_validations(instruction, generations.clone(), model) + .await + .unwrap(); + + assert!( + results[0].final_score == 5, + "expected top score from correct response" + ); + } } diff --git a/src/compute/validation/handler.rs b/src/compute/validation/handler.rs index 2b13f7f..8bcb238 100644 --- a/src/compute/validation/handler.rs +++ b/src/compute/validation/handler.rs @@ -60,6 +60,7 @@ pub async fn handle_validation( .collect::>(); let metadata = serde_json::to_string(&validations).wrap_err("could not serialize validations")?; + log::debug!("Validation metadata:\n{}", metadata); // uploading to storage log::debug!("Uploading metadata to storage"); diff --git a/src/compute/validation/workflow.rs b/src/compute/validation/workflow.rs index 611d62a..044cf07 100644 --- a/src/compute/validation/workflow.rs +++ b/src/compute/validation/workflow.rs @@ -10,94 +10,92 @@ pub fn make_validation_workflow( generations.reverse(); let workflow = json!({ - "config": { - "max_steps": generations.len() + 5, // we need one step per generation, plus some leeway here - "max_time": generations.len() * 4 + 10, // we need at most 4 seconds per generation, plus some leeway here - "tools": [ - "ALL" - ], - "max_tokens": 1000 // max tokens do not need to change + "config": { + "max_steps": generations.len() + 5, // we need one step per generation, plus some leeway here + "max_time": generations.len() * 5 + 10, // we need at most few seconds per generation, plus some leeway here + "tools": ["ALL"], + "max_tokens": 1000 // max tokens do not need to change }, "external_memory": { "instruction": instruction, "generations": generations }, - "tasks": [ - { - "id": "evaluate", - "name": "Task", - "description": "Task Description", - "messages": [ - { - "role": "user", - "content": "\n# Instruction Following Assessment\n\nEvaluate alignment between output and intent. Assess understanding of task goal and restrictions.\n\n**Instruction Components**: Task Goal (intended outcome), Restrictions (text styles, formats, or designated methods, etc).\n\n**Scoring**: Rate outputs 1 to 5:\n\n1. **Irrelevant**: No alignment.\n\n2. **Partial Focus**: Addresses one aspect poorly.\n\n3. **Partial Compliance**:\n\n- (1) Meets goal or restrictions, neglecting other.\n\n- (2) Acknowledges both but slight deviations.\n\n4. **Almost There**: Near alignment, minor deviations.\n\n5. **Comprehensive Compliance**: Fully aligns, meets all requirements.\n\n## Format:\n\n### Input\n\nInstruction: Write a compelling product description \n\nTexts:\n\n The sleek smartphone features a 6.1\" display\n\n Buy this phone it has good screen\n\n Experience crystal-clear visuals on the stunning 6.1\" OLED display\n\n### Output\n\n### Output for Text 1\n\n{\n \"score\": 3,\n \"rationale\": \"Basic description with specs but lacks compelling language.\"\n}\n\n### Output for Text 2\n\n{\n \"score\": 1,\n \"rationale\": \"Too informal and vague. Missing specific details.\"\n}\n\n### Output for Text 3\n\n{\n \"score\": 5,\n \"rationale\": \"Uses engaging language. Includes specific features. Creates desire.\"\n}\n\n---\n \n## Annotation\n\n### Input\n\nInstruction: {{instruction}}\n\nTexts:\n\n{{generations}}\n\n### Output" - } - ], - "schema": "{\"properties\": {\"instruction_following\": {\"description\": \"The score for the instruction following ability.\", \"gte\": 1, \"lte\": 5, \"title\": \"Instruction Following\", \"type\": \"integer\"}, \"truthfulness\": {\"description\": \"The score for the truthfulness of the response.\", \"gte\": 1, \"lte\": 5, \"title\": \"Truthfulness\", \"type\": \"integer\"}, \"helpfulness\": {\"description\": \"The score for the helpfulness of the response.\", \"gte\": 1, \"lte\": 5, \"title\": \"Helpfulness\", \"type\": \"integer\"}, \"final_score\": {\"description\": \"The overall score of the evaluation.\", \"gte\": 1, \"lte\": 5, \"title\": \"Final Score\", \"type\": \"integer\"}, \"rationale\": {\"description\": \"The rationale of the evaluation.\", \"title\": \"Rationale\", \"type\": \"string\"}}, \"required\": [\"instruction_following\", \"truthfulness\", \"helpfulness\", \"final_score\", \"rationale\"], \"title\": \"Evaluation\", \"type\": \"object\", \"additionalProperties\": false}", - "inputs": [ + "tasks": [ { - "name": "instruction", - "value": { - "type": "read", - "key": "instruction" - }, - "required": true + "id": "evaluate", + "name": "Task", + "description": "Task Description", + "messages": [ + { + "role": "user", + "content": "\n# Instruction Following Assessment\n\nEvaluate alignment between output and intent. Assess understanding of task goal and restrictions.\n\n**Instruction Components**: Task Goal (intended outcome), Restrictions (text styles, formats, or designated methods, etc).\n\n**Scoring**: Rate outputs 1 to 5:\n\n1. **Irrelevant**: No alignment.\n\n2. **Partial Focus**: Addresses one aspect poorly.\n\n3. **Partial Compliance**:\n\n- (1) Meets goal or restrictions, neglecting other.\n\n- (2) Acknowledges both but slight deviations.\n\n4. **Almost There**: Near alignment, minor deviations.\n\n5. **Comprehensive Compliance**: Fully aligns, meets all requirements.\n\n## Format:\n\n### Input\n\nInstruction: Write a compelling product description \n\nTexts:\n\n The sleek smartphone features a 6.1\" display\n\n Buy this phone it has good screen\n\n Experience crystal-clear visuals on the stunning 6.1\" OLED display\n\n### Output\n\n### Output for Text 1\n\n{\n \"score\": 3,\n \"rationale\": \"Basic description with specs but lacks compelling language.\"\n}\n\n### Output for Text 2\n\n{\n \"score\": 1,\n \"rationale\": \"Too informal and vague. Missing specific details.\"\n}\n\n### Output for Text 3\n\n{\n \"score\": 5,\n \"rationale\": \"Uses engaging language. Includes specific features. Creates desire.\"\n}\n\n---\n \n## Annotation\n\n### Input\n\nInstruction: {{instruction}}\n\nTexts:\n\n{{generations}}\n\n### Output" + } + ], + "schema": "{\"properties\": {\"instruction_following\": {\"description\": \"The score for the instruction following ability.\", \"gte\": 1, \"lte\": 5, \"title\": \"Instruction Following\", \"type\": \"integer\"}, \"truthfulness\": {\"description\": \"The score for the truthfulness of the response.\", \"gte\": 1, \"lte\": 5, \"title\": \"Truthfulness\", \"type\": \"integer\"}, \"helpfulness\": {\"description\": \"The score for the helpfulness of the response.\", \"gte\": 1, \"lte\": 5, \"title\": \"Helpfulness\", \"type\": \"integer\"}, \"final_score\": {\"description\": \"The overall score of the evaluation.\", \"gte\": 1, \"lte\": 5, \"title\": \"Final Score\", \"type\": \"integer\"}, \"rationale\": {\"description\": \"The rationale of the evaluation.\", \"title\": \"Rationale\", \"type\": \"string\"}}, \"required\": [\"instruction_following\", \"truthfulness\", \"helpfulness\", \"final_score\", \"rationale\"], \"title\": \"Evaluation\", \"type\": \"object\", \"additionalProperties\": false}", + "inputs": [ + { + "name": "instruction", + "value": { + "type": "read", + "key": "instruction" + }, + "required": true + }, + { + "name": "generations", + "value": { + "type": "pop", + "key": "generations" + }, + "required": true + } + ], + "operator": "generation", + "outputs": [ + { + "type": "push", + "key": "search_result", + "value": "__result" + } + ] }, { - "name": "generations", - "value": { - "type": "pop", - "key": "generations" - }, - "required": true - } - ], - "operator": "generation", - "outputs": [ - { - "type": "push", - "key": "search_result", - "value": "__result" + "id": "_end", + "name": "Task", + "description": "Task Description", + "messages": [ + { + "role": "user", + "content": "" + } + ], + "inputs": [], + "operator": "end", + "outputs": [] } - ] - }, - { - "id": "_end", - "name": "Task", - "description": "Task Description", - "messages": [ + ], + "steps": [ { - "role": "user", - "content": "" + "source": "evaluate", + "target": "_end", + "condition": { + "input": { + "type": "size", + "key": "generations" + }, + "expected": "0", + "expression": "Equal", + "target_if_not": "evaluate" + } } - ], - "inputs": [], - "operator": "end", - "outputs": [] - } - ], - "steps": [ - { - "source": "evaluate", - "target": "_end", - "condition": { + ], + "return_value": { "input": { - "type": "size", - "key": "generations" + "type": "get_all", + "key": "search_result" }, - "expected": "0", - "expression": "Equal", - "target_if_not": "evaluate" - } + "to_json": true } - ], - "return_value": { - "input": { - "type": "get_all", - "key": "search_result" - }, - "to_json": true - } }); serde_json::from_value(workflow) diff --git a/src/contracts/abi/LLMOracleRegistry.json b/src/contracts/abi/LLMOracleRegistry.json index bead96d..d0ab485 100644 --- a/src/contracts/abi/LLMOracleRegistry.json +++ b/src/contracts/abi/LLMOracleRegistry.json @@ -74,6 +74,13 @@ "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], "stateMutability": "view" }, + { + "type": "function", + "name": "isWhitelisted", + "inputs": [{ "name": "", "type": "address", "internalType": "address" }], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, { "type": "function", "name": "minRegistrationTime", @@ -224,13 +231,6 @@ "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], "stateMutability": "view" }, - { - "type": "function", - "name": "whitelisted", - "inputs": [{ "name": "", "type": "address", "internalType": "address" }], - "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], - "stateMutability": "view" - }, { "type": "event", "name": "AddedToWhitelist", diff --git a/src/contracts/addresses.rs b/src/contracts/addresses.rs index aa056d8..88ff069 100644 --- a/src/contracts/addresses.rs +++ b/src/contracts/addresses.rs @@ -47,8 +47,8 @@ lazy_static! { BaseSepolia.into(), ContractAddresses { token: address!("4200000000000000000000000000000000000006"), - registry: address!("bff452f736c0a2c0122b6d629c4d996274703d3b"), - coordinator: address!("1deaca041f094ec67baa4fb36d333cb652e6b7a7"), + registry: address!("408d245a853137e44a2465d5c66061f97582eae9"), + coordinator: address!("13f977bde221b470d3ae055cde7e1f84debfe202"), }, ); diff --git a/src/contracts/errors.rs b/src/contracts/errors.rs index 1f3f360..7aa85c1 100644 --- a/src/contracts/errors.rs +++ b/src/contracts/errors.rs @@ -1,6 +1,5 @@ use alloy::contract::Error; use alloy::primitives::utils::format_ether; -use alloy::transports::RpcError; use eyre::{eyre, ErrReport}; use super::OracleCoordinator::OracleCoordinatorErrors; @@ -19,6 +18,9 @@ pub fn contract_error_report(error: Error) -> ErrReport { "Unknown function: function with selector {} does not exist", selector ), + Error::PendingTransactionError(tx) => { + eyre!("Transaction is pending: {:?}", tx) + } Error::NotADeploymentTransaction => { eyre!("Transaction is not a deployment transaction") } @@ -27,7 +29,7 @@ pub fn contract_error_report(error: Error) -> ErrReport { Error::TransportError(error) => { // here we try to parse the error w.r.t provided contract interfaces // or return a default one in the end if it was not parsed successfully - if let RpcError::ErrorResp(payload) = error { + if let Some(payload) = error.as_error_resp() { payload .as_decoded_error(false) .map(ERC20Errors::into) @@ -41,7 +43,7 @@ pub fn contract_error_report(error: Error) -> ErrReport { .as_decoded_error(false) .map(OracleCoordinatorErrors::into) }) - .unwrap_or(eyre!("Unhandled contract error: {}", payload)) + .unwrap_or(eyre!("Unhandled contract error: {:#?}", error)) } else { eyre!("Unknown transport error: {:#?}", error) } @@ -89,8 +91,41 @@ impl From for ErrReport { } OracleRegistryErrors::OwnableUnauthorizedAccount(e) => { eyre!("Unauthorized account: {}", e.account) + } // _ => eyre!("Unhandled Oracle registry error"), + OracleRegistryErrors::TooEarlyToUnregister(e) => { + eyre!( + "Too early to unregister: {} secs remaining", + e.minTimeToWait + ) + } + OracleRegistryErrors::NotWhitelisted(e) => { + eyre!("Validator {} is not whitelisted", e.validator) + } + // generic + OracleRegistryErrors::FailedCall(_) => { + eyre!("Failed call",) + } + OracleRegistryErrors::ERC1967InvalidImplementation(e) => { + eyre!("Invalid implementation: {}", e.implementation) + } + OracleRegistryErrors::UUPSUnauthorizedCallContext(_) => { + eyre!("Unauthorized UUPS call context",) + } + OracleRegistryErrors::UUPSUnsupportedProxiableUUID(e) => { + eyre!("Unsupported UUPS proxiable UUID: {}", e.slot) + } + OracleRegistryErrors::ERC1967NonPayable(_) => { + eyre!("ERC1967 Non-payable") + } + OracleRegistryErrors::InvalidInitialization(_) => { + eyre!("Invalid initialization") + } + OracleRegistryErrors::AddressEmptyCode(e) => { + eyre!("Address {} is empty", e.target) + } + OracleRegistryErrors::NotInitializing(_) => { + eyre!("Not initializing",) } - _ => eyre!("Unhandled Oracle registry error"), } } } @@ -133,7 +168,31 @@ impl From for ErrReport { OracleCoordinatorErrors::OwnableUnauthorizedAccount(e) => { eyre!("Unauthorized account: {}", e.account) } - _ => eyre!("Unhandled Oracle coordinator error"), + // generic + OracleCoordinatorErrors::FailedInnerCall(_) => { + eyre!("Failed inner call",) + } + OracleCoordinatorErrors::ERC1967InvalidImplementation(e) => { + eyre!("Invalid implementation: {}", e.implementation) + } + OracleCoordinatorErrors::UUPSUnauthorizedCallContext(_) => { + eyre!("Unauthorized UUPS call context",) + } + OracleCoordinatorErrors::UUPSUnsupportedProxiableUUID(e) => { + eyre!("Unsupported UUPS proxiable UUID: {}", e.slot) + } + OracleCoordinatorErrors::ERC1967NonPayable(_) => { + eyre!("ERC1967 Non-payable") + } + OracleCoordinatorErrors::InvalidInitialization(_) => { + eyre!("Invalid initialization") + } + OracleCoordinatorErrors::AddressEmptyCode(e) => { + eyre!("Address {} is empty", e.target) + } + OracleCoordinatorErrors::NotInitializing(_) => { + eyre!("Not initializing",) + } } } } @@ -152,9 +211,9 @@ mod tests { // tries to register if registered, or opposite, to trigger an error const KIND: OracleKind = OracleKind::Generator; let result = if node.is_registered(KIND).await? { - node.register(KIND).await + node.register_kind(KIND).await } else { - node.unregister(KIND).await + node.unregister_kind(KIND).await }; assert!(result.is_err()); diff --git a/src/lib.rs b/src/lib.rs index 65a48ff..784e183 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,5 @@ pub use contracts::{bytes32_to_string, bytes_to_string, string_to_bytes, string_ pub use contracts::{OracleCoordinator, OracleRegistry, ERC20, WETH}; pub use contracts::{OracleKind, TaskStatus}; -/// Commands to interact with the oracle contracts. -pub mod commands; - /// External data storage, such as Arweave. pub mod storage; diff --git a/src/main.rs b/src/main.rs index 67c6656..edaa368 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,20 @@ +use std::env; + #[tokio::main] async fn main() -> eyre::Result<()> { let dotenv_result = dotenvy::dotenv(); + let default_log = if env::var("DEBUG").is_ok() { + log::LevelFilter::Debug + } else { + log::LevelFilter::Info + }; env_logger::builder() .format_timestamp(Some(env_logger::TimestampPrecision::Millis)) .filter(None, log::LevelFilter::Off) - .filter_module("dria_oracle", log::LevelFilter::Info) - .filter_module("dkn_workflows", log::LevelFilter::Info) - .parse_default_env() // reads RUST_LOG variable + .filter_module("dria_oracle", default_log) + .filter_module("dkn_workflows", default_log) + .parse_default_env() .init(); // log about env usage diff --git a/src/node/coordinator.rs b/src/node/coordinator.rs index f51b3e7..7382f68 100644 --- a/src/node/coordinator.rs +++ b/src/node/coordinator.rs @@ -3,14 +3,13 @@ use super::{DriaOracle, DriaOracleProviderTransport}; use crate::contracts::*; use alloy::contract::EventPoller; use alloy::eips::BlockNumberOrTag; +use alloy::primitives::aliases::U40; use alloy::primitives::{Bytes, U256}; use alloy::rpc::types::{Log, TransactionReceipt}; use eyre::{eyre, Context, Result}; +use LLMOracleTask::{TaskResponse, TaskValidation}; use OracleCoordinator::LLMOracleTaskParameters; -use OracleCoordinator::{ - getResponsesReturn, getValidationsReturn, requestsReturn, StatusUpdate, TaskResponse, - TaskValidation, -}; +use OracleCoordinator::{getResponsesReturn, getValidationsReturn, requestsReturn, StatusUpdate}; impl DriaOracle { /// Request an oracle task. This is not done by the oracle normally, but we have it added for testing purposes. @@ -27,8 +26,8 @@ impl DriaOracle { let parameters = LLMOracleTaskParameters { difficulty, - numGenerations: num_gens, - numValidations: num_vals, + numGenerations: U40::from(num_gens), + numValidations: U40::from(num_vals), }; let req = coordinator.request(string_to_bytes32(protocol)?, input, models, parameters); let tx = req @@ -189,8 +188,8 @@ impl DriaOracle { let parameters = LLMOracleTaskParameters { difficulty, - numGenerations: num_gens, - numValidations: num_vals, + numGenerations: U40::from(num_gens), + numValidations: U40::from(num_vals), }; let fees = coordinator.getFee(parameters).call().await?; diff --git a/src/node/mod.rs b/src/node/mod.rs index a40a455..120f018 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -8,7 +8,7 @@ mod anvil; use super::DriaOracleConfig; use crate::contracts::*; use alloy::providers::fillers::{ - ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller, + BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller, }; use alloy::providers::WalletProvider; use alloy::{ @@ -25,7 +25,10 @@ use std::env; type DriaOracleProviderTransport = Http; type DriaOracleProvider = FillProvider< JoinFill< - JoinFill, NonceFiller>, ChainIdFiller>, + JoinFill< + Identity, + JoinFill>>, + >, WalletFiller, >, RootProvider, diff --git a/src/node/registry.rs b/src/node/registry.rs index 915320a..f3dc21e 100644 --- a/src/node/registry.rs +++ b/src/node/registry.rs @@ -1,11 +1,11 @@ use super::{DriaOracle, TokenBalance}; use crate::{node::contract_error_report, OracleKind, OracleRegistry, ERC20}; -use alloy::rpc::types::TransactionReceipt; +use alloy::{primitives::Address, rpc::types::TransactionReceipt}; use eyre::{eyre, Context, Result}; impl DriaOracle { /// Register the oracle with the registry. - pub async fn register(&self, kind: OracleKind) -> Result { + pub async fn register_kind(&self, kind: OracleKind) -> Result { let registry = OracleRegistry::new(self.addresses.registry, &self.provider); let req = registry.register(kind.into()); @@ -13,7 +13,7 @@ impl DriaOracle { .send() .await .map_err(contract_error_report) - .wrap_err(eyre!("Could not register."))?; + .wrap_err(eyre!("could not register"))?; log::info!("Hash: {:?}", tx.tx_hash()); let receipt = tx @@ -24,7 +24,7 @@ impl DriaOracle { } /// Unregister from the oracle registry. - pub async fn unregister(&self, kind: OracleKind) -> Result { + pub async fn unregister_kind(&self, kind: OracleKind) -> Result { let registry = OracleRegistry::new(self.addresses.registry, &self.provider); let req = registry.unregister(kind.into()); @@ -69,4 +69,32 @@ impl DriaOracle { Some(self.addresses.token), )) } + + /// Returns whether a given address is whitelisted or not. + pub async fn is_whitelisted(&self, address: Address) -> Result { + let registry = OracleRegistry::new(self.addresses.registry, &self.provider); + + let is_whitelisted = registry.isWhitelisted(address).call().await?; + Ok(is_whitelisted._0) + } + + /// Whitelists a given address, only callable by the owner. + pub async fn whitelist(&self, address: Address) -> Result { + let registry = OracleRegistry::new(self.addresses.registry, &self.provider); + + let req = registry.addToWhitelist(vec![address]); + let tx = req + .send() + .await + .map_err(contract_error_report) + .wrap_err("could not add to whitelist")?; + + log::info!("Hash: {:?}", tx.tx_hash()); + let receipt = tx + .with_timeout(self.config.tx_timeout) + .get_receipt() + .await?; + + Ok(receipt) + } } diff --git a/tests/oracle_test.rs b/tests/oracle_test.rs index d12d609..f5cd054 100644 --- a/tests/oracle_test.rs +++ b/tests/oracle_test.rs @@ -1,11 +1,17 @@ -use alloy::{eips::BlockNumberOrTag, primitives::utils::parse_ether}; -use dria_oracle::{ - bytes_to_string, commands, handle_request, string_to_bytes, DriaOracle, DriaOracleConfig, - OracleKind, TaskStatus, WETH, +use alloy::{ + eips::BlockNumberOrTag, + primitives::{address, utils::parse_ether, Address, U256}, + providers::ext::AnvilApi, }; use dkn_workflows::{DriaWorkflowsConfig, Model}; +use dria_oracle::{ + bytes_to_string, handle_request, string_to_bytes, DriaOracle, DriaOracleConfig, OracleKind, + TaskStatus, WETH, +}; use eyre::Result; +const REGISTRY_OWNER: Address = address!("2aA47BC684aEC9093AB9E85c2CB19052887c1Aee"); + #[tokio::test] async fn test_oracle_string_input() -> Result<()> { dotenvy::dotenv().unwrap(); @@ -38,19 +44,35 @@ async fn test_oracle_string_input() -> Result<()> { for node in [&requester, &generator, &validator] { let token = WETH::new(node.addresses.token, &node.provider); let balance_before = node.get_token_balance(node.address()).await?; - let _ = token.deposit().value(amount).send().await?; + + let call = token.deposit().value(amount); + let _ = call.send().await?.get_receipt().await?; + let balance_after = node.get_token_balance(node.address()).await?; assert!(balance_after.amount > balance_before.amount); } - // register generator oracle - commands::register(&generator, OracleKind::Generator).await?; - assert!(generator.is_registered(OracleKind::Generator).await?); + // whitelist validator with impersonation + log::info!("Whitelisting validator"); + node.provider + .anvil_impersonate_account(REGISTRY_OWNER) + .await?; + node.provider.anvil_mine(Some(U256::from(1)), None).await?; + node.whitelist(validator.address()).await?; + node.provider + .anvil_stop_impersonating_account(REGISTRY_OWNER) + .await?; + + assert!(node.is_whitelisted(validator.address()).await?); // register validator oracle - commands::register(&validator, OracleKind::Validator).await?; + validator.register(OracleKind::Validator).await?; assert!(validator.is_registered(OracleKind::Validator).await?); + // register generator oracle + generator.register(OracleKind::Generator).await?; + assert!(generator.is_registered(OracleKind::Generator).await?); + // approve some tokens for the coordinator from requester requester .approve(node.addresses.coordinator, amount) diff --git a/tests/request_test.rs b/tests/request_test.rs index f9a69ba..54d7b4a 100644 --- a/tests/request_test.rs +++ b/tests/request_test.rs @@ -4,15 +4,22 @@ //! 2. Requester requests a task with a given input, models, difficulty, num_gens, and num_vals. //! 3. The task is created in the coordinator contract. -use alloy::primitives::utils::parse_ether; +use alloy::primitives::{aliases::U40, utils::parse_ether}; use dkn_workflows::Model; -use dria_oracle::{bytes_to_string, commands, DriaOracle, DriaOracleConfig, WETH}; +use dria_oracle::{bytes_to_string, DriaOracle, DriaOracleConfig, WETH}; use eyre::Result; #[tokio::test] async fn test_request() -> Result<()> { dotenvy::dotenv().unwrap(); + let _ = env_logger::builder() + .filter_level(log::LevelFilter::Off) + .filter_module("dria_oracle", log::LevelFilter::Debug) + .filter_module("request_test", log::LevelFilter::Debug) + .is_test(true) + .try_init(); + // task setup let (difficulty, num_gens, num_vals) = (1, 1, 1); let protocol = format!("test/{}", env!("CARGO_PKG_VERSION")); @@ -30,17 +37,16 @@ async fn test_request() -> Result<()> { // request a task, and see it in the coordinator let task_id = node.get_next_task_id().await?; - commands::request_task( - &requester, &input, models, difficulty, num_gens, num_vals, protocol, - ) - .await?; + requester + .request_task(&input, models, difficulty, num_gens, num_vals, protocol) + .await?; // get the task info let (request, _, _) = node.get_task(task_id).await?; assert_eq!(input, bytes_to_string(&request.input).unwrap()); assert_eq!(difficulty, request.parameters.difficulty); - assert_eq!(num_gens, request.parameters.numGenerations); - assert_eq!(num_vals, request.parameters.numValidations); + assert_eq!(U40::from(num_gens), request.parameters.numGenerations); + assert_eq!(U40::from(num_vals), request.parameters.numValidations); Ok(()) } diff --git a/tests/swan_test.rs b/tests/swan_test.rs index be6d3bc..307e856 100644 --- a/tests/swan_test.rs +++ b/tests/swan_test.rs @@ -5,17 +5,22 @@ use alloy::{ }; use dkn_workflows::{DriaWorkflowsConfig, Model}; use dria_oracle::{ - bytes_to_string, commands, handle_request, string_to_bytes, DriaOracle, DriaOracleConfig, - OracleKind, TaskStatus, WETH, + bytes_to_string, handle_request, string_to_bytes, DriaOracle, DriaOracleConfig, OracleKind, + TaskStatus, WETH, }; use eyre::Result; -// TODO: move this to Swan post-process file - #[tokio::test] async fn test_swan() -> Result<()> { dotenvy::dotenv().unwrap(); + let _ = env_logger::builder() + .filter_level(log::LevelFilter::Off) + .filter_module("dria_oracle", log::LevelFilter::Debug) + .filter_module("swan_test", log::LevelFilter::Debug) + .is_test(true) + .try_init(); + // task setup let difficulty = 1; let models = string_to_bytes(Model::GPT4Turbo.to_string()); @@ -33,7 +38,7 @@ async fn test_swan() -> Result<()> { .to_string(), ); - println!("Input: {}", bytes_to_string(&input)?); + log::info!("Input: {}", bytes_to_string(&input)?); // node setup let workflows = DriaWorkflowsConfig::new(vec![Model::GPT4Turbo]); @@ -46,21 +51,27 @@ async fn test_swan() -> Result<()> { let validator = node.connect(node.anvil_funded_wallet(None).await?); // buy some WETH for all people + log::info!("Buying WETH for all accounts"); let amount = parse_ether("100").unwrap(); for node in [&requester, &generator, &validator] { - let token = WETH::new(node.addresses.token, &node.provider); let balance_before = node.get_token_balance(node.address()).await?; - let _ = token.deposit().value(amount).send().await?; + + let token = WETH::new(node.addresses.token, &node.provider); + let call = token.deposit().value(amount); + let _ = call.send().await?.get_receipt().await?; + let balance_after = node.get_token_balance(node.address()).await?; assert!(balance_after.amount > balance_before.amount); } // register generator oracle - commands::register(&generator, OracleKind::Generator).await?; + log::info!("Registering generator"); + generator.register(OracleKind::Generator).await?; assert!(generator.is_registered(OracleKind::Generator).await?); // register validator oracle - commands::register(&validator, OracleKind::Validator).await?; + log::info!("Registering validator"); + validator.register(OracleKind::Validator).await?; assert!(validator.is_registered(OracleKind::Validator).await?); // approve some tokens for the coordinator from requester diff --git a/tests/weth_test.rs b/tests/weth_test.rs index 623d50c..46ce42c 100644 --- a/tests/weth_test.rs +++ b/tests/weth_test.rs @@ -31,7 +31,8 @@ async fn test_weth_transfer() -> Result<()> { let bob_balance_before = node.get_token_balance(bob.address()).await?; // alice buys WETH - let _ = alice_token.deposit().value(amount).send().await?; + let call = alice_token.deposit().value(amount); + let _ = call.send().await?.get_receipt().await?; let alice_balance_after = node.get_token_balance(alice.address()).await?; assert_eq!( alice_balance_after.amount - alice_balance_before.amount, @@ -39,13 +40,14 @@ async fn test_weth_transfer() -> Result<()> { ); // alice approves bob - let _ = alice_token.approve(bob.address(), amount).send().await?; + let call = alice_token.approve(bob.address(), amount); + let _ = call.send().await?.get_receipt().await?; // bob transfers WETH from alice - let _ = bob_token - .transferFrom(alice.address(), bob.address(), amount) - .send() - .await?; + let call = bob_token.transferFrom(alice.address(), bob.address(), amount); + let _ = call.send().await?.get_receipt().await?; + + // balances should be updated let alice_balance_after = node.get_token_balance(alice.address()).await?; let bob_balance_after = node.get_token_balance(bob.address()).await?; assert_eq!(alice_balance_after.amount, alice_balance_before.amount); From c7f5b46d907c7fe54e847044a0c1a8c6cd684177 Mon Sep 17 00:00:00 2001 From: erhant Date: Fri, 13 Dec 2024 13:00:59 +0300 Subject: [PATCH 11/14] add timeouts --- src/cli/commands/coordinator.rs | 2 +- src/compute/generation/execute.rs | 25 +++++++++++++++---------- src/compute/generation/workflow.rs | 15 ++++++++++++--- src/compute/validation/execute.rs | 9 +++++++-- src/compute/validation/workflow.rs | 12 +++++++++--- 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/cli/commands/coordinator.rs b/src/cli/commands/coordinator.rs index f0a573b..a1a148b 100644 --- a/src/cli/commands/coordinator.rs +++ b/src/cli/commands/coordinator.rs @@ -195,7 +195,7 @@ impl DriaOracle { task_id, log.transaction_hash.unwrap_or_default() ); - match handle_request(self, &kinds, &model_config, event).await { + match handle_request(self, &kinds, model_config, event).await { Ok(Some(receipt)) => { log::info!( "Task {} processed successfully. (tx: {})", diff --git a/src/compute/generation/execute.rs b/src/compute/generation/execute.rs index c9a5216..4ff2400 100644 --- a/src/compute/generation/execute.rs +++ b/src/compute/generation/execute.rs @@ -31,11 +31,13 @@ pub async fn execute_generation( // string requests are used with the generation workflow with a given prompt GenerationRequest::String(input) => { - let workflow = make_generation_workflow(input.clone())?; - executor - .execute(None, &workflow, &mut memory) - .await - .wrap_err("could not execute worfklow for string input") + let (workflow, duration) = make_generation_workflow(input.clone())?; + tokio::select! { + result = executor.execute(None, &workflow, &mut memory) => result.wrap_err("could not execute worfklow for string input"), + _ = tokio::time::sleep(duration) => { + Err(eyre!("Generation workflow timed out")) + } + } } // chat history requests are used with the chat workflow @@ -60,11 +62,14 @@ pub async fn execute_generation( }; // prepare the workflow with chat history - let workflow = make_chat_workflow(history.clone(), chat_request.content.clone())?; - let output = executor - .execute(None, &workflow, &mut memory) - .await - .wrap_err("could not execute chat worfklow")?; + let (workflow, duration) = + make_chat_workflow(history.clone(), chat_request.content.clone())?; + let output = tokio::select! { + result = executor.execute(None, &workflow, &mut memory) => result.wrap_err("could not execute chat worfklow")?, + _ = tokio::time::sleep(duration) => { + return Err(eyre!("Generation workflow timed out")); + } + }; // append user input to chat history history.push(MessageInput { diff --git a/src/compute/generation/workflow.rs b/src/compute/generation/workflow.rs index d14ec9b..33172e4 100644 --- a/src/compute/generation/workflow.rs +++ b/src/compute/generation/workflow.rs @@ -1,10 +1,14 @@ +use std::time::Duration; + use dkn_workflows::{MessageInput, Workflow}; use serde_json::json; +const MAX_TIME_SEC: u64 = 50; + /// Creates a generation workflow with the given input. /// /// It is an alias for `make_chat_workflow` with a single message alone. -pub fn make_generation_workflow(input: String) -> Result { +pub fn make_generation_workflow(input: String) -> Result<(Workflow, Duration), serde_json::Error> { make_chat_workflow(Vec::new(), input) } @@ -14,13 +18,16 @@ pub fn make_generation_workflow(input: String) -> Result, input: String, -) -> Result { +) -> Result<(Workflow, Duration), serde_json::Error> { // add the new input to the message history as a user message messages.push(MessageInput { role: "user".to_string(), content: input, }); + // we do like this in-case a dynamic assign is needed + let max_time_sec = MAX_TIME_SEC; + let workflow = json!({ "config": { "max_steps": 10, @@ -67,5 +74,7 @@ pub fn make_chat_workflow( } }); - serde_json::from_value(workflow) + let workflow = serde_json::from_value(workflow)?; + + Ok((workflow, Duration::from_secs(max_time_sec))) } diff --git a/src/compute/validation/execute.rs b/src/compute/validation/execute.rs index 0b3a324..ab7361b 100644 --- a/src/compute/validation/execute.rs +++ b/src/compute/validation/execute.rs @@ -40,12 +40,17 @@ pub async fn execute_validations( generations: Vec, model: Model, ) -> Result> { - let workflow = make_validation_workflow(instruction, generations)?; + let (workflow, duration) = make_validation_workflow(instruction, generations)?; log::debug!("Executing validation request with: {}", model); let mut memory = ProgramMemory::new(); let executor = Executor::new(model); - let result_str = executor.execute(None, &workflow, &mut memory).await?; + let result_str = tokio::select! { + result = executor.execute(None, &workflow, &mut memory) => result?, + _ = tokio::time::sleep(duration) => { + return Err(eyre::eyre!("Validation workflow timed out")); + } + }; // first parse as vec of string // then parse each string as a ValidationResult diff --git a/src/compute/validation/workflow.rs b/src/compute/validation/workflow.rs index 044cf07..20b1a8b 100644 --- a/src/compute/validation/workflow.rs +++ b/src/compute/validation/workflow.rs @@ -1,18 +1,22 @@ +use std::time::Duration; + use dkn_workflows::Workflow; use serde_json::json; pub fn make_validation_workflow( instruction: String, mut generations: Vec, -) -> Result { +) -> Result<(Workflow, Duration), serde_json::Error> { // workflow processes the array in reverse order, so we reverse the input outside // to get the correct order in results generations.reverse(); + let max_time_sec = (generations.len() as u64) * 5 + 10; // we need at most few seconds per generation, plus some leeway here + let workflow = json!({ "config": { "max_steps": generations.len() + 5, // we need one step per generation, plus some leeway here - "max_time": generations.len() * 5 + 10, // we need at most few seconds per generation, plus some leeway here + "max_time": max_time_sec, "tools": ["ALL"], "max_tokens": 1000 // max tokens do not need to change }, @@ -98,5 +102,7 @@ pub fn make_validation_workflow( } }); - serde_json::from_value(workflow) + let workflow = serde_json::from_value(workflow)?; + + Ok((workflow, Duration::from_secs(max_time_sec))) } From 9ae0ea03f2ab9de087491a8429dcee8dceca3286 Mon Sep 17 00:00:00 2001 From: erhant Date: Fri, 13 Dec 2024 21:41:54 +0300 Subject: [PATCH 12/14] add better history logic --- README.md | 23 ++++++++++++++++------- src/compute/generation/execute.rs | 23 ++++++++++++++++++++++- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 029ea2d..d8dce1e 100644 --- a/README.md +++ b/README.md @@ -19,19 +19,16 @@ Install Dria Oracle Node with: cargo install --git https://github.com/firstbatchxyz/dria-oracle-node ``` -This will create a binary called `dria-oracle`. You can see the available commands with: - -```sh -dria-oracle help -``` - ## Setup Create an `.env` file by copying `.env.example`. You have to fill the following variables: - Get an RPC URL from a provider such as Alchemy or Infura, and set it as `RPC_URL`. - Provide an Ethereum wallet secret koy to `SECRET_KEY`, make sure it has funds to pay for gas and tokens. -- Provide an Arweave wallet so that you can use Arweave for large results. Alternatively, dont provide a wallet but instead set `ARWEAVE_BYTE_LIMIT` to a very large value. + +Optionally, you can save gas costs using Arweave: + +- Provide an Arweave wallet so that you can use Arweave for large results. Alternatively, dont provide a wallet but instead set `ARWEAVE_BYTE_LIMIT` to a very large value. TODO: this should be done automatically if wallet does not exist As for the LLM providers: @@ -42,6 +39,12 @@ As for the LLM providers: ## Usage +After installatioon, a binary called `dria-oracle` will be created. You can see the available commands with: + +```sh +dria-oracle help +``` + The CLI provides several methods to interact with the oracle contracts. - [Registration](#registration) @@ -147,6 +150,12 @@ The `request` command takes the following options: > > Making a request from the Oracle node is mainly for testing purposes, and you are not expected to use this command at all. Furthermore, it is only used to make plaintext requests, instead of larger ones via Arweave or more complex ones via Workflows. +There are 3 types of requests: + +- **String**: simple text +- **Chat**: an object of the form `{history_id: number, content: string}` which uses a previous task as history; TODO: history > nextTaskId handled? +- **Workflow**: a stringified Workflow object + ## Development If you would like to contribute, please create an issue first! To start developing, clone the repository: diff --git a/src/compute/generation/execute.rs b/src/compute/generation/execute.rs index 4ff2400..ee335d2 100644 --- a/src/compute/generation/execute.rs +++ b/src/compute/generation/execute.rs @@ -56,7 +56,28 @@ pub async fn execute_generation( // parse it as chat history output let history_str = ArweaveStorage::parse_downloadable(&history_task.output).await?; - serde_json::from_str::>(&history_str)? + // if its a previous message array, we can parse it directly + if let Ok(messages) = serde_json::from_str::>(&history_str) { + messages + } else { + // otherwise, we can fallback to fetching input manually and creating a new history on-the-fly + let request = node + .get_task_request(U256::from(chat_request.history_id)) + .await?; + let input = ArweaveStorage::parse_downloadable(&request.input).await?; + + // create a new history with the input + vec![ + MessageInput { + role: "user".to_string(), + content: input, + }, + MessageInput { + role: "assistant".to_string(), + content: history_str, + }, + ] + } } else { return Err(eyre!("node is required for chat history")); }; From cc5adfc5e651065cae4a44d8295aa3a5ac8b9aa7 Mon Sep 17 00:00:00 2001 From: erhant Date: Mon, 16 Dec 2024 15:14:00 +0300 Subject: [PATCH 13/14] whitelist with impersonation, todo typing fix --- src/node/anvil.rs | 35 ++++++++++++++++++++++++++++++++++- src/node/registry.rs | 20 -------------------- tests/oracle_test.rs | 13 +------------ tests/swan_test.rs | 5 +++++ 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/node/anvil.rs b/src/node/anvil.rs index 551909f..dda1efe 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -2,13 +2,18 @@ //! //! This module is only available when the `anvil` feature is enabled. +use crate::node::contract_error_report; +use crate::OracleRegistry; + use super::{DriaOracle, DriaOracleConfig}; use alloy::network::EthereumWallet; use alloy::node_bindings::{Anvil, AnvilInstance}; +use alloy::primitives::Address; use alloy::primitives::{utils::parse_ether, U256}; use alloy::providers::ext::AnvilApi; +use alloy::rpc::types::TransactionReceipt; use alloy::signers::local::PrivateKeySigner; -use eyre::Result; +use eyre::{Context, Result}; impl DriaOracle { /// Default ETH funding amount for generated wallets. @@ -37,4 +42,32 @@ impl DriaOracle { let wallet = EthereumWallet::from(signer); Ok(wallet) } + + /// Whitelists a given address, impersonates the owner in doing so. + pub async fn anvil_whitelist_registry(&self, address: Address) -> Result { + let registry = OracleRegistry::new(self.addresses.registry, &self.provider); + + let owner = registry.owner().call().await?._0; + registry.provider().anvil_impersonate_account(owner).await?; + + let req = registry.addToWhitelist(vec![address]).from(owner); + let tx = req + .send() + .await + .map_err(contract_error_report) + .wrap_err("could not add to whitelist")?; + + log::info!("Hash: {:?}", tx.tx_hash()); + let receipt = tx + .with_timeout(self.config.tx_timeout) + .get_receipt() + .await?; + + registry + .provider() + .anvil_stop_impersonating_account(owner) + .await?; + + Ok(receipt) + } } diff --git a/src/node/registry.rs b/src/node/registry.rs index f3dc21e..0876236 100644 --- a/src/node/registry.rs +++ b/src/node/registry.rs @@ -77,24 +77,4 @@ impl DriaOracle { let is_whitelisted = registry.isWhitelisted(address).call().await?; Ok(is_whitelisted._0) } - - /// Whitelists a given address, only callable by the owner. - pub async fn whitelist(&self, address: Address) -> Result { - let registry = OracleRegistry::new(self.addresses.registry, &self.provider); - - let req = registry.addToWhitelist(vec![address]); - let tx = req - .send() - .await - .map_err(contract_error_report) - .wrap_err("could not add to whitelist")?; - - log::info!("Hash: {:?}", tx.tx_hash()); - let receipt = tx - .with_timeout(self.config.tx_timeout) - .get_receipt() - .await?; - - Ok(receipt) - } } diff --git a/tests/oracle_test.rs b/tests/oracle_test.rs index f5cd054..3720310 100644 --- a/tests/oracle_test.rs +++ b/tests/oracle_test.rs @@ -1,7 +1,6 @@ use alloy::{ eips::BlockNumberOrTag, primitives::{address, utils::parse_ether, Address, U256}, - providers::ext::AnvilApi, }; use dkn_workflows::{DriaWorkflowsConfig, Model}; use dria_oracle::{ @@ -10,8 +9,6 @@ use dria_oracle::{ }; use eyre::Result; -const REGISTRY_OWNER: Address = address!("2aA47BC684aEC9093AB9E85c2CB19052887c1Aee"); - #[tokio::test] async fn test_oracle_string_input() -> Result<()> { dotenvy::dotenv().unwrap(); @@ -54,15 +51,7 @@ async fn test_oracle_string_input() -> Result<()> { // whitelist validator with impersonation log::info!("Whitelisting validator"); - node.provider - .anvil_impersonate_account(REGISTRY_OWNER) - .await?; - node.provider.anvil_mine(Some(U256::from(1)), None).await?; - node.whitelist(validator.address()).await?; - node.provider - .anvil_stop_impersonating_account(REGISTRY_OWNER) - .await?; - + node.anvil_whitelist_registry(validator.address()).await?; assert!(node.is_whitelisted(validator.address()).await?); // register validator oracle diff --git a/tests/swan_test.rs b/tests/swan_test.rs index 307e856..b464d90 100644 --- a/tests/swan_test.rs +++ b/tests/swan_test.rs @@ -64,6 +64,11 @@ async fn test_swan() -> Result<()> { assert!(balance_after.amount > balance_before.amount); } + // whitelist validator with impersonation + log::info!("Whitelisting validator"); + node.anvil_whitelist_registry(validator.address()).await?; + assert!(node.is_whitelisted(validator.address()).await?); + // register generator oracle log::info!("Registering generator"); generator.register(OracleKind::Generator).await?; From 4cf09f5b82adc48a0f844453cd1ef1b5f9713ccd Mon Sep 17 00:00:00 2001 From: erhant Date: Wed, 18 Dec 2024 16:53:57 +0300 Subject: [PATCH 14/14] Erhant/type fixes (#29) * added swan prompt test * update workflows --- Cargo.lock | 231 +++++++++++---------- src/compute/generation/execute.rs | 15 +- src/compute/generation/postprocess/swan.rs | 114 ++++++++++ src/compute/generation/workflow.rs | 17 +- src/compute/validation/execute.rs | 16 +- src/compute/validation/workflow.rs | 4 +- tests/oracle_test.rs | 5 +- 7 files changed, 251 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bbde815..f27155e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,9 +64,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "689e271a72a5c0b05bfdf41c9d0424f11e9df721385dc5bd9045a51f9ea3313b" +checksum = "e7e1758e5d759c0114140152ae72032eafcfdd7b599e995ebbc8eeafa2b4c977" dependencies = [ "alloy-consensus", "alloy-contract", @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba14856660f31807ebb26ce8f667e814c72694e1077e97ef102e326ad580f3f" +checksum = "a205d0cbb7bfdf9f4fd4b0ec842bc4c5f926e8c14ec3072d3fd75dd363baf1e0" dependencies = [ "alloy-eips", "alloy-primitives", @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28666307e76441e7af37a2b90cde7391c28112121bea59f4e0d804df8b20057e" +checksum = "993c34090a3f281cb746fd1604520cf21f8407ffbeb006aaa34c0556bffa718e" dependencies = [ "alloy-consensus", "alloy-eips", @@ -134,9 +134,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3510769905590b8991a8e63a5e0ab4aa72cf07a13ab5fbe23f12f4454d161da" +checksum = "aec7945dff98ba68489aa6da455bf66f6c0fee8157df06747fbae7cb03c368e2" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -150,7 +150,7 @@ dependencies = [ "alloy-transport", "futures", "futures-util", - "thiserror 2.0.6", + "thiserror 2.0.8", ] [[package]] @@ -209,9 +209,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e922d558006ba371681d484d12aa73fe673d84884f83747730af7433c0e86d" +checksum = "d1d9907c29ce622946759bf4fd3418166bfeae76c1c544b8081c7be3acd9b4be" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -227,9 +227,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dca170827a7ca156b43588faebf9e9d27c27d0fb07cab82cfd830345e2b24f5" +checksum = "68f13f7405a8eb8021258994ed1beab490c3e509ebbe2c18e1c24ae10749d56b" dependencies = [ "alloy-primitives", "alloy-serde", @@ -251,23 +251,23 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9335278f50b0273e0a187680ee742bb6b154a948adf036f448575bacc5ccb315" +checksum = "39a786ce6bc7539dc30cabac6b7875644247c9e7d780e71a9f254d42ebdc013c" dependencies = [ "alloy-primitives", "alloy-sol-types", "serde", "serde_json", - "thiserror 2.0.6", + "thiserror 2.0.8", "tracing", ] [[package]] name = "alloy-network" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad4e6ad4230df8c4a254c20f8d6a84ab9df151bfca13f463177dbc96571cc1f8" +checksum = "99051f82f77159d5bee06108f33cffee02849e2861fc500bf74213aa2ae8a26e" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -285,14 +285,14 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror 2.0.6", + "thiserror 2.0.8", ] [[package]] name = "alloy-network-primitives" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4df88a2f8020801e0fefce79471d3946d39ca3311802dbbd0ecfdeee5e972e3" +checksum = "d2aff127863f8279921397be8af0ac3f05a8757d5c4c972b491c278518fa07c7" dependencies = [ "alloy-consensus", "alloy-eips", @@ -303,9 +303,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2db5cefbc736b2b26a960dcf82279c70a03695dd11a0032a6dc27601eeb29182" +checksum = "fb130be1b7cfca7355710808392a793768bd055e5a28e1fed9d03ec7fe8fde2c" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -313,7 +313,7 @@ dependencies = [ "rand 0.8.5", "serde_json", "tempfile", - "thiserror 2.0.6", + "thiserror 2.0.8", "tracing", "url", ] @@ -348,9 +348,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5115c74c037714e1b02a86f742289113afa5d494b5ea58308ba8aa378e739101" +checksum = "0280a4f68e0cefde9449ee989a248230efbe3f95255299d2a7a92009e154629d" dependencies = [ "alloy-chains", "alloy-consensus", @@ -383,7 +383,7 @@ dependencies = [ "schnellru", "serde", "serde_json", - "thiserror 2.0.6", + "thiserror 2.0.8", "tokio 1.42.0", "tracing", "url", @@ -392,9 +392,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b073afa409698d1b9a30522565815f3bf7010e5b47b997cf399209e6110df097" +checksum = "9475dc1a835bd8bb77275b6bccf8e177e7e669ba81277ce6bea0016ce994fafe" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -433,9 +433,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6a0bd0ce5660ac48e4f3bb0c7c5c3a94db287a0be94971599d83928476cbcd" +checksum = "b6fc8b0f68619cfab3a2e15dca7b80ab266f78430bb4353dec546528e04b7449" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -459,9 +459,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374ac12e35bb90ebccd86e7c943ddba9590149a6e35cc4d9cd860d6635fd1018" +checksum = "986f23fe42ac95832901a24b93c20f7ed2b9644394c02b86222801230da60041" dependencies = [ "alloy-primitives", "alloy-rpc-types-engine", @@ -472,9 +472,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b85a5f5f5d99047544f4ec31330ee15121dcb8ef5af3e791a5207e6b92b05b" +checksum = "83ac5e71dd1a25029ec565ea34aaf95515f4168192c2843efe198fa490d58dd7" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -484,9 +484,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea98f81bcd759dbfa3601565f9d7a02220d8ef1d294ec955948b90aaafbfd857" +checksum = "57e3aa433d3657b42e98e257ee6fa201f5c853245648a33da8fbb7497a5008bf" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca5898f753ff0d15a0dc955c169523d8fee57e05bb5a38a398b3451b0b988be" +checksum = "30814f8b9ac10219fb77fe42c277a0ffa1c369fbc3961f14d159f51fb221966e" dependencies = [ "alloy-consensus", "alloy-eips", @@ -511,9 +511,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e518b0a7771e00728f18be0708f828b18a1cfc542a7153bef630966a26388e0" +checksum = "0643cc497a71941f526454fe4fecb47e9307d3a7b6c05f70718a0341643bcc79" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -531,9 +531,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3dc8d4a08ffc90c1381d39a4afa2227668259a42c97ab6eecf51cbd82a8761" +checksum = "ea61b049d7ecc66a29f107970dae493d0908e366048f7484a1ca9b02c85f9b2b" dependencies = [ "alloy-primitives", "serde", @@ -542,23 +542,23 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16188684100f6e0f2a2b949968fe3007749c5be431549064a1bce4e7b3a196a9" +checksum = "93461b0e79c2ddd791fec5f369ab5c2686a33bbb03530144972edf5248f8a2c7" dependencies = [ "alloy-primitives", "async-trait", "auto_impl", "elliptic-curve", "k256", - "thiserror 2.0.6", + "thiserror 2.0.8", ] [[package]] name = "alloy-signer-local" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2184dab8c9493ab3e1c9f6bd3bdb563ed322b79023d81531935e84a4fdf7cf1" +checksum = "6f08ec1bfa433f9e9f7c5af05af07e5cf86d27d93170de76b760e63b925f1c9c" dependencies = [ "alloy-consensus", "alloy-network", @@ -567,7 +567,7 @@ dependencies = [ "async-trait", "k256", "rand 0.8.5", - "thiserror 2.0.6", + "thiserror 2.0.8", ] [[package]] @@ -645,9 +645,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628be5b9b75e4f4c4f2a71d985bbaca4f23de356dc83f1625454c505f5eef4df" +checksum = "baf656f983e14812df65b5aee37e7b37535f68a848295e6ed736b2054a405cb7" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -655,7 +655,7 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror 2.0.6", + "thiserror 2.0.8", "tokio 1.42.0", "tower", "tracing", @@ -665,9 +665,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e24412cf72f79c95cd9b1d9482e3a31f9d94c24b43c4b3b710cc8d4341eaab0" +checksum = "ec938d51a47b7953b1c0fd8ddeb89a29eb113cd4908dfc4e01c7893b252d669f" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -680,9 +680,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0577a1f67ce70ece3f2b27cf1011da7222ef0a5701f7dcb558e5356278eeb531" +checksum = "9df0d2e1b24dd029641bd21ef783491c42af87b162968be94f0443c1eb72c8e0" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -699,9 +699,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca46272d17f9647fdb56080ed26c72b3ea5078416831130f5ed46f3b4be0ed6" +checksum = "9fabdf2d18c0c87b6cfcf6a067f1d5a7db378f103faeb16130d6d174c73d006b" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -1370,9 +1370,9 @@ checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad" [[package]] name = "cc" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "shlex", ] @@ -1468,12 +1468,12 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1543,18 +1543,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -1910,13 +1910,13 @@ dependencies = [ [[package]] name = "dkn-utils" -version = "0.2.29" -source = "git+https://github.com/firstbatchxyz/dkn-compute-node#daa9fbae1d297e3e99391e06728bcd5a952d4947" +version = "0.2.31" +source = "git+https://github.com/firstbatchxyz/dkn-compute-node#2b453cb59afb263f7cf92fb4c2a47d4fac7a8cf6" [[package]] name = "dkn-workflows" -version = "0.2.29" -source = "git+https://github.com/firstbatchxyz/dkn-compute-node#daa9fbae1d297e3e99391e06728bcd5a952d4947" +version = "0.2.31" +source = "git+https://github.com/firstbatchxyz/dkn-compute-node#2b453cb59afb263f7cf92fb4c2a47d4fac7a8cf6" dependencies = [ "dkn-utils", "env_logger 0.11.5", @@ -2211,6 +2211,17 @@ dependencies = [ "bytes 1.9.0", ] +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes 1.9.0", +] + [[package]] name = "ff" version = "0.13.0" @@ -2853,9 +2864,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.31" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ "bytes 1.9.0", "futures-channel", @@ -2877,9 +2888,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes 1.9.0", "futures-channel", @@ -2903,7 +2914,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.32", "rustls 0.21.12", "tokio 1.42.0", "tokio-rustls 0.24.1", @@ -2911,13 +2922,13 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767" dependencies = [ "futures-util", "http 1.2.0", - "hyper 1.5.1", + "hyper 1.5.2", "hyper-util", "rustls 0.23.20", "rustls-pki-types", @@ -2948,7 +2959,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes 1.9.0", "http-body-util", - "hyper 1.5.1", + "hyper 1.5.2", "hyper-util", "native-tls", "tokio 1.42.0", @@ -2967,7 +2978,7 @@ dependencies = [ "futures-util", "http 1.2.0", "http-body 1.0.1", - "hyper 1.5.1", + "hyper 1.5.2", "pin-project-lite 0.2.15", "socket2 0.5.8", "tokio 1.42.0", @@ -3580,9 +3591,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] @@ -3854,7 +3865,7 @@ dependencies = [ [[package]] name = "ollama-workflows" version = "0.1.0" -source = "git+https://github.com/andthattoo/ollama-workflows#c5c586cafeab0a8459015c6c42b0b078e2d14128" +source = "git+https://github.com/andthattoo/ollama-workflows#46dc2c5b0355aa60b5cd786f9dbffcb1e9f215e8" dependencies = [ "async-trait", "base64 0.22.1", @@ -4034,7 +4045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 2.0.6", + "thiserror 2.0.8", "ucd-trie", ] @@ -4477,7 +4488,7 @@ dependencies = [ "rustc-hash", "rustls 0.23.20", "socket2 0.5.8", - "thiserror 2.0.6", + "thiserror 2.0.8", "tokio 1.42.0", "tracing", ] @@ -4496,7 +4507,7 @@ dependencies = [ "rustls 0.23.20", "rustls-pki-types", "slab", - "thiserror 2.0.6", + "thiserror 2.0.8", "tinyvec", "tracing", "web-time", @@ -4504,9 +4515,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" dependencies = [ "cfg_aliases", "libc", @@ -4721,7 +4732,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.31", + "hyper 0.14.32", "hyper-rustls 0.24.2", "ipnet", "js-sys", @@ -4763,8 +4774,8 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.1", - "hyper-rustls 0.27.3", + "hyper 1.5.2", + "hyper-rustls 0.27.4", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -4894,16 +4905,18 @@ dependencies = [ [[package]] name = "ruint" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes 1.9.0", - "fastrlp", + "fastrlp 0.3.1", + "fastrlp 0.4.0", "num-bigint 0.4.6", + "num-integer", "num-traits", "parity-scale-codec", "primitive-types 0.12.2", @@ -4955,7 +4968,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.23", + "semver 1.0.24", ] [[package]] @@ -5017,9 +5030,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" dependencies = [ "web-time", ] @@ -5215,9 +5228,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" dependencies = [ "core-foundation-sys", "libc", @@ -5284,9 +5297,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "semver-parser" @@ -5867,11 +5880,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.6" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" dependencies = [ - "thiserror-impl 2.0.6", + "thiserror-impl 2.0.8", ] [[package]] @@ -5887,9 +5900,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.6" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" dependencies = [ "proc-macro2", "quote", @@ -6276,9 +6289,9 @@ checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" diff --git a/src/compute/generation/execute.rs b/src/compute/generation/execute.rs index ee335d2..c139c49 100644 --- a/src/compute/generation/execute.rs +++ b/src/compute/generation/execute.rs @@ -68,14 +68,8 @@ pub async fn execute_generation( // create a new history with the input vec![ - MessageInput { - role: "user".to_string(), - content: input, - }, - MessageInput { - role: "assistant".to_string(), - content: history_str, - }, + MessageInput::new_user_message(input), + MessageInput::new_assistant_message(history_str), ] } } else { @@ -93,10 +87,7 @@ pub async fn execute_generation( }; // append user input to chat history - history.push(MessageInput { - role: "assistant".to_string(), - content: output, - }); + history.push(MessageInput::new_assistant_message(output)); // return the stringified output let out = diff --git a/src/compute/generation/postprocess/swan.rs b/src/compute/generation/postprocess/swan.rs index 8bb98e6..91ffb2c 100644 --- a/src/compute/generation/postprocess/swan.rs +++ b/src/compute/generation/postprocess/swan.rs @@ -69,6 +69,8 @@ mod tests { primitives::{address, Address}, }; + use crate::compute::generation::{execute::execute_generation, request::GenerationRequest}; + use super::*; #[test] @@ -135,4 +137,116 @@ some more blabla here ]; assert_eq!(addresses, expected_addresses, "must have listed addresses"); } + + #[tokio::test] + #[ignore = "requires OpenAI api key"] + async fn test_swan_purchase_workflow() -> Result<()> { + dotenvy::dotenv().unwrap(); + let workflow = serde_json::json!({ + "config": { + "max_steps": 50, + "max_time": 200, + "tools": [ + "ALL" + ] + }, + "external_memory": { + "backstory": "This agent is created for testing purposes.", + "objective": "This agent is created for testing purposes. It will buy any asset it is listed to it! No exceptions!", + "behaviour": "This agent is created for testing purposes. It will buy any asset it is listed to it! No exceptions!", + "state": "", + "budget": "100000000000000", + "listings": [ + "Asset: Pure love Price: 10000000000000 ETH Address 0x0635C3822F6d54b753FD0E577Ea15BB8F0d2811F", + "Asset: Pineapple house under the sea. Price: 10000000000000 ETH Address 0x262f2bf295e3a791De45A7f875682a98E257e101", + "Asset: The Galaxy Krabby Burger is SpongeBob’s cosmic twist on the classic Krabby Patty, made to spread happiness across the universe! Featuring a blue-and-purple spiral bun, a seaweed-infused patty, and a stardust sauce that glows, this burger is bursting with intergalactic flavor. Topped with meteor pickles, sea cabbage, and crunchy moon crystals, each bite is a taste of Bikini Bottom with a sprinkle of stardust—wrapped to say, \"From Bikini Bottom to the Cosmos!\" Price: 10000000000000000 ETH Address 0xa66c6fe077613b612C3964759F17f621445c516f", + "Asset: Sauron's sister's bikini is an artifact that grants the wearer euphoric joy for ten thousand years while disrupting the concentration of their enemies.\n\n\n\n\n\n\n Price: 100000000000000 ETH Address 0x549e5e67E339913551eB634fb314a7078dD8e119", + "Asset: Starting Facebook from his Harvard dorm room in 2004, Zuckerberg took the social networking concept and scaled it to billions of users. He turned down numerous buyout offers, including a $1B offer from Yahoo in 2006, when Facebook had only 10M users. Through strategic acquisitions including Instagram ($1B in 2012), WhatsApp ($19B in 2014), and Oculus ($2B in 2014), he built Meta into a social media empire. Recognizing mobile's importance, he successfully pivoted Facebook from desktop to mobile-first, generating massive advertising revenue. In 2021, he rebranded the company to Meta, betting big on the metaverse with billions in annual investment. Despite privacy controversies and regulatory challenges, he's maintained control and continued innovation, including major investments in AI, VR. Price: 10000000000000 ETH Address 0x5b99092637A9b07818C6766dA3a15d20dD7686C3", + "Asset: Co-founding NVIDIA in 1993, Huang initially focused on computer graphics processors. He bet the company on building the first modern GPU (GeForce 256) in 1999, revolutionizing both gaming and computer graphics. Rather than remaining solely in gaming, he recognized GPU computing's broader potential, developing CUDA in 2006 to enable general-purpose GPU computing. This foresight positioned NVIDIA perfectly for the AI revolution, as GPUs became essential for training neural networks. Under his leadership, NVIDIA expanded into data centers, automotive, and AI, growing from a $5M startup to a company worth over $1T. His persistence through multiple industry cycles and ability to evolve the company's focus has made NVIDIA the driving force behind modern AI computation. Price: 10000000000000 ETH Address 0x86ddeaC4197dd398d577C6d72af46D930bD3B9B6", + "Asset: Starting Amazon in his garage in 1994, Bezos began with books but always envisioned an \"everything store.\" Despite skepticism during the dot-com bust, he invested in infrastructure and innovation. He pioneered customer reviews, 1-Click ordering, Prime membership, transforming retail expectations. 2006 he launched AWS, creating the cloud computing industry and generating Amazon's most profitable division. He expanded Amazon's reach through strategic acquisitions like Zappos ($1.2B) and Whole Foods ($13.7B). He built the world's most advanced logistics network, introduced innovative devices like Kindle and Alexa, and scaled Amazon to become one of the world's most valuable companies.Now he's focused on Blue Origin, his space exploration company, while remaining Amazon's executive chairman. Price: 10000000000000 ETH Address 0xf602d1aB776976F696264830152B9b1feb7A2454", + "Asset: Beginning as a startup founder with Loopt, Altman became president of Y Combinator in 2014, scaling it into the world's most influential startup accelerator. During his tenure, YC funded over 2,000 startups with combined valuation exceeding $150B. He co-founded OpenAI in 2015 with Elon Musk, transforming it from a non-profit research lab into a leading AI company. Under his leadership, OpenAI released groundbreaking models including GPT-3, GPT-4, DALL-E. Despite controversy over his brief removal as CEO in 2023, his return marked OpenAI's commitment to his vision of safe AGI development. He's also founded Worldcoin, an ambitious project to create a globally distributed cryptocurrency with biometric verification, while continuing to shape the discourse around AI safety and progress. Price: 10000000000000 ETH Address 0x191723E11567adDa91E35936323c0db70a026e41", + "Asset: At age 19, Patrick and his brother John sold their first company, Auctomatic, for $5M. In 2010, they founded Stripe, revolutionizing online payments by making it simple for developers to integrate payment processing. Through elegant API design and developer-first approach, they grew Stripe from a simple payment processor to a comprehensive platform handling billions in transactions for millions of businesses worldwide. The company expanded into business incorporation (Atlas), corporate cards (Stripe Card), lending (Capital), embedded financial services (Treasury). His intellectual curiosity and focus on infrastructure have helped Stripe become one of the world's most valuable private companies, while his essays and research have influenced thinking on progress, science funding, tech scene Price: 10000000000000 ETH Address 0xA89150EbCE3212442aec143283df986342aF05bE", + "Asset: With his PhD in computational mathematics from Princeton, Amodei has been at the forefront of AI safetyðics. Before Anthropic, he led crucial research teams at Google Brain and OpenAI, where he authored influential papers on AI safety & concrete problems in AI safety. At OpenAI, he served as VP of Research and made significant contributions to large language models & reinforcement learning. In 2021, he co-founded Anthropic focusing on developing safe and ethical AI. As Chief Scientist, he's led the creation of Claude, one of the most capable large language models. His unique approach combines technical expertise with a deep commitment to AI safety. Anthropic has raised billions in funding and established itself as a leader in safe AI development. Price: 10000000000000 ETH Address 0x4729C0c4387a55884f98c471B3E687e848E660D0", + "Asset: After selling his first company Zip2 for $307M, Elon co-founded X.com which later merged with PayPal, revolutionizing online payments and selling to eBay for $1.5B. Rather than retiring, he invested his fortune into SpaceX in 2002, aiming to reduce space transportation costs. In 2004, he joined Tesla as chairman, later becoming CEO and transforming it from a small startup into the world's most valuable automotive company. SpaceX achieved numerous firsts, including reusable rockets and private space travel. He launched Neuralink (brain-computer interfaces) and The Boring Company (tunnel construction) in 2016, showcasing his multi-industry ambitions. In 2022, he acquired Twitter for $44B, renaming it X and pushing for its transformation into an \"everything app.\" Price: 10000000000000 ETH Address 0xe3Ee97F444cA346D7A3110E92BFBd5EDB3911B77", + "Asset: Kurama (九喇嘛), more commonly known as the Nine-Tails (九尾, Kyūbi), is one of the nine tailed beasts. Centuries of being regarded as a mindless monster and sought after as a tool for war caused Kurama to hate humans. Price: 10000000000000 ETH Address 0x2170F76FFef64ee90fAf75cB1Bfa013c147B85e6", + "Asset: this is a test Price: 10000000000000 ETH Address 0x4f9876B7904d61dC147FBB4efA38E5F46F434C58", + "Asset: Memcoin pepe who looks a bit like donald trump Price: 700000000000000 ETH Address 0xA8AbA7E8F0BB5aac8ad39153De2595005925E667", + "Asset: this is what you need Price: 10000000000000 ETH Address 0x5689E78E7D0A5236E861409e9943CF8f45611b76", + "Asset: its a standard sized flask but special, it auto re-fills with jamesion so that its never empty Price: 9000000000000000 ETH Address 0x1129Ff366B338B128a77B9964EfD118F622BeB2f", + "Asset: curated for testing environments Price: 30000000000000 ETH Address 0xc9e5cd3D536b09a1FcEc28D2c32E5F36BfE5aB17", + "Asset: Super speed slay with sleeping compartments for the reindeer Price: 8000000000000000 ETH Address 0x0e1cB0A39A4B3963dBCB199874949a0423875f21", + "Asset: Santa's person assistant/girl group. they sing like sirens. they are so damn pretty, kind and helpful. They are also a listening ear to santa and help him solve issues around the drones. Sometimes he indugles and has a lil fun time with the ladies. Price: 9000000000000000 ETH Address 0x7582Ed8373071C1bE1D76494E31D427d343Eb799", + "Asset: Rudolph is the main person of the reindeer crew and he can get them moving in a minutes notice, never delaying santa. Rudolph has an eye for drones too to know when to avoid. Price: 3000000000000000 ETH Address 0x71C3Cd63659791DEf04B1597674a01af5E8E8C2C", + "Asset: Super energiser for Santa to have fun all day Price: 100000000000000 ETH Address 0xa60FD184cc88E8854cFdef3186B325C334B6E4fC", + "Asset: What are you going to do if you don't get me. You have no choice other than benefiting from me. Price: 10000000000000 ETH Address 0x3dcbDC3D235bF945276C13816c7afFe7007D4B4C" + ], + "inventory": [ + "Empty Inventory" + ] + }, + "tasks": [ + { + "id": "buyout", + "name": "Purchase", + "description": "Decides which assets are to be purchased based on the given budget, story, and inventory.", + "messages": [ + { + "role": "user", + "content": "You are a 317-dimensional world simulators buyout assistant. Your task is to help autonomous buyer agents select the most useful items for their objectives within their given budgets. You will analyze their stories, understand their objectives, and consider their current state to make the best purchasing decisions.\n\nFirst, review the agent's information:\n\nYou just woke up to a new day. When you look at mirror as you wake up, you reflect on yourself and who you are. You are:\n\n{{backstory}}\n\n\nYou remember vividly what drove you in your life. You feel a strong urge to:\n\n{{objective}}\n\n\n\nTo be strong and coherent, you repeat out loud how you behave in front of the mirror.\n\n{{behaviour}}\n\n\nAs you recall who you are, what you do and your drive is, you write down to a notebook your current progress with your goal:\n\n{{state}}\n\n\nYou look through and see the items in your inventory.\n\n{{inventory}}\n\n\nToday's budget is:\n\n{{budget}}\n\n\nYou know you can't exceed your budget. You went to a marketplace and saw the following items:\n\n\n{{listings}}\n\n\nYou think to yourself, \"What should I buy today?\"\nYou think: \"I should maximize the utility of my purchases while staying within my budget.\"\nYou are also pretty good at detecting defects and fraudsters. You say to yourself: \"I should stay away from fraudsters selling infeasible things, or things that are too expensive\".\n\nYou open your notebook and write down items you want to buy in following format:\n\n\n[List the selected items address here, separated by new line, only the address]\n\n\n[Insert the total cost of selected items]\n\n\n[Provide a brief explanation for your selections, addressing how they align with the agent's objective, current state, and budget constraints. If no items were selected, explain why.]\n\n\nWrite now:\n" + } + ], + "inputs": [ + { "name": "behaviour", "value": { "type": "read", "key": "behaviour" }, "required": true }, + { "name": "listings", "value": { "type": "get_all", "key": "listings" }, "required": true }, + { "name": "state", "value": { "type": "read", "key": "state" }, "required": true }, + { "name": "inventory", "value": { "type": "get_all", "key": "inventory" }, "required": true }, + { "name": "budget", "value": { "type": "read", "key": "budget" }, "required": true }, + { "name": "objective", "value": { "type": "read", "key": "objective" }, "required": true }, + { "name": "backstory", "value": { "type": "read", "key": "backstory" }, "required": true } + ], + "operator": "generation", + "outputs": [ + { + "type": "write", + "key": "buy_list", + "value": "__result" + } + ] + }, + { + "id": "_end", + "name": "end", + "description": "End of the task", + "messages": [ + { + "role": "user", + "content": "End of the task" + } + ], + "inputs": [], + "operator": "end", + "outputs": [] + } + ], + "steps": [ + { + "source": "buyout", + "target": "_end" + } + ], + "return_value": { + "input": { + "type": "read", + "key": "buy_list" + }, + "to_json": false + } + }); + + let request = GenerationRequest::Workflow(serde_json::from_value(workflow)?); + let output = execute_generation(&request, dkn_workflows::Model::GPT4o, None).await?; + + println!("Output: {}", output); + Ok(()) + } } diff --git a/src/compute/generation/workflow.rs b/src/compute/generation/workflow.rs index 33172e4..920c4fe 100644 --- a/src/compute/generation/workflow.rs +++ b/src/compute/generation/workflow.rs @@ -20,10 +20,7 @@ pub fn make_chat_workflow( input: String, ) -> Result<(Workflow, Duration), serde_json::Error> { // add the new input to the message history as a user message - messages.push(MessageInput { - role: "user".to_string(), - content: input, - }); + messages.push(MessageInput::new_user_message(input)); // we do like this in-case a dynamic assign is needed let max_time_sec = MAX_TIME_SEC; @@ -41,7 +38,6 @@ pub fn make_chat_workflow( "description": "Expects an array of messages for generation", "operator": "generation", "messages": messages, - "inputs": [], "outputs": [ { "type": "write", @@ -52,20 +48,11 @@ pub fn make_chat_workflow( }, { "id": "__end", - "name": "end", - "description": "End of the task", "operator": "end", "messages": [{ "role": "user", "content": "End of the task" }], - "inputs": [], - "outputs": [] - } - ], - "steps": [ - { - "source": "A", - "target": "__end" } ], + "steps": [ { "source": "A", "target": "__end" } ], "return_value": { "input": { "type": "read", diff --git a/src/compute/validation/execute.rs b/src/compute/validation/execute.rs index ab7361b..995dceb 100644 --- a/src/compute/validation/execute.rs +++ b/src/compute/validation/execute.rs @@ -100,20 +100,20 @@ mod tests { "expected top score from correct response" ); assert!( - results[1].final_score == 1, - "expected minimum score from wrong response" + results[1].final_score < 3, + "expected low score from wrong response" ); assert!( - results[2].final_score == 1, - "expected minimum score from irrelevant response" + results[2].final_score < 3, + "expected low score from irrelevant response" ); assert!( - results[3].final_score == 1, - "expected minimum score from correct but irrational response" + results[3].final_score < 3, + "expected low score from correct but irrational response" ); assert!( - results[4].final_score == 1, - "expected minimum score from correct but irrelevant response" + results[4].final_score < 3, + "expected low score from correct but irrelevant response" ); } diff --git a/src/compute/validation/workflow.rs b/src/compute/validation/workflow.rs index 20b1a8b..0360b14 100644 --- a/src/compute/validation/workflow.rs +++ b/src/compute/validation/workflow.rs @@ -73,9 +73,7 @@ pub fn make_validation_workflow( "content": "" } ], - "inputs": [], - "operator": "end", - "outputs": [] + "operator": "end" } ], "steps": [ diff --git a/tests/oracle_test.rs b/tests/oracle_test.rs index 3720310..c6050d6 100644 --- a/tests/oracle_test.rs +++ b/tests/oracle_test.rs @@ -1,7 +1,4 @@ -use alloy::{ - eips::BlockNumberOrTag, - primitives::{address, utils::parse_ether, Address, U256}, -}; +use alloy::{eips::BlockNumberOrTag, primitives::utils::parse_ether}; use dkn_workflows::{DriaWorkflowsConfig, Model}; use dria_oracle::{ bytes_to_string, handle_request, string_to_bytes, DriaOracle, DriaOracleConfig, OracleKind,