Skip to content

Commit 6ea367a

Browse files
committed
add correctness check for header related content
1 parent 776d235 commit 6ea367a

File tree

5 files changed

+249
-47
lines changed

5 files changed

+249
-47
lines changed

Cargo.lock

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

glados-audit/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ ethportal-api = { git = "https://github.com/ethereum/trin" }
1919
glados-core = { path = "../glados-core" }
2020
migration = { path = "../migration" }
2121
rand = "0.8.5"
22+
reqwest = "0.11.16"
2223
sea-orm = "0.10.3"
2324
serde_json = "1.0.95"
25+
thiserror = "1.0.40"
2426
tokio = "1.21.2"
2527
tracing = "0.1.37"
2628
trin-utils = {git = "https://github.com/ethereum/trin" }
2729
url = "2.3.1"
2830
web3 = "0.18.0"
29-

glados-audit/src/cli.rs

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,46 @@ use url::Url;
55

66
const DEFAULT_DB_URL: &str = "sqlite::memory:";
77

8-
#[derive(Parser, Debug, Eq, PartialEq)]
8+
#[derive(Parser, Default, Debug, Eq, PartialEq)]
99
#[command(author, version, about, long_about = None)]
1010
pub struct Args {
11+
/// Database connection URL, such as SQLite or PostgreSQL.
1112
#[arg(short, long, default_value = DEFAULT_DB_URL)]
1213
pub database_url: String,
14+
15+
/// IPC Path for connection to Portal node.
1316
#[arg(short, long, requires = "transport")]
1417
pub ipc_path: Option<PathBuf>,
18+
19+
/// HTTP URL for connection to Portal node.
1520
#[arg(short = 'u', long, requires = "transport")]
1621
pub http_url: Option<Url>,
22+
23+
/// Portal node connection mode.
1724
#[arg(short, long)]
1825
pub transport: TransportType,
26+
1927
#[arg(short, long, default_value = "4", help = "number of auditing threads")]
2028
pub concurrency: u8,
21-
#[arg(short, long, action(ArgAction::Append), value_enum, default_value = None, help = "Specific strategy to use. Default is to use all available strategies. May be passed multiple times for multiple strategies (--strategy latest --strategy random). Duplicates are permitted (--strategy random --strategy random).")]
29+
30+
/// Specific strategy to use. Default is to use all available strategies.
31+
/// May be passed multiple times for multiple strategies
32+
/// (--strategy latest --strategy random).
33+
/// Duplicates are permitted (--strategy random --strategy random).
34+
#[arg(short, long, action(ArgAction::Append), value_enum, default_value = None)]
2235
pub strategy: Option<Vec<SelectionStrategy>>,
36+
37+
/// Non-portal Ethereum execution node for validating data against.
38+
#[arg(long, default_value = "http")]
39+
pub trusted_provider: TrustedProvider,
40+
41+
/// HTTP URL for connection to non-portal Ethereum execution node.
42+
#[arg(long, requires = "trusted_provider")]
43+
pub provider_http_url: Option<Url>,
44+
45+
/// Pandaops URL for connection to non-portal Ethereum execution node.
46+
#[arg(long, requires = "trusted_provider")]
47+
pub provider_pandaops: Option<String>,
2348
}
2449

2550
#[cfg(test)]
@@ -37,7 +62,7 @@ mod test {
3762
concurrency: 4,
3863
http_url: None,
3964
transport: TransportType::IPC,
40-
strategy: None,
65+
..Default::default()
4166
};
4267
assert_eq!(result, expected);
4368
}
@@ -59,7 +84,7 @@ mod test {
5984
concurrency: 3,
6085
http_url: None,
6186
transport: TransportType::IPC,
62-
strategy: None,
87+
..Default::default()
6388
};
6489
assert_eq!(result, expected);
6590
}
@@ -84,6 +109,7 @@ mod test {
84109
ipc_path: Some(PathBuf::from(IPC_PATH)),
85110
concurrency: 4,
86111
strategy: Some(vec![SelectionStrategy::Latest]),
112+
..Default::default()
87113
};
88114
assert_eq!(result, expected);
89115
}
@@ -117,16 +143,30 @@ mod test {
117143
SelectionStrategy::Latest,
118144
SelectionStrategy::Random,
119145
]),
146+
..Default::default()
120147
};
121148
assert_eq!(result, expected);
122149
}
123150
}
124151

125152
/// Used by a user to specify the intended form of transport
126153
/// to connect to a Portal node.
127-
#[derive(Debug, Clone, Eq, PartialEq, ValueEnum)]
154+
#[derive(Debug, Default, Clone, Eq, PartialEq, ValueEnum)]
128155
#[clap(rename_all = "snake_case")]
129156
pub enum TransportType {
157+
#[default]
158+
HTTP,
130159
IPC,
160+
}
161+
162+
/// Used by a user to specify the intended form of transport
163+
/// to connect to a Portal node.
164+
#[derive(Debug, Default, Clone, Eq, PartialEq, ValueEnum)]
165+
#[clap(rename_all = "snake_case")]
166+
pub enum TrustedProvider {
167+
#[default]
168+
/// An HTTP-based provider.
131169
HTTP,
170+
/// A Trin operations provider.
171+
Pandaops,
132172
}

