Skip to content

Commit

Permalink
refactor!: use single executor for manager and auditor
Browse files Browse the repository at this point in the history
Signed-off-by: Gustavo Inacio <gustavo@semiotic.ai>
  • Loading branch information
gusinacio committed Dec 27, 2023
1 parent 467c917 commit 6794fbb
Show file tree
Hide file tree
Showing 10 changed files with 525 additions and 200 deletions.
1 change: 1 addition & 0 deletions tap_core/src/adapters/mock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2023-, Semiotic AI, Inc.
// SPDX-License-Identifier: Apache-2.0

pub mod auditor_executor_mock;
pub mod escrow_adapter_mock;
pub mod executor_mock;
pub mod rav_storage_adapter_mock;
Expand Down
171 changes: 171 additions & 0 deletions tap_core/src/adapters/mock/auditor_executor_mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright 2023-, Semiotic AI, Inc.
// SPDX-License-Identifier: Apache-2.0

use super::{escrow_adapter_mock::AdpaterErrorMock, receipt_checks_adapter_mock::AdapterErrorMock};
use crate::adapters::escrow_adapter::EscrowAdapter;
use crate::adapters::receipt_checks_adapter::ReceiptChecksAdapter;
use crate::eip_712_signed_message::EIP712SignedMessage;
use crate::tap_receipt::{Receipt, ReceivedReceipt};
use alloy_primitives::Address;
use async_trait::async_trait;
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use tokio::sync::RwLock;

/// `RAVStorageAdapterMock` is a mock implementation of the `RAVStorageAdapter` trait.
///
/// It serves two main purposes:
///
/// 1. **Unit Testing**: The `RAVStorageAdapterMock` is primarily intended to be used for unit tests,
/// providing a way to simulate the behavior of a real `RAVStorageAdapter` without requiring a real
/// implementation. By using a mock implementation, you can create predictable behaviors and
/// responses, enabling isolated and focused testing of the logic that depends on the `RAVStorageAdapter` trait.
///
/// 2. **Example Implementation**: New users of the `RAVStorageAdapter` trait can look to
/// `RAVStorageAdapterMock` as a basic example of how to implement the trait.
///
/// Note: This mock implementation is not suitable for production use. Its methods simply manipulate a
/// local `RwLock<Option<SignedRAV>>`, and it provides no real error handling.
///
/// # Usage
///
/// To use `RAVStorageAdapterMock`, first create an `Arc<RwLock<Option<SignedRAV>>>`, then pass it to
/// `RAVStorageAdapterMock::new()`. Now, it can be used anywhere a `RAVStorageAdapter` is required.
///
/// ```rust
/// use std::sync::{Arc};
/// use tokio::sync::RwLock;
/// use tap_core::{tap_manager::SignedRAV, adapters::rav_storage_adapter_mock::RAVStorageAdapterMock};
///
/// let rav_storage: Arc<RwLock<Option<SignedRAV>>> = Arc::new(RwLock::new(None));
/// let adapter = RAVStorageAdapterMock::new(rav_storage);
/// ```
#[derive(Clone)]
pub struct AuditorExecutorMock {
receipt_storage: Arc<RwLock<HashMap<u64, ReceivedReceipt>>>,

sender_escrow_storage: Arc<RwLock<HashMap<Address, u128>>>,

query_appraisals: Arc<RwLock<HashMap<u64, u128>>>,
allocation_ids: Arc<RwLock<HashSet<Address>>>,
sender_ids: Arc<RwLock<HashSet<Address>>>,
}

impl AuditorExecutorMock {
pub fn new(
receipt_storage: Arc<RwLock<HashMap<u64, ReceivedReceipt>>>,
sender_escrow_storage: Arc<RwLock<HashMap<Address, u128>>>,
query_appraisals: Arc<RwLock<HashMap<u64, u128>>>,
allocation_ids: Arc<RwLock<HashSet<Address>>>,
sender_ids: Arc<RwLock<HashSet<Address>>>,
) -> Self {
AuditorExecutorMock {
receipt_storage,
sender_escrow_storage,
allocation_ids,
sender_ids,
query_appraisals,
}
}
}

