Skip to content

Commit

Permalink
Introduce a way for callers to get CCIP requests (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
Antony1060 authored Dec 6, 2023
1 parent 62688ad commit e4a1adb
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 11 deletions.
14 changes: 11 additions & 3 deletions src/ccip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use serde::Deserialize;
use crate::errors::{CCIPFetchError, CCIPRequestError};
use crate::utils::truncate_str;
use crate::CCIPReadMiddlewareError;
use crate::CCIPRequest;

#[derive(Debug, Clone, Deserialize)]
pub struct CCIPResponse {
Expand Down Expand Up @@ -98,22 +99,29 @@ pub async fn handle_ccip<M: Middleware>(
tx: &TypedTransaction,
calldata: &[u8],
urls: Vec<String>,
) -> Result<Bytes, CCIPReadMiddlewareError<M>> {
) -> Result<(Bytes, Vec<CCIPRequest>), CCIPReadMiddlewareError<M>> {
// If there are no URLs or the transaction's destination is empty, return an empty result
if urls.is_empty() || tx.to().is_none() {
return Ok(Bytes::new());
return Ok((Bytes::new(), Vec::new()));
}

let urls = dedup_ord(&urls);

// url —> [error_message]
let mut errors: HashMap<String, Vec<String>> = HashMap::new();

let mut requests = Vec::new();

for url in urls {
let result = handle_ccip_raw(client, &url, sender, calldata).await;
requests.push(CCIPRequest {
url: url.clone(),
sender: *sender,
calldata: calldata.to_vec().into(),
});

match result {
Ok(result) => return Ok(result),
Ok(result) => return Ok((result, requests)),
Err(err) => {
errors.entry(url).or_default().push(err.to_string());
}
Expand Down
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@
//!
//! Provides an [ethers](https://docs.rs/ethers) compatible middleware for submitting
pub use errors::CCIPReadMiddlewareError;
use ethers_core::types::{Address, Bytes};
pub use middleware::CCIPReadMiddleware;

mod ccip;
mod errors;
mod middleware;
pub mod utils;

#[derive(Debug, Clone)]
pub struct CCIPRequest {
pub url: String,
pub sender: Address,
pub calldata: Bytes,
}
31 changes: 23 additions & 8 deletions src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use serde_json::Value;

use crate::ccip::handle_ccip;
use crate::utils::{build_reqwest, decode_bytes, dns_encode};
use crate::CCIPReadMiddlewareError;
use crate::{CCIPReadMiddlewareError, CCIPRequest};

#[derive(Debug, Clone)]
pub struct CCIPReadMiddleware<M> {
Expand Down Expand Up @@ -229,7 +229,8 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
transaction: &TypedTransaction,
block_id: Option<BlockId>,
attempt: u8,
) -> Result<Bytes, CCIPReadMiddlewareError<M>> {
requests_buffer: &mut Vec<CCIPRequest>,
) -> Result<(Bytes, Vec<CCIPRequest>), CCIPReadMiddlewareError<M>> {
if attempt >= self.max_redirect_attempt {
// may need more info
return Err(CCIPReadMiddlewareError::MaxRedirectionError);
Expand Down Expand Up @@ -258,14 +259,14 @@ impl<M: Middleware> CCIPReadMiddleware<M> {

if !matches!(block_id.unwrap_or(BlockId::Number(BlockNumber::Latest)), BlockId::Number(block) if block.is_latest())
{
return Ok(result);
return Ok((result, requests_buffer.to_vec()));
}

if tx_sender.is_zero()
|| !result.starts_with(OFFCHAIN_LOOKUP_SELECTOR)
|| result.len() % 32 != 4
{
return Ok(result);
return Ok((result, requests_buffer.to_vec()));
}

let output_types = vec![
Expand All @@ -292,7 +293,7 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
decoded_data.get(4),
)
else {
return Ok(result);
return Ok((result, requests_buffer.to_vec()));
};

let urls: Vec<String> = urls
Expand All @@ -310,9 +311,11 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
});
}

let ccip_result =
let (ccip_result, requests) =
handle_ccip(&self.reqwest_client, sender, transaction, calldata, urls).await?;

requests_buffer.extend(requests);

if ccip_result.is_empty() {
return Err(CCIPReadMiddlewareError::GatewayNotFoundError);
}
Expand All @@ -327,7 +330,19 @@ impl<M: Middleware> CCIPReadMiddleware<M> {
[callback_selector.clone(), encoded_data.clone()].concat(),
));

self._call(&callback_tx, block_id, attempt + 1).await
self._call(&callback_tx, block_id, attempt + 1, requests_buffer)
.await
}

/// Call the underlying middleware with the provided transaction and block,
/// returning both the result of the call and the CCIP requests made during the call
pub async fn call_ccip(
&self,
tx: &TypedTransaction,
block: Option<BlockId>,
) -> Result<(Bytes, Vec<CCIPRequest>), CCIPReadMiddlewareError<M>> {
let mut requests = Vec::new();
self._call(tx, block, 0, &mut requests).await
}
}

Expand All @@ -353,7 +368,7 @@ where
tx: &TypedTransaction,
block: Option<BlockId>,
) -> Result<Bytes, Self::Error> {
return self._call(tx, block, 0).await;
Ok(self.call_ccip(tx, block).await?.0)
}

/**
Expand Down

0 comments on commit e4a1adb

Please sign in to comment.