glados-audit/src/lib.rs

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
11
use std::{
2+
env,
23
sync::{
34
atomic::{AtomicU8, Ordering},
45
Arc,
56
},
67
thread::available_parallelism,
78
};
89

9-
use anyhow::{bail, Result};
10+
use anyhow::{anyhow, bail};
1011
use clap::Parser;
1112
use cli::Args;
13+
use entity::{
14+
content,
15+
content_audit::{self, SelectionStrategy},
16+
execution_metadata,
17+
};
1218
use ethportal_api::{HistoryContentKey, OverlayContentKey};
19+
use glados_core::jsonrpc::{PortalClient, TransportConfig};
20+
use reqwest::header::{HeaderMap, HeaderValue};
1321
use sea_orm::DatabaseConnection;
1422
use tokio::{
1523
sync::mpsc,
1624
time::{sleep, Duration},
1725
};
1826
use tracing::{debug, error, info, warn};
19-
20-
use entity::{
21-
content,
22-
content_audit::{self, SelectionStrategy},
23-
execution_metadata,
24-
};
25-
use glados_core::jsonrpc::{PortalClient, TransportConfig};
27+
use url::Url;
28+
use validation::Provider;
29+
use web3::{transports::Http, Web3};
2630

2731
use crate::{
2832
cli::TransportType, selection::start_audit_selection_task, validation::content_is_valid,
@@ -43,10 +47,13 @@ pub struct AuditConfig {
4347
pub transport: TransportConfig,
4448
/// Specific strategies to run.
4549
pub strategies: Vec<SelectionStrategy>,
50+
/// An Ethereum execution node to validate content received from
51+
/// the Portal node against.
52+
pub trusted_provider: Provider,
4653
}
4754

4855
impl AuditConfig {
49-
pub fn from_args() -> Result<AuditConfig> {
56+
pub fn from_args() -> anyhow::Result<AuditConfig> {
5057
let args = Args::parse();
5158
let transport: TransportConfig = match args.transport {
5259
TransportType::IPC => match args.ipc_path {
@@ -87,11 +94,50 @@ impl AuditConfig {
8794
]
8895
}
8996
};
97+
let trusted_provider: Provider = match args.trusted_provider {
98+
cli::TrustedProvider::HTTP => {
99+
match args.provider_http_url{
100+
Some(url) => {
101+
let transport = Http::new(url.as_str())?;
102+
let w3 = Web3::new(transport);
103+
Provider::Http(w3)
104+
},
105+
None => bail!("The '--provider-http-url' flag is required if 'http' is selected for the '--trusted-provider'"),
106+
}
107+
},
108+
cli::TrustedProvider::Pandaops => {
109+
match args.provider_pandaops {
110+
Some(provider_url) => {
111+
let mut headers = HeaderMap::new();
112+
let client_id = env::var("PANDAOPS_CLIENT_ID")
113+
.map_err(|_| anyhow!("PANDAOPS_CLIENT_ID env var not set."))?;
114+
let client_id = HeaderValue::from_str(&client_id);
115+
let client_secret = env::var("PANDAOPS_CLIENT_SECRET")
116+
.map_err(|_| anyhow!("PANDAOPS_CLIENT_SECRET env var not set."))?;
117+
let client_secret = HeaderValue::from_str(&client_secret);
118+
headers.insert("CF-Access-Client-Id", client_id?);
119+
headers.insert("CF-Access-Client-Secret", client_secret?);
120+
121+
let client = reqwest::Client::builder()
122+
.default_headers(headers)
123+
.build()?;
124+
let url = Url::parse(&provider_url)?;
125+
let transport = Http::with_client(client, url);
126+
let w3 = Web3::new(transport);
127+
Provider::Pandaops(w3)
128+
},
129+
None => bail!("The '--provider-pandaops' flag is required if 'pandaops' is selected for the '--trusted-provider'"),
130+
}
131+
}
132+
}
133+
;
134+
90135
Ok(AuditConfig {
91136
concurrency: args.concurrency,
92137
database_url: args.database_url,
93138
transport,
94139
strategies,
140+
trusted_provider,
95141
})
96142
}
97143
}
@@ -201,9 +247,21 @@ async fn perform_single_audit(
201247
}
202248
};
203249

204-
// If content was absent audit result is 'fail'.
250+
// If content was absent or invalid the audit result is 'fail'.
205251
let audit_result = match content_response {
206-
Some(content_bytes) => content_is_valid(&task.content_key, &content_bytes.raw),
252+
Some(content_bytes) => {
253+
match content_is_valid(&config, &task.content_key, &content_bytes.raw).await {
254+
Ok(res) => res,
255+
Err(e) => {
256+
error!(
257+
content.key=?task.content_key.to_hex(),
258+
err=?e,
259+
"Problem requesting validation from Trusted provider node.");
260+
active_threads.fetch_sub(1, Ordering::Relaxed);
261+
return;
262+
}
263+
}
264+
}
207265
None => false,
208266
};
209267

0 commit comments

Comments
 (0)