impl AuditorExecutorMock {
pub async fn escrow(&self, sender_id: Address) -> Result<u128, AdpaterErrorMock> {
let sender_escrow_storage = self.sender_escrow_storage.read().await;
if let Some(escrow) = sender_escrow_storage.get(&sender_id) {
return Ok(*escrow);
}
Err(AdpaterErrorMock::AdapterError {
error: "No escrow exists for provided sender ID.".to_owned(),
})
}

pub async fn increase_escrow(&mut self, sender_id: Address, value: u128) {
let mut sender_escrow_storage = self.sender_escrow_storage.write().await;

if let Some(current_value) = sender_escrow_storage.get(&sender_id) {
let mut sender_escrow_storage = self.sender_escrow_storage.write().await;
sender_escrow_storage.insert(sender_id, current_value + value);
} else {
sender_escrow_storage.insert(sender_id, value);
}
}

pub async fn reduce_escrow(
&self,
sender_id: Address,
value: u128,
) -> Result<(), AdpaterErrorMock> {
let mut sender_escrow_storage = self.sender_escrow_storage.write().await;

if let Some(current_value) = sender_escrow_storage.get(&sender_id) {
let checked_new_value = current_value.checked_sub(value);
if let Some(new_value) = checked_new_value {
sender_escrow_storage.insert(sender_id, new_value);
return Ok(());
}
}
Err(AdpaterErrorMock::AdapterError {
error: "Provided value is greater than existing escrow.".to_owned(),
})
}
}

#[async_trait]
impl EscrowAdapter for AuditorExecutorMock {
type AdapterError = AdpaterErrorMock;
async fn get_available_escrow(&self, sender_id: Address) -> Result<u128, Self::AdapterError> {
self.escrow(sender_id).await
}
async fn subtract_escrow(
&self,
sender_id: Address,
value: u128,
) -> Result<(), Self::AdapterError> {
self.reduce_escrow(sender_id, value).await
}
}

#[async_trait]
impl ReceiptChecksAdapter for AuditorExecutorMock {
type AdapterError = AdapterErrorMock;

async fn is_unique(
&self,
receipt: &EIP712SignedMessage<Receipt>,
receipt_id: u64,
) -> Result<bool, Self::AdapterError> {
let receipt_storage = self.receipt_storage.read().await;
Ok(receipt_storage
.iter()
.all(|(stored_receipt_id, stored_receipt)| {
(stored_receipt.signed_receipt().message != receipt.message)
|| *stored_receipt_id == receipt_id
}))
}

async fn is_valid_allocation_id(
&self,
allocation_id: Address,
) -> Result<bool, Self::AdapterError> {
let allocation_ids = self.allocation_ids.read().await;
Ok(allocation_ids.contains(&allocation_id))
}

async fn is_valid_value(&self, value: u128, query_id: u64) -> Result<bool, Self::AdapterError> {
let query_appraisals = self.query_appraisals.read().await;
let appraised_value = query_appraisals.get(&query_id).unwrap();

if value != *appraised_value {
return Ok(false);
}
Ok(true)
}

async fn is_valid_sender_id(&self, sender_id: Address) -> Result<bool, Self::AdapterError> {
let sender_ids = self.sender_ids.read().await;
Ok(sender_ids.contains(&sender_id))
}
}
129 changes: 125 additions & 4 deletions tap_core/src/adapters/mock/executor_mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,24 @@
// SPDX-License-Identifier: Apache-2.0

use super::{escrow_adapter_mock::AdpaterErrorMock, receipt_checks_adapter_mock::AdapterErrorMock};
use crate::adapters::escrow_adapter::EscrowAdapter;
use crate::adapters::receipt_checks_adapter::ReceiptChecksAdapter;
use crate::adapters::receipt_storage_adapter::{
safe_truncate_receipts, ReceiptRead, ReceiptStore, StoredReceipt,
};
use crate::tap_receipt::ReceivedReceipt;
use crate::eip_712_signed_message::EIP712SignedMessage;
use crate::tap_receipt::{Receipt, ReceivedReceipt};
use crate::{
adapters::rav_storage_adapter::{RAVRead, RAVStore},
tap_manager::SignedRAV,
};
use alloy_primitives::Address;
use async_trait::async_trait;
use std::ops::RangeBounds;
use std::{collections::HashMap, sync::Arc};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use tokio::sync::RwLock;

/// `RAVStorageAdapterMock` is a mock implementation of the `RAVStorageAdapter` trait.
Expand Down Expand Up @@ -43,22 +50,37 @@ use tokio::sync::RwLock;
/// let rav_storage: Arc<RwLock<Option<SignedRAV>>> = Arc::new(RwLock::new(None));
/// let adapter = RAVStorageAdapterMock::new(rav_storage);
/// ```
#[derive(Clone)]
pub struct ExecutorMock {
/// local RAV store with rwlocks to allow sharing with other compenents as needed
rav_storage: Arc<RwLock<Option<SignedRAV>>>,
receipt_storage: Arc<RwLock<HashMap<u64, ReceivedReceipt>>>,
unique_id: RwLock<u64>,
unique_id: Arc<RwLock<u64>>,

sender_escrow_storage: Arc<RwLock<HashMap<Address, u128>>>,

query_appraisals: Arc<RwLock<HashMap<u64, u128>>>,
allocation_ids: Arc<RwLock<HashSet<Address>>>,
sender_ids: Arc<RwLock<HashSet<Address>>>,
}

