#[cfg(test)]
mod tests {
use std::{sync::Arc, time::Duration};
use crate::rust_eigenda_signers::signers::private_key::Signer as PrivateKeySigner;
use crate::{
client::BlobProvider,
config::EigenConfig,
errors::{CommunicationError, EigenClientError},
test_eigenda_config, EigenClient,
};
use backon::{ConstantBuilder, Retryable};
use serial_test::serial;
use crate::blob_info::BlobInfo;
const STATUS_QUERY_INTERVAL: Duration = Duration::from_millis(5);
const MAX_RETRY_ATTEMPTS: usize = 1800000;
async fn get_blob_info<S>(
client: &EigenClient<S>,
blob_id: &str,
) -> Result<BlobInfo, EigenClientError> {
let blob_info = (|| async {
let blob_info = client.get_blob_info(blob_id).await?;
if blob_info.is_none() {
return Err(EigenClientError::Communication(
CommunicationError::FailedToGetBlob,
));
}
Ok(blob_info.unwrap())
})
.retry(
&ConstantBuilder::default()
.with_delay(STATUS_QUERY_INTERVAL)
.with_max_times(MAX_RETRY_ATTEMPTS),
)
.when(|e| {
matches!(
e,
EigenClientError::Communication(CommunicationError::FailedToGetBlob)
)
})
.await?;
Ok(blob_info)
}
#[derive(Debug, Clone)]
struct MockBlobProvider;
#[async_trait::async_trait]
impl BlobProvider for MockBlobProvider {
async fn get_blob(
&self,
_blob_id: &str,
) -> Result<Option<Vec<u8>>, Box<dyn std::error::Error + Send + Sync>> {
Ok(None)
}
}
#[ignore = "depends on external RPC"]
#[tokio::test]
#[serial]
async fn test_non_auth_dispersal() {
let config = test_eigenda_config();
let private_key = "d08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6"
.parse()
.unwrap();
let pk_signer = PrivateKeySigner::new(private_key);
let client = EigenClient::new(config.clone(), pk_signer, Arc::new(MockBlobProvider))
.await
.unwrap();
let data = vec![1; 20];
let result = client.dispatch_blob(data.clone()).await.unwrap();
let blob_info = get_blob_info(&client, &result).await.unwrap();
let expected_inclusion_data = blob_info.clone().blob_verification_proof.inclusion_proof;
let actual_inclusion_data = client.get_inclusion_data(&result).await.unwrap().unwrap();
assert!(actual_inclusion_data
.windows(expected_inclusion_data.len())
.any(|window| window == expected_inclusion_data)); let retrieved_data = client
.get_blob(
blob_info.blob_verification_proof.blob_index,
blob_info
.blob_verification_proof
.batch_medatada
.batch_header_hash,
)
.await
.unwrap();
assert_eq!(retrieved_data.unwrap(), data);
}
#[ignore = "depends on external RPC"]
#[tokio::test]
#[serial]
async fn test_check_finality() {
let config = test_eigenda_config();
let private_key = "d08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6"
.parse()
.unwrap();
let pk_signer = PrivateKeySigner::new(private_key);
let client = EigenClient::new(config.clone(), pk_signer, Arc::new(MockBlobProvider))
.await
.unwrap();
let data = vec![1; 20];
let result = client.dispatch_blob(data.clone()).await.unwrap();
let finalized = (|| async {
let finalized = client.check_finality(&result).await?;
if !finalized {
return Err(EigenClientError::Communication(
CommunicationError::FailedToGetBlob,
));
}
Ok(finalized)
})
.retry(
&ConstantBuilder::default()
.with_delay(STATUS_QUERY_INTERVAL)
.with_max_times(MAX_RETRY_ATTEMPTS),
)
.when(|e| {
matches!(
e,
EigenClientError::Communication(CommunicationError::FailedToGetBlob)
)
})
.await
.unwrap();
assert!(finalized);
}
#[ignore = "depends on external RPC"]
#[tokio::test]
#[serial]
async fn test_auth_dispersal() {
let config = EigenConfig {
authenticated: true,
..test_eigenda_config()
};
let pk = "d08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6"
.parse()
.unwrap();
let pk_signer = PrivateKeySigner::new(pk);
let client = EigenClient::new(config.clone(), pk_signer, Arc::new(MockBlobProvider))
.await
.unwrap();
let data = vec![1; 20];
let result = client.dispatch_blob(data.clone()).await.unwrap();
let blob_info = get_blob_info(&client, &result).await.unwrap();
let expected_inclusion_data = blob_info.clone().blob_verification_proof.inclusion_proof;
let actual_inclusion_data = client.get_inclusion_data(&result).await.unwrap().unwrap();
assert!(actual_inclusion_data
.windows(expected_inclusion_data.len())
.any(|window| window == expected_inclusion_data)); let retrieved_data = client
.get_blob(
blob_info.blob_verification_proof.blob_index,
blob_info
.blob_verification_proof
.batch_medatada
.batch_header_hash,
)
.await
.unwrap();
assert_eq!(retrieved_data.unwrap(), data);
}
#[ignore = "depends on external RPC"]
#[tokio::test]
#[serial]
async fn test_wait_for_finalization() {
let config = EigenConfig {
wait_for_finalization: true,
authenticated: true,
..test_eigenda_config()
};
let pk = "d08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6"
.parse()
.unwrap();
let pk_signer = PrivateKeySigner::new(pk);
let client = EigenClient::new(config.clone(), pk_signer, Arc::new(MockBlobProvider))
.await
.unwrap();
let data = vec![1; 20];
let result = client.dispatch_blob(data.clone()).await.unwrap();
let blob_info = get_blob_info(&client, &result).await.unwrap();
let expected_inclusion_data = blob_info.clone().blob_verification_proof.inclusion_proof;
let actual_inclusion_data = client.get_inclusion_data(&result).await.unwrap().unwrap();
assert!(actual_inclusion_data
.windows(expected_inclusion_data.len())
.any(|window| window == expected_inclusion_data)); let retrieved_data = client
.get_blob(
blob_info.blob_verification_proof.blob_index,
blob_info
.blob_verification_proof
.batch_medatada
.batch_header_hash,
)
.await
.unwrap();
assert_eq!(retrieved_data.unwrap(), data);
}
#[ignore = "depends on external RPC"]
#[tokio::test]
#[serial]
async fn test_settlement_layer_confirmation_depth() {
let config = EigenConfig {
settlement_layer_confirmation_depth: 5,
..test_eigenda_config()
};
let pk = "d08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6"
.parse()
.unwrap();
let pk_signer = PrivateKeySigner::new(pk);
let client = EigenClient::new(config.clone(), pk_signer, Arc::new(MockBlobProvider))
.await
.unwrap();
let data = vec![1; 20];
let result = client.dispatch_blob(data.clone()).await.unwrap();
let blob_info = get_blob_info(&client, &result).await.unwrap();
let expected_inclusion_data = blob_info.clone().blob_verification_proof.inclusion_proof;
let actual_inclusion_data = client.get_inclusion_data(&result).await.unwrap().unwrap();
assert!(actual_inclusion_data
.windows(expected_inclusion_data.len())
.any(|window| window == expected_inclusion_data)); let retrieved_data = client
.get_blob(
blob_info.blob_verification_proof.blob_index,
blob_info
.blob_verification_proof
.batch_medatada
.batch_header_hash,
)
.await
.unwrap();
assert_eq!(retrieved_data.unwrap(), data);
}
#[ignore = "depends on external RPC"]
#[tokio::test]
#[serial]
async fn test_auth_dispersal_settlement_layer_confirmation_depth() {
let config = EigenConfig {
settlement_layer_confirmation_depth: 5,
authenticated: true,
..test_eigenda_config()
};
let pk = "d08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6"
.parse()
.unwrap();
let pk_signer = PrivateKeySigner::new(pk);
let client = EigenClient::new(config.clone(), pk_signer, Arc::new(MockBlobProvider))
.await
.unwrap();
let data = vec![1; 20];
let result = client.dispatch_blob(data.clone()).await.unwrap();
let blob_info = get_blob_info(&client, &result).await.unwrap();
let expected_inclusion_data = blob_info.clone().blob_verification_proof.inclusion_proof;
let actual_inclusion_data = client.get_inclusion_data(&result).await.unwrap().unwrap();
assert!(actual_inclusion_data
.windows(expected_inclusion_data.len())
.any(|window| window == expected_inclusion_data)); let retrieved_data = client
.get_blob(
blob_info.blob_verification_proof.blob_index,
blob_info
.blob_verification_proof
.batch_medatada
.batch_header_hash,
)
.await
.unwrap();
assert_eq!(retrieved_data.unwrap(), data);
}
#[ignore = "depends on external RPC"]
#[tokio::test]
#[serial]
async fn test_custom_quorum_numbers() {
let config = EigenConfig {
custom_quorum_numbers: vec![2],
..test_eigenda_config()
};
let pk = "d08aa7ae1bb5ddd46c3c2d8cdb5894ab9f54dec467233686ca42629e826ac4c6"
.parse()
.unwrap();
let pk_signer = PrivateKeySigner::new(pk);
let client = EigenClient::new(config.clone(), pk_signer, Arc::new(MockBlobProvider))
.await
.unwrap();
let data = vec![1; 20];
let result = client.dispatch_blob(data.clone()).await.unwrap();
let blob_info = get_blob_info(&client, &result).await.unwrap();
let expected_inclusion_data = blob_info.clone().blob_verification_proof.inclusion_proof;
let actual_inclusion_data = client.get_inclusion_data(&result).await.unwrap().unwrap();
assert!(actual_inclusion_data
.windows(expected_inclusion_data.len())
.any(|window| window == expected_inclusion_data)); let retrieved_data = client
.get_blob(
blob_info.blob_verification_proof.blob_index,
blob_info
.blob_verification_proof
.batch_medatada
.batch_header_hash,
)
.await
.unwrap();
assert_eq!(retrieved_data.unwrap(), data);
}
}