Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improved eigenlayer context and testing #453

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
399d384
feat!(blueprint-test-utils): wip making eigenlayer testing environmen…
Tjemmmic Nov 5, 2024
30da6c9
feat!(blueprint-test-utils): moved eigen test to blueprint and improv…
Tjemmmic Nov 6, 2024
958771c
Merge branch 'main' into donovan/eigen-improvements
Tjemmmic Nov 6, 2024
2c74234
Merge branch 'main' into donovan/eigen-improvements
Tjemmmic Nov 6, 2024
72edb32
feat!(macros): eigenlayer context methods and relevant tests wip
Tjemmmic Nov 6, 2024
cac4bfd
Merge branch 'main' into donovan/eigen-improvements
Tjemmmic Nov 6, 2024
4312e2a
feat!: more improvements to eigen utilities and eigen context example…
Tjemmmic Nov 9, 2024
4f6c905
feat(blueprint-test-utils): add contract bindings to remove relative …
Tjemmmic Nov 12, 2024
72a736d
feat(blueprint-examples): eigenlayer context example blueprint
Tjemmmic Nov 12, 2024
965cf04
chore(clippy): cleanup before merging in main
Tjemmmic Nov 12, 2024
e0d1c4d
Merge branch 'main' into donovan/eigen-improvements
Tjemmmic Nov 12, 2024
88f917f
chore(clippy): formatting
Tjemmmic Nov 12, 2024
1378d3f
feat(gadget-sdk): methods for easily creating context configs for eac…
Tjemmmic Nov 12, 2024
840a4a1
fix(ci): debugging ci
Tjemmmic Nov 12, 2024
4127a4e
fix(ci): import fix for ci
Tjemmmic Nov 13, 2024
f4e27ad
fix!: eigenlayer incredible squaring test no longer uses binary
Tjemmmic Nov 13, 2024
da5b847
fix!: eigenlayer incredible squaring test no longer hangs
Tjemmmic Nov 13, 2024
cadf0de
chore: clippy
Tjemmmic Nov 13, 2024
ad25295
chore: cleanup unnecessary code
Tjemmmic Nov 13, 2024
013b6f7
fix(ci): clippy, update workflow, and readme
Tjemmmic Nov 13, 2024
f736638
Merge branch 'main' into donovan/eigen-improvements
Tjemmmic Nov 13, 2024
41f2ed7
fix(ci): workflow fix after merge
Tjemmmic Nov 13, 2024
e94334a
fix(ci): fix build script for ci
Tjemmmic Nov 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion blueprint-metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustdoc_types::{Crate, Id, Item, ItemEnum, Module};

/// Generate `blueprint.json` to the current crate working directory next to `build.rs` file.
pub fn generate_json() {
Config::builder().build().generate_json();
// Config::builder().build().generate_json();
Tjemmmic marked this conversation as resolved.
Show resolved Hide resolved
}

#[derive(Debug, Clone, Default, typed_builder::TypedBuilder)]
Expand Down
1 change: 0 additions & 1 deletion blueprint-test-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ publish = false
default = ["std"]
std = ["sp-core/std", "gadget-io/std", "gadget-sdk/std"]
wasm = ["gadget-io/wasm-bindgen", "gadget-sdk/wasm"]
eigenlayer_test = []

[dependencies]
# Core dependencies
Expand Down
123 changes: 20 additions & 103 deletions blueprint-test-utils/src/eigenlayer_test_env.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
use alloy_primitives::{address, Address};
use alloy_provider::Provider;
use gadget_sdk::info;
use gadget_sdk::{config::protocol::EigenlayerContractAddresses, utils::evm::get_provider_http};

use crate::helpers::get_receipt;

alloy_sol_types::sol!(
#[allow(missing_docs)]
#[sol(rpc)]
#[derive(Debug)]
IncredibleSquaringTaskManager,
"./../blueprints/incredible-squaring-eigenlayer/contracts/out/IncredibleSquaringTaskManager.sol/IncredibleSquaringTaskManager.json"
);