impl ExecutorMock {
pub fn new(
rav_storage: Arc<RwLock<Option<SignedRAV>>>,
receipt_storage: Arc<RwLock<HashMap<u64, ReceivedReceipt>>>,
sender_escrow_storage: Arc<RwLock<HashMap<Address, u128>>>,
query_appraisals: Arc<RwLock<HashMap<u64, u128>>>,
allocation_ids: Arc<RwLock<HashSet<Address>>>,
sender_ids: Arc<RwLock<HashSet<Address>>>,
) -> Self {
ExecutorMock {
rav_storage,
receipt_storage,
unique_id: RwLock::new(0),
unique_id: Arc::new(RwLock::new(0)),
sender_escrow_storage,
allocation_ids,
sender_ids,
query_appraisals,
}
}
}
Expand Down Expand Up @@ -149,3 +171,102 @@ impl ReceiptRead for ExecutorMock {
}
}
}

impl ExecutorMock {
pub async fn escrow(&self, sender_id: Address) -> Result<u128, AdpaterErrorMock> {
let sender_escrow_storage = self.sender_escrow_storage.read().await;
if let Some(escrow) = sender_escrow_storage.get(&sender_id) {
return Ok(*escrow);
}
Err(AdpaterErrorMock::AdapterError {
error: "No escrow exists for provided sender ID.".to_owned(),
})
}

pub async fn increase_escrow(&mut self, sender_id: Address, value: u128) {
let mut sender_escrow_storage = self.sender_escrow_storage.write().await;

if let Some(current_value) = sender_escrow_storage.get(&sender_id) {
let mut sender_escrow_storage = self.sender_escrow_storage.write().await;
sender_escrow_storage.insert(sender_id, current_value + value);
} else {
sender_escrow_storage.insert(sender_id, value);
}
}

pub async fn reduce_escrow(
&self,
sender_id: Address,
value: u128,
) -> Result<(), AdpaterErrorMock> {
let mut sender_escrow_storage = self.sender_escrow_storage.write().await;

if let Some(current_value) = sender_escrow_storage.get(&sender_id) {
let checked_new_value = current_value.checked_sub(value);
if let Some(new_value) = checked_new_value {
sender_escrow_storage.insert(sender_id, new_value);
return Ok(());
}
}
Err(AdpaterErrorMock::AdapterError {
error: "Provided value is greater than existing escrow.".to_owned(),
})
}
}

#[async_trait]
impl EscrowAdapter for ExecutorMock {
type AdapterError = AdpaterErrorMock;
async fn get_available_escrow(&self, sender_id: Address) -> Result<u128, Self::AdapterError> {
self.escrow(sender_id).await
}
async fn subtract_escrow(
&self,
sender_id: Address,
value: u128,
) -> Result<(), Self::AdapterError> {
self.reduce_escrow(sender_id, value).await
}
}

#[async_trait]
impl ReceiptChecksAdapter for ExecutorMock {
type AdapterError = AdapterErrorMock;

async fn is_unique(
&self,
receipt: &EIP712SignedMessage<Receipt>,
receipt_id: u64,
) -> Result<bool, Self::AdapterError> {
let receipt_storage = self.receipt_storage.read().await;
Ok(receipt_storage
.iter()
.all(|(stored_receipt_id, stored_receipt)| {
(stored_receipt.signed_receipt().message != receipt.message)
|| *stored_receipt_id == receipt_id
}))
}

async fn is_valid_allocation_id(
&self,
allocation_id: Address,
) -> Result<bool, Self::AdapterError> {
let allocation_ids = self.allocation_ids.read().await;
Ok(allocation_ids.contains(&allocation_id))
}

async fn is_valid_value(&self, value: u128, query_id: u64) -> Result<bool, Self::AdapterError> {
let query_appraisals = self.query_appraisals.read().await;
let appraised_value = query_appraisals.get(&query_id).unwrap();

if value != *appraised_value {
return Ok(false);
}
Ok(true)
}

async fn is_valid_sender_id(&self, sender_id: Address) -> Result<bool, Self::AdapterError> {
let sender_ids = self.sender_ids.read().await;
Ok(sender_ids.contains(&sender_id))
}
}
Loading

0 comments on commit 6794fbb

Please sign in to comment.