Skip to content

Commit 4a93d39

Browse files
committed
fix(coprocessor): wip
1 parent 9f94772 commit 4a93d39

File tree

9 files changed

+106
-38
lines changed

9 files changed

+106
-38
lines changed

coprocessor/fhevm-engine/Cargo.lock

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

coprocessor/fhevm-engine/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ axum = "0.7"
3232
tower-http = { version = "0.5", features = ["trace"] }
3333
anyhow = "1.0.98"
3434
aws-config = "1.8.5"
35+
aws-credential-types = "1.2.6"
3536
aws-sdk-kms = { version = "1.68.0", default-features = false }
3637
aws-sdk-s3 = { version = "1.103.0", features = ["test-util"] }
3738
bigdecimal = "0.4.8"

coprocessor/fhevm-engine/gw-listener/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ alloy = { workspace = true }
1111
anyhow = { workspace = true }
1212
axum = { workspace = true }
1313
aws-config = { workspace = true }
14+
aws-credential-types = { workspace = true }
1415
aws-sdk-s3 = { workspace = true }
1516
clap = { workspace = true }
1617
futures-util = { workspace = true }
@@ -26,6 +27,7 @@ tokio-util = { workspace = true }
2627
tracing = { workspace = true }
2728
tracing-subscriber = { workspace = true }
2829
tower-http = { workspace = true }
30+
url = "2.5.7"
2931

3032
fhevm-engine-common = { path = "../fhevm-engine-common" }
3133

coprocessor/fhevm-engine/gw-listener/src/aws_s3.rs

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::time::Duration;
33
use aws_config::{retry::RetryConfig, timeout::TimeoutConfig, BehaviorVersion};
44
use aws_sdk_s3::{config::Builder, Client};
55
use tokio_util::bytes;
6-
use tracing::{error, info};
6+
use tracing::{error, info, warn};
77

88
#[derive(Clone, Debug, Default)]
99
pub struct S3Policy {
@@ -26,8 +26,16 @@ impl S3Policy {
2626
};
2727
}
2828