alloy_sol_types::sol!(
#[allow(missing_docs)]
#[sol(rpc)]
#[derive(Debug)]
PauserRegistry,
"./../blueprints/incredible-squaring-eigenlayer/contracts/out/IPauserRegistry.sol/IPauserRegistry.json"
);

alloy_sol_types::sol!(
#[allow(missing_docs, clippy::too_many_arguments)]
#[sol(rpc)]
#[derive(Debug)]
RegistryCoordinator,
"./../blueprints/incredible-squaring-eigenlayer/contracts/out/RegistryCoordinator.sol/RegistryCoordinator.json"
);
pub use crate::helpers::get_receipt;
pub use alloy_primitives::{address, Address, Bytes, U256};
pub use alloy_provider::Provider;
pub use gadget_sdk::config::protocol::EigenlayerContractAddresses;
pub use gadget_sdk::futures::StreamExt;
pub use gadget_sdk::tokio::sync::Mutex;
pub use gadget_sdk::utils::evm::{get_provider_http, get_provider_ws};
pub use gadget_sdk::{error, info};
pub use std::sync::Arc;
pub use std::time::Duration;

pub const AVS_DIRECTORY_ADDR: Address = address!("0000000000000000000000000000000000000000");
pub const DELEGATION_MANAGER_ADDR: Address = address!("dc64a140aa3e981100a9beca4e685f962f0cf6c9");
pub const ERC20_MOCK_ADDR: Address = address!("7969c5ed335650692bc04293b07f5bf2e7a673c0");
pub const MAILBOX_ADDR: Address = address!("0000000000000000000000000000000000000000");
pub const OPERATOR_STATE_RETRIEVER_ADDR: Address =
address!("1613beb3b2c4f22ee086b2b38c1476a3ce7f78e8");
pub const REGISTRY_COORDINATOR_ADDR: Address = address!("c3e53f4d16ae77db1c982e75a937b9f60fe63690");
pub const SERVICE_MANAGER_ADDR: Address = address!("67d269191c92caf3cd7723f116c85e6e9bf55933");
pub const STRATEGY_MANAGER_ADDR: Address = address!("5fc8d32690cc91d4c39d9d3abcbd16989f875707");

