Skip to content

Commit e5f3fa6

Browse files
authored
Merge pull request #36 from firstbatchxyz/erhant/bugfixes-timeouts-postprocess
fix timeout issue + handle swan post-process error
2 parents ad2bea9 + c050e7f commit e5f3fa6

File tree

17 files changed

+396
-174
lines changed

17 files changed

+396
-174
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ RUST_LOG=none,dria_oracle=info
99
# example: ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
1010
SECRET_KEY=your-secret-key
1111

12+
# Coordinator address (optional)
13+
COORDINATOR_ADDRESS=
14+
1215
## Arweave configurations
1316
# path to wallet, only required if your BYTE_LIMIT is enough that
1417
# you may do an Arweave upload to store a large value on-chain

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "dria-oracle"
33
description = "Dria Knowledge Network Oracle Node"
4-
version = "0.2.0"
4+
version = "0.2.1"
55
edition = "2021"
66
license = "Apache-2.0"
77
readme = "README.md"
@@ -19,7 +19,6 @@ tokio = { version = "1.39.2", features = [
1919
"signal",
2020
] }
2121
tokio-util = "0.7.13"
22-
lazy_static = "1.5.0"
2322

2423
# workflows
2524
dkn-workflows = { git = "https://github.com/firstbatchxyz/dkn-compute-node" }

README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,31 @@ cargo install --git https://github.com/firstbatchxyz/dria-oracle-node
2323

2424
Create an `.env` file by copying `.env.example`. You have to fill the following variables:
2525

