Skip to content

Commit 5a2e329

Browse files
fix(kms-connector): increase gas_limit (#258)
* fix(kms-connector): add gas_limit * fix(kms-connector): increase gas limit * fix(kms-connector): infinite gas limit + add tx retry * fix(kms-connector): add more logs
1 parent edf7961 commit 5a2e329

File tree

3 files changed

+70
-17
lines changed

3 files changed

+70
-17
lines changed

kms-connector/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,14 @@ The KMS Connector supports flexible configuration through both TOML files and en
156156
# Set required configuration
157157
export KMS_CONNECTOR_GATEWAY_URL="ws://localhost:8547"
158158
export KMS_CONNECTOR_KMS_CORE_ENDPOINT="http://localhost:50052"
159-
159+
160160
# Wallet configuration (one of the following is required)
161161
export KMS_CONNECTOR_PRIVATE_KEY="0x0000000000000000000000000000000000000000000000000000000000000001"
162162
# OR for AWS KMS
163163
export KMS_CONNECTOR_AWS_KMS_CONFIG__KEY_ID="alias/my-kms-key"
164164
export KMS_CONNECTOR_AWS_KMS_CONFIG__REGION="us-east-1"
165165
export KMS_CONNECTOR_AWS_KMS_CONFIG__ENDPOINT="http://localhost:4566"
166-
166+
167167
export KMS_CONNECTOR_CHAIN_ID="31337"
168168
export KMS_CONNECTOR_DECRYPTION_ADDRESS="0x..."
169169
export KMS_CONNECTOR_GATEWAY_CONFIG_ADDRESS="0x..."
@@ -478,4 +478,4 @@ cargo test
478478

479479
🌟 If you find this project helpful or interesting, please consider giving it a star on GitHub! Your support helps to grow the community and motivates further development.
480480

481-
[![GitHub stars](https://img.shields.io/github/stars/zama-ai/fhevm?style=social)](https://github.com/zama-ai/fhevm/)
481+
[![GitHub stars](https://img.shields.io/github/stars/zama-ai/fhevm?style=social)](https://github.com/zama-ai/fhevm/)

kms-connector/simple-connector/src/core/connector.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ impl<P: Provider + Clone + 'static> KmsCoreConnector<P> {
3737
config.gateway_config_address,
3838
event_tx,
3939
);
40+
41+
// Possible gas limit
4042
let decryption = DecryptionAdapter::new(config.decryption_address, provider.clone());
4143

4244
let decryption_handler =

kms-connector/simple-connector/src/gw_adapters/decryption/adapter.rs

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
use crate::error::{Error, Result};
22
use alloy::{
3+
network::Ethereum,
34
primitives::{Address, Bytes, U256},
4-
providers::Provider,
5+
providers::{PendingTransactionBuilder, Provider},
6+
rpc::types::TransactionRequest,
57
};
68
use fhevm_gateway_rust_bindings::decryption::Decryption;
7-
use std::sync::Arc;
8-
use tracing::{debug, info};
9+
use std::{sync::Arc, time::Duration};
10+
use tracing::{debug, info, warn};
11+
12+
/// The max value for the `gas_limit` of a transaction.
13+
const INFINITE_GAS_LIMIT: u64 = u64::MAX;
14+
15+
/// The time to wait between two transactions attempt.
16+
const TX_INTERVAL: Duration = Duration::from_secs(3);
917

1018
/// Adapter for decryption operations
1119
#[derive(Clone)]
@@ -57,18 +65,20 @@ impl<P: Provider + Clone> DecryptionAdapter<P> {
5765

5866
let contract = Decryption::new(self.decryption_address, self.provider.clone());
5967

60-
// Create and send transaction
61-
let call = contract.publicDecryptionResponse(id, result, signature.into());
62-
let tx = call
63-
.send()
64-
.await
65-
.map_err(|e| Error::Contract(e.to_string()))?;
68+
let call_builder = contract.publicDecryptionResponse(id, result, signature.into());
69+
info!(decryption_id = ?id, "public decryption calldata length {}", call_builder.calldata().len());
70+
71+
let mut call = call_builder.into_transaction_request();
72+
self.estimate_gas(id, &mut call).await;
73+
let tx = self.send_tx_with_retry(call).await?;
74+
6675
// TODO: optimize for low latency
6776
let receipt = tx
6877
.get_receipt()
6978
.await
7079
.map_err(|e| Error::Contract(e.to_string()))?;
7180
info!(decryption_id = ?id, "🎯 Public Decryption response sent with tx receipt: {:?}", receipt);
81+
info!(decryption_id = ?id, "⛽ Gas consumed for Public Decryption: {}", receipt.gas_used);
7282
Ok(())
7383
}
7484

@@ -102,17 +112,58 @@ impl<P: Provider + Clone> DecryptionAdapter<P> {
102112
let contract = Decryption::new(self.decryption_address, self.provider.clone());
103113

104114
// Create and send transaction
105-
let call = contract.userDecryptionResponse(id, result, signature.into());
106-
let tx = call
107-
.send()
108-
.await
109-
.map_err(|e| Error::Contract(e.to_string()))?;
115+
let call_builder = contract.userDecryptionResponse(id, result, signature.into());
116+
info!(decryption_id = ?id, "user decryption calldata length {}", call_builder.calldata().len());
117+
118+
let mut call = call_builder.into_transaction_request();
119+
self.estimate_gas(id, &mut call).await;
120+
let tx = self.send_tx_with_retry(call).await?;
121+
110122
// TODO: optimize for low latency
111123
let receipt = tx
112124
.get_receipt()
113125
.await
114126
.map_err(|e| Error::Contract(e.to_string()))?;
115127
info!(decryption_id = ?id, "🎯 User Decryption response sent with tx receipt: {:?}", receipt);
128+
info!(decryption_id = ?id, "⛽ Gas consumed for User Decryption: {}", receipt.gas_used);
116129
Ok(())
117130
}
131+
132+
/// Estimates the `gas_limit` for the upcoming transaction.
133+
async fn estimate_gas(&self, id: U256, call: &mut TransactionRequest) {
134+
match self.provider.estimate_gas(call.clone()).await {
135+
Ok(gas) => info!(decryption_id = ?id, "Initial gas estimation for the tx: {gas}"),
136+
Err(e) => warn!(decryption_id = ?id, "Failed to estimate gas for the tx: {e}"),
137+
}
138+
139+
// TODO: temporary workaround for out-of-gas errors
140+
// Our automatic estimation fails during gas pikes.
141+
// (see https://zama-ai.slack.com/archives/C0915Q59CKG/p1749843623276629?thread_ts=1749828466.079719&cid=C0915Q59CKG)
142+
info!(decryption_id = ?id, "Updating `gas_limit` to max value");
143+
call.gas = Some(INFINITE_GAS_LIMIT);
144+
}
145+
146+
/// Sends the requested transactions with one retry.
147+
async fn send_tx_with_retry(
148+
&self,
149+
call: TransactionRequest,
150+
) -> Result<PendingTransactionBuilder<Ethereum>> {
151+
match self.provider.send_transaction(call.clone()).await {
152+
Ok(tx) => Ok(tx),
153+
Err(e) => {
154+
warn!(
155+
"Retrying to send transaction in {}s after failure: {}",
156+
TX_INTERVAL.as_secs(),
157+
e
158+
);
159+
160+
tokio::time::sleep(TX_INTERVAL).await;
161+
162+
self.provider
163+
.send_transaction(call)
164+
.await
165+
.map_err(|e| Error::Contract(e.to_string()))
166+
}
167+
}
168+
}
118169
}

0 commit comments

Comments
 (0)