pub struct EigenlayerTestEnvironment {
pub http_endpoint: String,
Expand All @@ -36,76 +26,3 @@ pub struct EigenlayerTestEnvironment {
pub eigenlayer_contract_addresses: EigenlayerContractAddresses,
pub pauser_registry_address: Address,
}

pub async fn setup_eigenlayer_test_environment(
http_endpoint: &str,
ws_endpoint: &str,
) -> EigenlayerTestEnvironment {
let provider = get_provider_http(http_endpoint);

let accounts = provider.get_accounts().await.unwrap();

let registry_coordinator_address = address!("c3e53f4d16ae77db1c982e75a937b9f60fe63690");
std::env::set_var(
"REGISTRY_COORDINATOR_ADDR",
registry_coordinator_address.to_string(),
);
let operator_state_retriever_address = address!("1613beb3b2c4f22ee086b2b38c1476a3ce7f78e8");
std::env::set_var(
"OPERATOR_STATE_RETRIEVER_ADDR",
operator_state_retriever_address.to_string(),
);
let delegation_manager_address = address!("dc64a140aa3e981100a9beca4e685f962f0cf6c9");
std::env::set_var(
"DELEGATION_MANAGER_ADDR",
delegation_manager_address.to_string(),
);
let strategy_manager_address = address!("5fc8d32690cc91d4c39d9d3abcbd16989f875707");
std::env::set_var(
"STRATEGY_MANAGER_ADDR",
strategy_manager_address.to_string(),
);
let erc20_mock_address = address!("7969c5ed335650692bc04293b07f5bf2e7a673c0");
std::env::set_var("ERC20_MOCK_ADDR", erc20_mock_address.to_string());

let pauser_registry = PauserRegistry::deploy(provider.clone()).await.unwrap();
let pauser_registry_address = *pauser_registry.address();

let registry_coordinator =
RegistryCoordinator::new(registry_coordinator_address, provider.clone());

let operator_set_params = RegistryCoordinator::OperatorSetParam {
maxOperatorCount: 10,
kickBIPsOfOperatorStake: 100,
kickBIPsOfTotalStake: 1000,
};
let strategy_params = RegistryCoordinator::StrategyParams {
strategy: erc20_mock_address,
multiplier: 1,
};

info!("Creating Quorum");
let _receipt = get_receipt(registry_coordinator.createQuorum(
operator_set_params,
0,
vec![strategy_params],
))
.await
.unwrap();

info!("Setup Eigenlayer test environment");

EigenlayerTestEnvironment {
http_endpoint: http_endpoint.to_string(),
ws_endpoint: ws_endpoint.to_string(),
accounts,
eigenlayer_contract_addresses: EigenlayerContractAddresses {
registry_coordinator_address,
operator_state_retriever_address,
delegation_manager_address,
strategy_manager_address,
avs_directory_address: Default::default(),
},
pauser_registry_address,
}
}
187 changes: 43 additions & 144 deletions blueprint-test-utils/src/incredible_squaring_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,157 +1,55 @@
use futures::StreamExt;
use gadget_sdk::utils::evm::{get_provider_http, get_provider_ws};
use gadget_sdk::{error, info};
use crate::anvil;
use alloy_primitives::{address, Address};
use std::sync::Arc;
use std::time::Duration;
use testcontainers::{ContainerAsync, GenericImage};
use tokio::sync::Mutex;

#[cfg(feature = "eigenlayer_test")]
use crate::eigenlayer_test_env::{IncredibleSquaringTaskManager, RegistryCoordinator};
use crate::helpers::get_receipt;
use alloy_primitives::{Address, Bytes, U256};
use alloy_provider::Provider;
const DEFAULT_ANVIL_STATE_PATH: &str =
"./blueprint-test-utils/anvil/deployed_anvil_states/testnet_state.json";

#[cfg(feature = "eigenlayer_test")]
pub async fn deploy_task_manager(
http_endpoint: &str,
registry_coordinator_address: Address,
pauser_registry_address: Address,
owner_address: Address,
aggregator_address: Address,
task_generator_address: Address,
) -> Address {
let provider = get_provider_http(http_endpoint);
let deploy_call = IncredibleSquaringTaskManager::deploy_builder(
provider.clone(),
registry_coordinator_address,
10u32,
);
info!("Deploying Incredible Squaring Task Manager");
let task_manager_address = match get_receipt(deploy_call).await {
Ok(receipt) => match receipt.contract_address {
Some(address) => address,
None => {
error!("Failed to get contract address from receipt");
panic!("Failed to get contract address from receipt");
}
},
Err(e) => {
error!("Failed to get receipt: {:?}", e);
panic!("Failed to get contract address from receipt");
}
};
info!(
"Deployed Incredible Squaring Task Manager at {}",
task_manager_address
);
std::env::set_var("TASK_MANAGER_ADDRESS", task_manager_address.to_string());

let task_manager = IncredibleSquaringTaskManager::new(task_manager_address, provider.clone());
// Initialize the Incredible Squaring Task Manager
info!("Initializing Incredible Squaring Task Manager");
let init_call = task_manager.initialize(
pauser_registry_address,
owner_address,
aggregator_address,
task_generator_address,
);
let init_receipt = get_receipt(init_call).await.unwrap();
assert!(init_receipt.status());
info!("Initialized Incredible Squaring Task Manager");
/// Starts an Anvil container for testing from the given state file in JSON format.
///
/// # Arguments
/// * `path` - The path to the save-state file.
/// * `include_logs` - If true, testnet output will be printed to the console.
///
/// # Returns
/// `(container, http_endpoint, ws_endpoint)`
/// - `container` as a [`ContainerAsync`] - The Anvil container.
/// - `http_endpoint` as a `String` - The Anvil HTTP endpoint.
/// - `ws_endpoint` as a `String` - The Anvil WS endpoint.
pub async fn start_anvil_testnet(
path: &str,
include_logs: bool,
) -> (ContainerAsync<GenericImage>, String, String) {
let (container, http_endpoint, ws_endpoint) =
anvil::start_anvil_container(path, include_logs).await;
std::env::set_var("EIGENLAYER_HTTP_ENDPOINT", http_endpoint.clone());
std::env::set_var("EIGENLAYER_WS_ENDPOINT", ws_endpoint.clone());

task_manager_address
// Sleep to give the testnet time to spin up
tokio::time::sleep(Duration::from_secs(1)).await;
(container, http_endpoint, ws_endpoint)
}

#[cfg(feature = "eigenlayer_test")]
pub async fn setup_task_spawner(
task_manager_address: Address,
registry_coordinator_address: Address,
task_generator_address: Address,
accounts: Vec<Address>,
http_endpoint: String,
) -> impl std::future::Future<Output = ()> {
let provider = get_provider_http(http_endpoint.as_str());
let task_manager = IncredibleSquaringTaskManager::new(task_manager_address, provider.clone());
let registry_coordinator =
RegistryCoordinator::new(registry_coordinator_address, provider.clone());

let operators = vec![vec![accounts[0]]];
let quorums = Bytes::from(vec![0]);
async move {
loop {
tokio::time::sleep(std::time::Duration::from_millis(10000)).await;

info!("Creating a new task...");
if get_receipt(
task_manager
.createNewTask(U256::from(2), 100u32, quorums.clone())
.from(task_generator_address),
)
.await
.unwrap()
.status()
{
info!("Created a new task...");
}

if get_receipt(
registry_coordinator.updateOperatorsForQuorum(operators.clone(), quorums.clone()),
)
.await
.unwrap()
.status()
{
info!("Updated operators for quorum...");
}

tokio::process::Command::new("sh")
.arg("-c")
.arg(format!(
"cast rpc anvil_mine 1 --rpc-url {} > /dev/null",
http_endpoint
))
.output()
.await
.unwrap();
info!("Mined a block...");
}
}
}

#[cfg(feature = "eigenlayer_test")]
pub async fn setup_task_response_listener(
task_manager_address: Address,
ws_endpoint: String,
successful_responses: Arc<Mutex<usize>>,
) -> impl std::future::Future<Output = ()> {
let task_manager = IncredibleSquaringTaskManager::new(
task_manager_address,
get_provider_ws(ws_endpoint.as_str()).await,
);

async move {
let filter = task_manager.TaskResponded_filter().filter;
let mut event_stream = match task_manager.provider().subscribe_logs(&filter).await {
Ok(stream) => stream.into_stream(),
Err(e) => {
error!("Failed to subscribe to logs: {:?}", e);
return;
}
};
while let Some(event) = event_stream.next().await {
let IncredibleSquaringTaskManager::TaskResponded {
taskResponse: _, ..
} = event
.log_decode::<IncredibleSquaringTaskManager::TaskResponded>()
.unwrap()
.inner
.data;
let mut counter = successful_responses.lock().await;
*counter += 1;
}
}
/// Starts an Anvil container for testing from this library's default state file.
///
/// # Arguments
/// * `include_logs` - If true, testnet output will be printed to the console.
///
/// # Returns
/// `(container, http_endpoint, ws_endpoint)`
/// - `container` as a [`ContainerAsync`] - The Anvil container.
/// - `http_endpoint` as a `String` - The Anvil HTTP endpoint.
/// - `ws_endpoint` as a `String` - The Anvil WS endpoint.
pub async fn start_default_anvil_testnet(
include_logs: bool,
) -> (ContainerAsync<GenericImage>, String, String) {
anvil::start_anvil_container(DEFAULT_ANVIL_STATE_PATH, include_logs).await
}

/// Waits for the given `successful_responses` Mutex to be greater than or equal to `task_response_count`.
pub async fn wait_for_responses(
successful_responses: Arc<Mutex<usize>>,
task_response_count: usize,
Expand All @@ -161,6 +59,7 @@ pub async fn wait_for_responses(
loop {
let count = *successful_responses.lock().await;
if count >= task_response_count {
crate::info!("Successfully received {} task responses", count);
return Ok(());
}
tokio::time::sleep(Duration::from_secs(1)).await;
Expand Down
Loading