26-
- Get an RPC URL from a provider such as Alchemy or Infura, and set it as `RPC_URL`.
27-
- Provide an Ethereum wallet secret koy to `SECRET_KEY`, make sure it has funds to pay for gas and tokens.
26+
- Get an RPC URL from a provider such as [Alchemy](https://www.alchemy.com/) or [Infura](https://www.infura.io/), and set it as `RPC_URL`.
27+
- Provide an Ethereum wallet secret key to `SECRET_KEY`, make sure it has funds to pay for gas and tokens.
2828

29-
Optionally, you can save gas costs using Arweave:
29+
> [!NOTE]
30+
>
31+
> The contract addresses are determined with respect to the chain connected via RPC URL, but you can override it via `COORDINATOR_ADDRESS` environment variable.
32+
> In any case, you should not need to do this.
33+
34+
### Arweave
35+
36+
You can save gas costs using [Arweave](https://arweave.org/):
3037

31-
- 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
38+
- Provide an Arweave wallet via `ARWEAVE_WALLET_PATH` variable so that you can use Arweave for large results. You can create one [here](https://arweave.app/).
39+
- You can set `ARWEAVE_BYTE_LIMIT` to determine the byte length threshold, beyond which values are uploaded to Arweave. It defaults to 1024, so any data less than that many bytes will be written as-is.
40+
41+
If you omit Arweave, it will only use the client for downloading things from Arweave, but will never upload.
42+
43+
### LLM Providers
3244

3345
As for the LLM providers:
3446

3547
- If you are using Ollama, make sure it is running and the host & port are correct.
36-
- If you are using OpenAI, make sure you provide the `OPENAI_API_KEY`.
37-
- If you are using Gemini, make sure you provide the `GEMINI_API_KEY`.
38-
- If you are using OpenRouter, make sure you provide the `OPENROUTER_API_KEY`.
48+
- If you are using OpenAI, provide the `OPENAI_API_KEY`.
49+
- If you are using Gemini, provide the `GEMINI_API_KEY`.
50+
- If you are using OpenRouter, provide the `OPENROUTER_API_KEY`.
3951

4052
## Usage
4153

@@ -52,6 +64,11 @@ The CLI provides several methods to interact with the oracle contracts.
5264
- [Viewing Tasks](#viewing-tasks)
5365
- [Balance & Rewards](#balance--rewards)
5466

67+
> [!TIP]
68+
>
69+
> By default logs will be `info` level, but you can add a `DEBUG=1` env variable and it will use `debug` level instead.
70+
> You can set `RUST_LOG` variable yourself as well.
71+
5572
### Registration
5673

5774
To serve oracle requests, you **MUST** first register as your desired oracle type, i.e. `generator` or `validator`. These are handled by the registration commands `register` and `unregister` which accepts multiple arguments to register at once. You can then see your registrations with `registrations` command.

misc/arweave.js

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,46 @@
11
/**
2-
* A helper script to print the content of an Arweave transaction, where transaction id is hex-encoded.
3-
* This means that the input is a 64-char hexadecimal.
2+
* A helper script to print the content of an Arweave transaction.
43
*
54
* Usage:
65
*
7-
* bun run ./misc/arweave.js 0x30613233613135613236663864663332366165306137663863633636343437336238373463353966333964623436366665316337313531393634623734393231
6+
* ```sh
7+
* # calldata as-is
8+
* bun run ./misc/arweave.js 0x7b2261727765617665223a224d49555775656361634b417a62755442335a6a57613463784e6461774d71435a704550694f71675a625a63227d
89
*
9-
* Tip:
10+
* # as an object (with escaped quotes)
11+
* bun run ./misc/arweave.js "{\"arweave\":\"MIUWuecacKAzbuTB3ZjWa4cxNdawMqCZpEPiOqgZbZc\"}"
1012
*
11-
* Can be piped to `pbcopy` on macOS to copy the output to clipboard.
13+
* # base64 txid
14+
* bun run ./misc/arweave.js MIUWuecacKAzbuTB3ZjWa4cxNdawMqCZpEPiOqgZbZc
15+
* ```
16+
*
17+
* Can be piped to `pbcopy` on macOS to copy the output to clipboard.
1218
*/
1319

1420
// parse input
1521
let input = process.argv[2];
1622
if (!input) {
1723
console.error("No input provided.");
24+
return;
1825
}
1926

20-
// get rid of 0x
27+
let arweaveTxId;
2128
if (input.startsWith("0x")) {
22-
input = input.slice(2);
29+
// if it starts with 0x, we assume its all hex
30+
arweaveTxId = JSON.parse(
31+
Buffer.from(input.slice(2), "hex").toString()
32+
).arweave;
33+
} else if (input.startsWith("{")) {
34+
// if it starts with {, we assume its a JSON string
35+
console.log("input", input);
36+
arweaveTxId = JSON.parse(input).arweave;
37+
} else {
38+
// otherwise, we assume its a base64 txid
39+
arweaveTxId = input;
2340
}
24-
const inputDecoded = Buffer.from(input, "hex").toString();
25-
const obj = JSON.parse(inputDecoded);
2641

42+
// construct the URL
2743
// download the actual response from Arweave
28-
const url = `https://arweave.net/${obj.arweave}`;
29-
console.log(url);
44+
const url = `https://arweave.net/${arweaveTxId}`;
3045
const res = await fetch(url);
31-
3246
console.log(await res.text());

src/cli/commands/coordinator.rs

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use crate::{
99
use alloy::{
1010
eips::BlockNumberOrTag,
1111
primitives::{utils::format_ether, U256},
12-
rpc::types::Log,
1312
};
1413
use dkn_workflows::{DriaWorkflowsConfig, Model, ModelProvider};
1514
use eyre::{eyre, Context, Result};
@@ -45,6 +44,7 @@ impl DriaOracle {
4544
}
4645
}
4746
}
47+
4848
log::info!(
4949
"Running as: {}",
5050
kinds
@@ -122,8 +122,12 @@ impl DriaOracle {
122122
next = event_stream.next() => {
123123
match next {
124124
Some(Ok((event, log))) => {
125-
self.handle_event_log(event, log, &kinds, &model_config)
126-
.await
125+
log::debug!(
126+
"Handling task {} (tx: {})",
127+
event.taskId,
128+
log.transaction_hash.unwrap_or_default()
129+
);
130+
self.handle_event_log(event, &kinds, &model_config).await
127131
}
128132
Some(Err(e)) => log::error!("Could not handle event: {}", e),
129133
None => {
@@ -141,19 +145,16 @@ impl DriaOracle {
141145
async fn handle_event_log(
142146
&self,
143147
event: StatusUpdate,
144-
log: Log,
145148
kinds: &[OracleKind],
146-
model_config: &DriaWorkflowsConfig,
149+
workflows: &DriaWorkflowsConfig,
147150
) {
148151
let task_id = event.taskId;
149-
log::debug!(
150-
"Handling task {} (tx: {})",
151-
task_id,
152-
log.transaction_hash.unwrap_or_default()
153-
);
152+
let Ok(status) = TaskStatus::try_from(event.statusAfter) else {
153+
log::error!("Could not parse task status: {}", event.statusAfter);
154+
return;
155+
};
154156

155-
// handle request
156-
match handle_request(self, kinds, model_config, event).await {
157+
match handle_request(self, kinds, workflows, status, event.taskId, event.protocol).await {
157158
Ok(Some(receipt)) => {
158159
log::info!(
159160
"Task {} processed successfully. (tx: {})",
@@ -171,7 +172,7 @@ impl DriaOracle {
171172
async fn handle_previous_tasks(
172173
&self,
173174
from_block: BlockNumberOrTag,
174-
model_config: &DriaWorkflowsConfig,
175+
workflows: &DriaWorkflowsConfig,
175176
kinds: &[OracleKind],
176177
) -> Result<()> {
177178
log::info!(
@@ -183,19 +184,30 @@ impl DriaOracle {
183184
.await?;
184185

185186
for (event, log) in prev_tasks {
187+
let status_before = TaskStatus::try_from(event.statusBefore)?;
188+
let status_after = TaskStatus::try_from(event.statusAfter)?;
186189
let task_id = event.taskId;
187190
log::info!(
188191
"Previous task: {} ({} -> {})",
189192
task_id,
190-
TaskStatus::try_from(event.statusBefore).unwrap_or_default(),
191-
TaskStatus::try_from(event.statusAfter).unwrap_or_default()
193+
status_before,
194+
status_after
192195
);
193196
log::debug!(
194197
"Handling task {} (tx: {})",
195198
task_id,
196199
log.transaction_hash.unwrap_or_default()
197200
);
198-
match handle_request(self, kinds, model_config, event).await {
201+
match handle_request(
202+
self,
203+
kinds,
204+
workflows,
205+
status_after,
206+
event.taskId,
207+
event.protocol,
208+
)
209+
.await
210+
{
199211
Ok(Some(receipt)) => {
200212
log::info!(
201213
"Task {} processed successfully. (tx: {})",
@@ -212,6 +224,7 @@ impl DriaOracle {
212224

213225
Ok(())
214226
}
227+
215228
pub(in crate::cli) async fn view_task_events(
216229
&self,
217230
from_block: impl Into<BlockNumberOrTag> + Clone,
@@ -233,12 +246,13 @@ impl DriaOracle {
233246

234247
let task_events = self.get_tasks_in_range(from_block, to_block).await?;
235248

236-
for (event, _) in task_events {
249+
for (event, log) in task_events {
237250
log::info!(
238-
"Task: {} ({} -> {})",
251+
"Task {} changed from {} to {} at block {}",
239252
event.taskId,
240253
TaskStatus::try_from(event.statusBefore).unwrap_or_default(),
241-
TaskStatus::try_from(event.statusAfter).unwrap_or_default()
254+
TaskStatus::try_from(event.statusAfter).unwrap_or_default(),
255+
log.block_number.unwrap_or_default()
242256
);
243257
}
244258

@@ -290,6 +304,42 @@ impl DriaOracle {
290304
Ok(())
291305
}
292306

307+
pub(in crate::cli) async fn process_task(
308+
&self,
309+
workflows: &DriaWorkflowsConfig,
310+
kinds: &[OracleKind],
311+
task_id: U256,
312+
) -> Result<()> {
313+
log::info!("Processing task {}.", task_id);
314+
let request = self.get_task_request(task_id).await?;
315+
316+
log::info!(
317+
"Request Information:\nRequester: {}\nStatus: {}\nInput: {}\nModels: {}",
318+
request.requester,
319+
TaskStatus::try_from(request.status)?,
320+
bytes_to_string(&request.input)?,
321+
bytes_to_string(&request.models)?
322+
);
323+
324+
// TODO: !!!
325+
let status = TaskStatus::try_from(request.status)?;
326+
match handle_request(self, kinds, workflows, status, task_id, request.protocol).await {
327+
Ok(Some(receipt)) => {
328+
log::info!(
329+
"Task {} processed successfully. (tx: {})",
330+
task_id,
331+
receipt.transaction_hash
332+
)
333+
}
334+
Ok(None) => {
335+
log::info!("Task {} ignored.", task_id)
336+
}
337+
Err(e) => log::error!("Could not process task: {:?}", e),
338+
}
339+
340+
Ok(())
341+
}
342+
293343
pub async fn request_task(
294344
&self,
295345
input: &str,

src/cli/commands/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,19 @@ pub enum Commands {
4343
models: Vec<Model>,
4444
},
4545
/// View status of a given task.
46-
View { task_id: U256 },
46+
View {
47+
#[arg(help = "Task id.", required = true)]
48+
task_id: U256,
49+
},
50+
/// Process a single task.
51+
Process {
52+
#[arg(help = "Task id.", required = true)]
53+
task_id: U256,
54+
#[arg(help = "The oracle kinds to handle the task as.", required = false)]
55+
kinds: Vec<OracleKind>,
56+
#[arg(short, long = "model", help = "The models to use for this task.", required = true, value_parser = parse_model)]
57+
models: Vec<Model>,
58+
},
4759
/// View tasks between specific blocks.
4860
Tasks {
4961
#[arg(long, help = "Starting block number, defaults to 'earliest'.", value_parser = parse_block_number_or_tag)]

src/cli/mod.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
mod commands;
2+
use std::time::Duration;
3+
24
use commands::Commands;
35

46
mod parsers;
7+
use dkn_workflows::DriaWorkflowsConfig;
58
use parsers::*;
69

710
use crate::{DriaOracle, DriaOracleConfig};
@@ -25,6 +28,9 @@ struct Cli {
2528
/// Ethereum wallet's secret (private) key.
2629
#[arg(short, long, env = "SECRET_KEY", value_parser = parse_secret_key)]
2730
secret_key: B256,
31+
32+
#[arg(short, long, env = "TX_TIMEOUT_SECS", default_value = "30")]
33+
tx_timeout: Option<u64>,
2834
}
2935

3036
/// Main CLI entry point.
@@ -39,7 +45,8 @@ pub async fn cli() -> Result<()> {
3945

4046
// create node
4147
let config = DriaOracleConfig::new(&secret_key, rpc_url)
42-
.wrap_err("could not create oracle configuration")?;
48+
.wrap_err("could not create oracle configuration")?
49+
.with_tx_timeout(Duration::from_secs(30)); // timeout is 30secs by default
4350
let node = DriaOracle::new(config)
4451
.await
4552
.wrap_err("could not create oracle node")?;
@@ -89,6 +96,14 @@ pub async fn cli() -> Result<()> {
8996
}
9097
}
9198
Commands::View { task_id } => node.view_task(task_id).await?,
99+
Commands::Process {
100+
task_id,
101+
kinds,
102+
models,
103+
} => {
104+
node.process_task(&DriaWorkflowsConfig::new(models), &kinds, task_id)
105+
.await?
106+
}
92107
Commands::Tasks { from, to } => {
93108
node.view_task_events(
94109
from.unwrap_or(BlockNumberOrTag::Earliest),

src/compute/generation/execute.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ mod tests {
156156
// cargo test --package dria-oracle --lib --all-features -- compute::generation::execute::tests::test_raw_workflow --exact --show-output --ignored
157157
dotenvy::dotenv().unwrap();
158158

159-
let contract_result = hex_literal::hex!("7b2261727765617665223a2239397a4252676c4c663443696b35676c57444f667542463736456e417a4a6344303431545a614c6d6f6934227d");
159+
let contract_result = hex_literal::hex!("7b2261727765617665223a224d49555775656361634b417a62755442335a6a57613463784e6461774d71435a704550694f71675a625a63227d");
160160
let request = GenerationRequest::try_parse_bytes(&contract_result.into())
161161
.await
162162
.unwrap();

0 commit comments

Comments
 (0)