29-
pub async fn create_s3_client(retry_policy: &S3Policy) -> aws_sdk_s3::Client {
29+
use aws_sdk_s3::config::ProvideCredentials;
30+
pub async fn create_s3_client(retry_policy: &S3Policy, url: &str) -> aws_sdk_s3::Client {
3031
let sdk_config = aws_config::load_defaults(BehaviorVersion::latest()).await;
32+
33+
let credentials = sdk_config.credentials_provider().unwrap().provide_credentials().await.unwrap();
34+
info!(access_key = %credentials.access_key_id(), "Loaded AWS credentials");
35+
36+
let region = sdk_config.region();
37+
info!(region = ?region, "Using AWS region");
38+
3139
let timeout_config = TimeoutConfig::builder()
3240
.connect_timeout(retry_policy.connect_timeout)
3341
.operation_attempt_timeout(retry_policy.max_retries_timeout)
@@ -40,43 +48,62 @@ pub async fn create_s3_client(retry_policy: &S3Policy) -> aws_sdk_s3::Client {
4048
let config = Builder::from(&sdk_config)
4149
.timeout_config(timeout_config)
4250
.retry_config(retry_config)
51+
.endpoint_url(url)
4352
.build();
4453

4554
Client::from_conf(config)
4655
}
4756

48-
pub async fn default_aws_s3_client() -> AwsS3Client {
49-
let s3_client = create_s3_client(&S3Policy::DEFAULT).await;
50-
AwsS3Client { s3_client }
51-
}
52-
53-
// Let's wrap Aws Client to have an interface for it so we can mock it.
57+
// Let's wrap Aws access to have an interface for it so we can mock it.
5458
#[derive(Clone)]
55-
pub struct AwsS3Client {
56-
pub s3_client: Client,
57-
}
59+
pub struct AwsS3Client {}
5860

5961
impl AwsS3Interface for AwsS3Client {
60-
async fn get_bucket_key(&self, bucket: &str, key: &str) -> anyhow::Result<bytes::Bytes> {
61-
let result = self
62-
.s3_client
62+
async fn get_bucket_key(
63+
&self,
64+
url: &str,
65+
bucket: &str,
66+
key: &str,
67+
) -> anyhow::Result<bytes::Bytes> {
68+
Ok(create_s3_client(&S3Policy::DEFAULT, url)
69+
.await
6370
.get_object()
6471
.bucket(bucket)
6572
.key(key)
6673
.send()
67-
.await?;
68-
Ok(result.body.collect().await?.into_bytes())
74+
.await?
75+
.body
76+
.collect()
77+
.await?
78+
.into_bytes())
6979
}
7080
}
7181

7282
pub trait AwsS3Interface {
7383
fn get_bucket_key(
7484
&self,
85+
url: &str,
7586
bucket: &str,
7687
key: &str,
7788
) -> impl std::future::Future<Output = anyhow::Result<bytes::Bytes>>;
7889
}
7990

91+
fn split_url(s3_bucket_url: &String) -> anyhow::Result<(String, String)> {
92+
let parsed_url_and_bucket = url::Url::parse(s3_bucket_url)?;
93+
let bucket = parsed_url_and_bucket.path();
94+
let host = s3_bucket_url.replace(bucket, "").trim_end_matches('/').to_owned();
95+
let host = if host.contains("minio:9000") {
96+
// TODO: replace by docker configuration
97+
warn!(s3_bucket_url, "Using localhost for minio access");
98+
host.replace("minio:9000", "172.17.0.1:9000")
99+
} else {
100+
host.to_owned()
101+
};
102+
let bucket = bucket.trim_start_matches('/');
103+
info!(s3_bucket_url, host, bucket, "Parsed S3 url");
104+
Ok((host.to_owned(), bucket.to_owned()))
105+
}
106+
80107
pub async fn download_key_from_s3<A: AwsS3Interface>(
81108
s3_client: &A,
82109
s3_bucket_urls: &[String],
@@ -92,7 +119,11 @@ pub async fn download_key_from_s3<A: AwsS3Interface>(
92119
key_path,
93120
s3_bucket_url, i_s3_bucket_url, nb_urls, url_index, "Try downloading"
94121
);
95-
let result = s3_client.get_bucket_key(s3_bucket_url, &key_path).await;
122+
let Ok((url, bucket)) = split_url(s3_bucket_url) else {
123+
error!(s3_bucket_url, "Failed to parse S3 url");
124+
continue;
125+
};
126+
let result = s3_client.get_bucket_key(&url, &bucket, &key_path).await;
96127
let Ok(result) = result else {
97128
error!(s3_bucket_url, key_path, result = ?result, "Downloading failed");
98129
continue;

coprocessor/fhevm-engine/gw-listener/src/bin/gw_listener.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::time::Duration;
33
use alloy::providers::{ProviderBuilder, WsConnect};
44
use alloy::{primitives::Address, transports::http::reqwest::Url};
55
use clap::Parser;
6-
use gw_listener::aws_s3::default_aws_s3_client;
6+
use gw_listener::aws_s3::AwsS3Client;
77
use gw_listener::gw_listener::GatewayListener;
88
use gw_listener::http_server::HttpServer;
99
use gw_listener::ConfigSettings;
@@ -116,7 +116,7 @@ async fn main() -> anyhow::Result<()> {
116116
}
117117
};
118118

119-
let aws_s3_client = default_aws_s3_client().await;
119+
let aws_s3_client = AwsS3Client {};
120120

121121
let cancel_token = CancellationToken::new();
122122

coprocessor/fhevm-engine/gw-listener/tests/gw_listener_tests.rs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ use alloy::{
99
sol,
1010
};
1111

12-
use aws_sdk_s3::operation::get_object::GetObjectError;
13-
use gw_listener::gw_listener::GatewayListener;
14-
use gw_listener::ConfigSettings;
12+
use aws_sdk_s3::{operation::get_object::GetObjectError, Client};
1513
use gw_listener::{
16-
aws_s3::{default_aws_s3_client, AwsS3Client},
17-
gw_listener::{key_id_to_key_bucket, to_bucket_key_prefix},
14+
aws_s3::{AwsS3Client, AwsS3Interface},
15+
gw_listener::{key_id_to_key_bucket, to_bucket_key_prefix, GatewayListener},
16+
ConfigSettings,
1817
};
1918
use serial_test::serial;
2019
use sqlx::{postgres::PgPoolOptions, Pool, Postgres};
2120
use test_harness::instance::ImportMode;
2221
use tokio::time::sleep;
22+
use tokio_util::bytes;
2323
use tokio_util::sync::CancellationToken;
2424
use tracing::Level;
2525

@@ -105,7 +105,7 @@ async fn verify_proof_request_inserted_into_db() -> anyhow::Result<()> {
105105
.wallet(env.wallet)
106106
.connect_ws(WsConnect::new(env.anvil.ws_endpoint_url()))
107107
.await?;
108-
let aws_s3_client = default_aws_s3_client().await;
108+
let aws_s3_client = AwsS3Client {};
109109
let input_verification = InputVerification::deploy(&provider).await?;
110110
let kms_management = KMSManagement::deploy(&provider).await?;
111111
let gw_listener = GatewayListener::new(
@@ -213,6 +213,30 @@ async fn has_crs(db_pool: &Pool<Postgres>) -> anyhow::Result<bool> {
213213
Ok(false)
214214
}
215215

216+
#[derive(Clone)]
217+
pub struct AwsS3ClientMocked(Client);
218+
219+
impl AwsS3Interface for AwsS3ClientMocked {
220+
async fn get_bucket_key(
221+
&self,
222+
url: &str,
223+
bucket: &str,
224+
key: &str,
225+
) -> anyhow::Result<bytes::Bytes> {
226+
Ok(self
227+
.0
228+
.get_object()
229+
.bucket(bucket)
230+
.key(key)
231+
.send()
232+
.await?
233+
.body
234+
.collect()
235+
.await?
236+
.into_bytes())
237+
}
238+
}
239+
216240
// test bad bucket
217241
// test bad key
218242
#[tokio::test]
@@ -233,10 +257,10 @@ async fn keygen_ok() -> anyhow::Result<()> {
233257

234258
// see ../contracts/KMSManagement.sol
235259
let buckets = [
236-
"https://s3.amazonaws.com/test-bucket1/PUB-P1",
237-
"https://s3.amazonaws.com/test-bucket2/PUB-P2",
238-
"https://s3.amazonaws.com/test-bucket3/PUB-P3",
239-
"https://s3.amazonaws.com/test-bucket4/PUB-P4",
260+
"/test-bucket1/PUB-P1",
261+
"/test-bucket2/PUB-P2",
262+
"/test-bucket3/PUB-P3",
263+
"/test-bucket4/PUB-P4",
240264
];
241265

242266
let keys_digests = [KeyType::PublicKey, KeyType::ServerKey];
@@ -283,7 +307,7 @@ async fn keygen_ok() -> anyhow::Result<()> {
283307
.wallet(env.wallet)
284308
.connect_ws(WsConnect::new(env.anvil.ws_endpoint_url()))
285309
.await?;
286-
let aws_s3_client = AwsS3Client { s3_client: s3 };
310+
let aws_s3_client = AwsS3ClientMocked(s3);
287311
let input_verification = InputVerification::deploy(&provider).await?;
288312
let kms_management = KMSManagement::deploy(&provider).await?;
289313
let gw_listener = GatewayListener::new(
@@ -383,7 +407,7 @@ async fn keygen_compromised_key() -> anyhow::Result<()> {
383407
.wallet(env.wallet)
384408
.connect_ws(WsConnect::new(env.anvil.ws_endpoint_url()))
385409
.await?;
386-
let aws_s3_client = AwsS3Client { s3_client: s3 };
410+
let aws_s3_client = AwsS3ClientMocked(s3);
387411
let input_verification = InputVerification::deploy(&provider).await?;
388412
let kms_management = KMSManagement::deploy(&provider).await?;
389413
let gw_listener = GatewayListener::new(
@@ -489,7 +513,7 @@ async fn keygen_bad_key_or_bucket() -> anyhow::Result<()> {
489513
.wallet(env.wallet)
490514
.connect_ws(WsConnect::new(env.anvil.ws_endpoint_url()))
491515
.await?;
492-
let aws_s3_client = AwsS3Client { s3_client: s3 };
516+
let aws_s3_client = AwsS3ClientMocked(s3);
493517
let input_verification = InputVerification::deploy(&provider).await?;
494518
let kms_management = KMSManagement::deploy(&provider).await?;
495519
let gw_listener = GatewayListener::new(

coprocessor/fhevm-engine/sns-worker/src/executor.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,10 @@ impl SwitchNSquashService {
154154
}
155155
}
156156

157-
async fn get_keyset(pool: PgPool,
157+
async fn get_keyset(
158+
pool: PgPool,
158159
keys_cache: Arc<RwLock<lru::LruCache<String, KeySet>>>,
159-
tenant_api_key: &String
160+
tenant_api_key: &String,
160161
) -> Result<Option<KeySet>, ExecutionError> {
161162
let t = telemetry::tracer("worker_loop_init");
162163
let s = t.child_span("fetch_keyset");
@@ -191,7 +192,10 @@ pub(crate) async fn run_loop(
191192
Some(keys)
192193
}
193194
None => {
194-
warn!(tenant_api_key = tenant_api_key, "No keys found for the given tenant_api_key");
195+
warn!(
196+
tenant_api_key = tenant_api_key,
197+
"No keys found for the given tenant_api_key"
198+
);
195199
None
196200
}
197201
};
@@ -205,7 +209,10 @@ pub(crate) async fn run_loop(
205209
update_last_active(last_active_at.clone()).await;
206210

207211
let Some(keys) = keys.as_ref() else {
208-
warn!(tenant_api_key = tenant_api_key, "No keys available, retrying in 5 seconds");
212+
warn!(
213+
tenant_api_key = tenant_api_key,
214+
"No keys available, retrying in 5 seconds"
215+
);
209216
tokio::time::sleep(Duration::from_secs(5)).await;
210217
if token.is_cancelled() {
211218
return Ok(());
@@ -214,7 +221,7 @@ pub(crate) async fn run_loop(
214221
continue;
215222
};
216223

217-
let maybe_remaining = fetch_and_execute_sns_tasks(&pool, &tx, &keys, &conf, &token).await?;
224+
let maybe_remaining = fetch_and_execute_sns_tasks(&pool, &tx, keys, &conf, &token).await?;
218225
if maybe_remaining {
219226
if token.is_cancelled() {
220227
return Ok(());

test-suite/fhevm/fhevm-cli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export CONNECTOR_TX_SENDER_VERSION="6e7245c"
2929
# Coprocessor services.
3030
# TODO DB_MIGRATION_VERSION GW_LISTENER_VERSION
3131
export DB_MIGRATION_VERSION="38a694f"
32-
export GW_LISTENER_VERSION="5fa7075"
32+
export GW_LISTENER_VERSION="a73d853"
3333
export HOST_LISTENER_VERSION=${HOST_LISTENER_VERSION:-"v0.8.0-6"}
3434
export TX_SENDER_VERSION=${TX_SENDER_VERSION:-"v0.8.0-6"}
3535

test-suite/fhevm/scripts/deploy-fhevm-stack.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ log_info "Starting crs & keygen"
355355
cd ${SCRIPT_DIR}/../../../gateway-contracts
356356

357357
DEPLOYER_PRIVATE_KEY="0x7136d8dc72f873124f4eded25f3525a20f6cee4296564c76b44f1d582c57640f" npx hardhat task:deployEmptyUUPSProxies
358+
sed -i s/KMS_MANAGEMENT_ADDRESS=0xDE409109E0fCCAaE7B87De518F61d617A3fda094/KMS_MANAGEMENT_ADDRESS=0xF0bFB159C7381F7CB332586004d8247252C5b816/g addresses/.env.gateway
358359

359360
DOTENV_CONFIG_PATH=.env.example HARDHAT_NETWORK=staging CHAIN_ID_GATEWAY=54321 RPC_URL=http://localhost:8546 npx hardhat task:triggerCrsgen \
360361
--max-bit-length 2048 \

0 commit comments

Comments
 (0)