diff --git a/crates/arpa-node/build.rs b/crates/arpa-node/build.rs index 3dc91fb..1ffb911 100644 --- a/crates/arpa-node/build.rs +++ b/crates/arpa-node/build.rs @@ -5,7 +5,7 @@ const PROTO_DIR: &str = "proto"; fn main() -> Result<(), Box> { println!("cargo:rerun-if-changed=proto"); - println!("cargo:rerun-if-changed=src/listener/test-contract"); + println!("cargo:rerun-if-changed=test-contract"); let mut prost_build = tonic_prost_build::Config::new(); prost_build.btree_map(["members"]); diff --git a/crates/arpa-node/src/listener/schedule_node_activation.rs b/crates/arpa-node/src/listener/schedule_node_activation.rs index a3abbac..f66ceec 100644 --- a/crates/arpa-node/src/listener/schedule_node_activation.rs +++ b/crates/arpa-node/src/listener/schedule_node_activation.rs @@ -277,7 +277,7 @@ mod tests { ) -> Result<(Address, Address), Box> { println!("Deploying mock contracts..."); - let node_registry = MockNodeRegistry::deploy(client.clone()).await?; + let node_registry = MockNodeRegistry::deploy(client.clone(), Address::ZERO, Address::ZERO, Address::ZERO).await?; let node_registry_address = *node_registry.address(); println!( "Node Registry contract deployed at: {}", diff --git a/crates/arpa-node/src/subscriber/block.rs b/crates/arpa-node/src/subscriber/block.rs index 54ad866..1db8409 100644 --- a/crates/arpa-node/src/subscriber/block.rs +++ b/crates/arpa-node/src/subscriber/block.rs @@ -60,3 +60,236 @@ impl Subscriber for BlockSubscriber { } impl DebuggableSubscriber for BlockSubscriber {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + event::{new_block::NewBlock, types::Topic, Event}, + queue::event_queue::EventQueue, + }; + use arpa_dal::{BlockInfoHandler, BlockInfoFetcher, BlockInfoUpdater}; + use std::sync::Arc; + use tokio::sync::RwLock; + + #[derive(Debug)] + struct MockBlockInfoHandler { + chain_id: u64, + block_height: Arc>, + block_time: usize, + } + + impl MockBlockInfoHandler { + fn new(chain_id: u64, initial_block_height: usize, block_time: usize) -> Self { + Self { + chain_id, + block_height: Arc::new(RwLock::new(initial_block_height)), + block_time, + } + } + } + + impl BlockInfoFetcher for MockBlockInfoHandler { + fn get_chain_id(&self) -> u64 { + self.chain_id.try_into().unwrap() + } + + fn get_block_height(&self) -> usize { + futures::executor::block_on(async { *self.block_height.read().await }) + } + + fn get_block_time(&self) -> usize { + self.block_time + } + } + + impl BlockInfoUpdater for MockBlockInfoHandler { + fn set_block_height(&mut self, block_height: usize) { + if let Ok(mut height) = self.block_height.try_write() { + *height = block_height; + } + } + } + + impl BlockInfoHandler for MockBlockInfoHandler {} + + #[tokio::test] + async fn test_block_subscriber_creation() { + let chain_id = 1u64; + let block_cache = Arc::new(RwLock::new( + Box::new(MockBlockInfoHandler::new(chain_id, 100, 12)) as Box + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + + let subscriber = BlockSubscriber::new(chain_id, block_cache.clone(), eq.clone()); + + assert_eq!(subscriber.chain_id, chain_id); + } + + #[tokio::test] + async fn test_notify_updates_block_height() { + let chain_id = 1u64; + let initial_height = 100; + let mock_handler = MockBlockInfoHandler::new(chain_id, initial_height, 12); + let block_cache = Arc::new(RwLock::new( + Box::new(mock_handler) as Box + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + + let subscriber = BlockSubscriber::new(chain_id, block_cache.clone(), eq.clone()); + + let new_block_height = 150; + let new_block_event = NewBlock::new(chain_id, new_block_height); + + let result = subscriber + .notify(Topic::NewBlock(chain_id), &new_block_event) + .await; + + assert!(result.is_ok()); + + let cache_guard = block_cache.read().await; + let current_height = cache_guard.get_block_height(); + assert_eq!(current_height, new_block_height); + } + + #[tokio::test] + async fn test_notify_with_different_chain_id() { + let chain_id = 1u64; + let different_chain_id = 2; + let initial_height = 100; + let mock_handler = MockBlockInfoHandler::new(chain_id, initial_height, 12); + let block_cache = Arc::new(RwLock::new( + Box::new(mock_handler) as Box + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + + let subscriber = BlockSubscriber::new(chain_id, block_cache.clone(), eq.clone()); + + let new_block_event = NewBlock::new(chain_id, 150); + let result = subscriber + .notify(Topic::NewBlock(different_chain_id), &new_block_event) + .await; + + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_subscribe_registers_with_event_queue() { + let chain_id = 1u64; + let block_cache = Arc::new(RwLock::new( + Box::new(MockBlockInfoHandler::new(chain_id, 100, 12)) as Box + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + + let subscriber = BlockSubscriber::new(chain_id, block_cache.clone(), eq.clone()); + subscriber.subscribe().await; + } + + #[tokio::test] + async fn test_multiple_notify_calls() { + let chain_id = 1u64; + let initial_height = 100; + let mock_handler = MockBlockInfoHandler::new(chain_id, initial_height, 12); + let block_cache = Arc::new(RwLock::new( + Box::new(mock_handler) as Box + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + + let subscriber = BlockSubscriber::new(chain_id, block_cache.clone(), eq.clone()); + + let first_block = NewBlock::new(chain_id, 150); + let result1 = subscriber + .notify(Topic::NewBlock(chain_id), &first_block) + .await; + assert!(result1.is_ok()); + + let second_block = NewBlock::new(chain_id, 200); + let result2 = subscriber + .notify(Topic::NewBlock(chain_id), &second_block) + .await; + assert!(result2.is_ok()); + + let cache_guard = block_cache.read().await; + let final_height = cache_guard.get_block_height(); + assert_eq!(final_height, 200); + } + + #[tokio::test] + async fn test_debuggable_subscriber_trait() { + let chain_id = 1u64; + let block_cache = Arc::new(RwLock::new( + Box::new(MockBlockInfoHandler::new(chain_id, 100, 12)) as Box + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + + let subscriber = BlockSubscriber::new(chain_id, block_cache, eq); + let _: &dyn DebuggableSubscriber = &subscriber; + } + + #[tokio::test] + #[should_panic] + async fn test_notify_with_wrong_event_type() { + let chain_id = 1u64; + let block_cache = Arc::new(RwLock::new( + Box::new(MockBlockInfoHandler::new(chain_id, 100, 12)) as Box + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + + let subscriber = BlockSubscriber::new(chain_id, block_cache, eq); + + #[derive(Debug)] + struct WrongEvent; + + impl Event for WrongEvent { + fn topic(&self) -> Topic { + Topic::NewBlock(1) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } + } + + impl DebuggableEvent for WrongEvent {} + + let wrong_event = WrongEvent; + let _result = subscriber + .notify(Topic::NewBlock(chain_id), &wrong_event) + .await; + } + + mod integration_tests { + use super::*; + + #[tokio::test] + async fn test_block_subscriber_integration() { + let chain_id = 1u64; + let mock_handler = MockBlockInfoHandler::new(chain_id, 0, 12); + + let block_cache = Arc::new(RwLock::new( + Box::new(mock_handler) as Box + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + + let subscriber_for_subscribe = BlockSubscriber::new(chain_id, block_cache.clone(), eq.clone()); + subscriber_for_subscribe.subscribe().await; + let subscriber = BlockSubscriber::new(chain_id, block_cache.clone(), eq.clone()); + + let heights = vec![10, 20, 30, 40, 50]; + + for height in heights.iter() { + let new_block = NewBlock::new(chain_id, *height); + + let result = subscriber + .notify(Topic::NewBlock(chain_id), &new_block) + .await; + + assert!(result.is_ok()); + } + + let cache_guard = block_cache.read().await; + let final_height = cache_guard.get_block_height(); + assert_eq!(final_height, 50); + } + } +} \ No newline at end of file diff --git a/crates/arpa-node/src/subscriber/in_grouping.rs b/crates/arpa-node/src/subscriber/in_grouping.rs index 2253cda..5baabe3 100644 --- a/crates/arpa-node/src/subscriber/in_grouping.rs +++ b/crates/arpa-node/src/subscriber/in_grouping.rs @@ -359,8 +359,6 @@ impl Subscriber for InGroup let cache_epoch = group_cache.clone().read().await.get_epoch().unwrap_or(0); cache_index != task_group_index || cache_epoch != task_epoch - //NodeError::GroupIndexObsolete(cache_index) - //NodeError::GroupEpochObsolete(cache_epoch) } }, 2000, @@ -382,3 +380,363 @@ impl DebuggableSubscriber for InGroupingSubscriber { } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + event::{run_dkg::RunDKG, types::Topic}, + queue::event_queue::EventQueue, + scheduler::dynamic::SimpleDynamicTaskScheduler, + }; + use alloy::node_bindings::{Anvil, AnvilInstance}; + use alloy::primitives::{Address, U256}; + use alloy::providers::WsConnect; + use alloy::signers::local::PrivateKeySigner; + use alloy::sol; + use arpa_core::{build_client, Config, DKGStatus, DKGTask, GeneralMainChainIdentity, ProviderClientWithSigner}; + use arpa_dal::{ + cache::{InMemoryGroupInfoCache, InMemoryNodeInfoCache}, + GroupInfoHandler, NodeInfoHandler, + }; + use rand::thread_rng; + use std::sync::Arc; + use threshold_bls::{group::Element, schemes::bn254::G2Curve}; + use tokio::sync::RwLock; + + sol! { + #[sol(rpc)] + MockController, + "test-contract/MockController.json" + } + + sol! { + #[sol(rpc)] + MockCoordinator, + "test-contract/MockCoordinator.json" + } + + struct TestEnvironment { + _anvil: AnvilInstance, + client: ProviderClientWithSigner, + wallet: PrivateKeySigner, + chain_id: u64, + ws_endpoint: String, + } + + impl TestEnvironment { + async fn new() -> Self { + let anvil = Anvil::new().spawn(); + let ws_endpoint = anvil.ws_endpoint(); + let ws_connect = WsConnect::new(&ws_endpoint); + let wallet: PrivateKeySigner = anvil.keys()[0].clone().into(); + let chain_id = anvil.chain_id(); + let client = build_client(wallet.clone(), chain_id, ws_connect) + .await + .unwrap(); + + TestEnvironment { + _anvil: anvil, + client, + wallet, + chain_id, + ws_endpoint, + } + } + + async fn deploy_controller(&self) -> (Address, MockController::MockControllerInstance) { + let contract = MockController::deploy(self.client.clone(), Address::ZERO) + .await + .unwrap(); + + let _receipt = contract + .setShouldSucceed(true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + (*contract.address(), contract) + } + + async fn deploy_coordinator(&self, threshold: u64) -> (Address, MockCoordinator::MockCoordinatorInstance) { + let contract = MockCoordinator::deploy(self.client.clone(), U256::from(threshold)) + .await + .unwrap(); + + (*contract.address(), contract) + } + + async fn create_chain_identity( + &self, + controller_address: Address, + ) -> Arc>> { + let config = Config::default(); + let ws_connect = WsConnect::new(&self.ws_endpoint); + let general_chain_identity = GeneralMainChainIdentity::new( + self.chain_id.try_into().unwrap(), + self.wallet.clone(), + ws_connect, + self.client.clone(), + self.ws_endpoint.clone(), + controller_address, + Address::ZERO, + Address::ZERO, + config.get_time_limits().contract_transaction_retry_descriptor, + config.get_time_limits().contract_view_retry_descriptor, + None, + ); + Arc::new(RwLock::new(Box::new(general_chain_identity))) + } + } + + async fn setup_node_cache(id_address: Address) -> NodeResult>>>> { + let node_cache: Arc>>> = Arc::new(RwLock::new( + Box::new(InMemoryNodeInfoCache::::new(id_address)), + )); + { + let mut node_cache_write = node_cache.write().await; + node_cache_write.set_node_rpc_endpoint("http://localhost:8545".to_string()).await?; + let private_key = ::Scalar::rand(&mut thread_rng()); + let mut public_key = ::Point::one(); + public_key.mul(&private_key); + node_cache_write.set_dkg_key_pair(private_key, public_key).await?; + } + Ok(node_cache) + } + + async fn setup_group_cache( + id_address: Address, + chain_id: usize, + group_index: usize, + epoch: usize, + size: usize, + threshold: usize, + member_addresses: Vec
, + dkg_status: DKGStatus, + ) -> NodeResult>>>> { + let group_cache: Arc>>> = Arc::new(RwLock::new( + Box::new(InMemoryGroupInfoCache::::new(id_address)), + )); + { + let mut group_cache_write = group_cache.write().await; + let dkg_task = DKGTask { + group_index, + epoch, + size, + threshold, + assignment_block_height: 100, + members: member_addresses.clone(), + coordinator_address: Address::ZERO, + }; + group_cache_write.save_task_info(chain_id, dkg_task).await?; + group_cache_write.update_dkg_status(group_index, epoch, dkg_status).await?; + } + Ok(group_cache) + } + + fn create_schedulers() -> (Arc>, Arc>) { + ( + Arc::new(RwLock::new(EventQueue::new())), + Arc::new(RwLock::new(SimpleDynamicTaskScheduler::new())) + ) + } + + #[tokio::test] + async fn test_in_grouping_subscriber_creation() { + let env = TestEnvironment::new().await; + let (controller_address, _) = env.deploy_controller().await; + let chain_identity = env.create_chain_identity(controller_address).await; + let id_address = Address::ZERO; + let node_cache = setup_node_cache(id_address).await.unwrap(); + let group_cache = setup_group_cache( + id_address, 1, 1, 1, 3, 2, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::InPhase, + ).await.unwrap(); + let (eq, ts) = create_schedulers(); + let subscriber = InGroupingSubscriber::new(chain_identity, node_cache, group_cache, eq, ts, 1000); + assert_eq!(subscriber.dkg_wait_for_phase_interval_millis, 1000); + } + + #[tokio::test] + async fn test_dkg_handler_creation() { + let env = TestEnvironment::new().await; + let (controller_address, _) = env.deploy_controller().await; + let (coordinator_address, _) = env.deploy_coordinator(2).await; + let chain_identity = env.create_chain_identity(controller_address).await; + let id_address = Address::ZERO; + let node_cache = setup_node_cache(id_address).await.unwrap(); + let group_cache = setup_group_cache( + id_address, 1, 1, 1, 3, 2, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::InPhase, + ).await.unwrap(); + let handler = AllInOneDKGHandler::new(|| thread_rng(), chain_identity, node_cache, group_cache.clone(), 1000); + let task = DKGTask { + group_index: 1, + epoch: 1, + size: 3, + threshold: 2, + members: vec![id_address, Address::ZERO, Address::ZERO], + assignment_block_height: 100, + coordinator_address, + }; + assert_eq!(task.group_index, 1); + assert_eq!(task.epoch, 1); + assert_eq!(task.size, 3); + assert_eq!(task.threshold, 2); + assert_eq!(handler.dkg_wait_for_phase_interval_millis, 1000); + } + + #[tokio::test] + async fn test_subscriber_notify() { + let env = TestEnvironment::new().await; + let (controller_address, _) = env.deploy_controller().await; + let (coordinator_address, _) = env.deploy_coordinator(2).await; + let chain_identity = env.create_chain_identity(controller_address).await; + let id_address = Address::ZERO; + let node_cache = setup_node_cache(id_address).await.unwrap(); + let group_cache = setup_group_cache( + id_address, 1, 1, 1, 3, 2, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::InPhase, + ).await.unwrap(); + let (eq, ts) = create_schedulers(); + let subscriber = InGroupingSubscriber::new(chain_identity, node_cache, group_cache, eq, ts, 1000); + let task = DKGTask { + group_index: 1, + epoch: 1, + size: 3, + threshold: 2, + members: vec![id_address, Address::ZERO, Address::ZERO], + assignment_block_height: 100, + coordinator_address, + }; + let run_dkg_event = RunDKG { dkg_task: task }; + let result = subscriber.notify(Topic::RunDKG, &run_dkg_event).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_subscriber_subscribe() { + let env = TestEnvironment::new().await; + let controller_address = Address::ZERO; + let chain_identity = env.create_chain_identity(controller_address).await; + let id_address = Address::ZERO; + let node_cache = setup_node_cache(id_address).await.unwrap(); + let group_cache = setup_group_cache( + id_address, 1, 1, 1, 3, 2, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::InPhase, + ).await.unwrap(); + let (eq, ts) = create_schedulers(); + let subscriber = InGroupingSubscriber::new(chain_identity, node_cache, group_cache, eq.clone(), ts, 1000); + subscriber.subscribe().await; + } + + #[tokio::test] + async fn test_group_cache_operations() { + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, 1, 2, 2, 5, 3, + vec![id_address, Address::ZERO, Address::ZERO, Address::ZERO, Address::ZERO], + DKGStatus::InPhase, + ).await.unwrap(); + { + let group_cache_read = group_cache.read().await; + assert_eq!(group_cache_read.get_index().unwrap(), 2); + assert_eq!(group_cache_read.get_epoch().unwrap(), 2); + assert_eq!(group_cache_read.get_size().unwrap(), 5); + assert_eq!(group_cache_read.get_threshold().unwrap(), 3); + assert_eq!(group_cache_read.get_self_id_address().unwrap(), id_address); + assert_eq!(group_cache_read.get_dkg_status().unwrap(), DKGStatus::InPhase); + } + { + let mut group_cache_write = group_cache.write().await; + let result = group_cache_write.update_dkg_status(2, 2, DKGStatus::CommitSuccess).await; + assert!(result.is_ok()); + } + { + let group_cache_read = group_cache.read().await; + assert_eq!(group_cache_read.get_dkg_status().unwrap(), DKGStatus::CommitSuccess); + } + } + + #[tokio::test] + async fn test_node_cache_operations() { + let id_address = Address::ZERO; + let node_cache = setup_node_cache(id_address).await.unwrap(); + { + let node_cache_read = node_cache.read().await; + assert_eq!(node_cache_read.get_id_address().unwrap(), id_address); + assert_eq!(node_cache_read.get_node_rpc_endpoint().unwrap(), "http://localhost:8545"); + assert!(node_cache_read.get_dkg_private_key().is_ok()); + assert!(node_cache_read.get_dkg_public_key().is_ok()); + } + { + let mut node_cache_write = node_cache.write().await; + let new_endpoint = "http://localhost:9545".to_string(); + let result = node_cache_write.set_node_rpc_endpoint(new_endpoint.clone()).await; + assert!(result.is_ok()); + } + { + let node_cache_read = node_cache.read().await; + assert_eq!(node_cache_read.get_node_rpc_endpoint().unwrap(), "http://localhost:9545"); + } + } + + #[tokio::test] + async fn test_dkg_task_with_different_statuses() { + let id_address = Address::ZERO; + let statuses = vec![DKGStatus::None, DKGStatus::InPhase, DKGStatus::WaitForPostProcess, DKGStatus::CommitSuccess]; + for (i, status) in statuses.iter().enumerate() { + let group_cache = setup_group_cache( + id_address, 1, i + 1, 1, 3, 2, + vec![id_address, Address::ZERO, Address::ZERO], + *status, + ).await.unwrap(); + let group_cache_read = group_cache.read().await; + assert_eq!(group_cache_read.get_index().unwrap(), i + 1); + assert_eq!(group_cache_read.get_dkg_status().unwrap(), *status); + } + } + + #[tokio::test] + async fn test_multiple_group_members() { + let id_address = Address::ZERO; + let member_addresses = vec![ + id_address, + Address::from([1u8; 20]), + Address::from([2u8; 20]), + Address::from([3u8; 20]), + Address::from([4u8; 20]) + ]; + let group_cache = setup_group_cache( + id_address, 1, 1, 1, 5, 3, + member_addresses.clone(), + DKGStatus::InPhase, + ).await.unwrap(); + let group_cache_read = group_cache.read().await; + assert_eq!(group_cache_read.get_size().unwrap(), 5); + assert_eq!(group_cache_read.get_threshold().unwrap(), 3); + let members = group_cache_read.get_members().unwrap(); + assert_eq!(members.len(), 5); + assert!(members.contains_key(&id_address)); + } + + #[tokio::test] + async fn test_contract_integration() { + let env = TestEnvironment::new().await; + let (controller_address, _) = env.deploy_controller().await; + let (coordinator_address, _) = env.deploy_coordinator(2).await; + let chain_identity = env.create_chain_identity(controller_address).await; + assert_ne!(controller_address, Address::ZERO); + assert_ne!(coordinator_address, Address::ZERO); + let chain_identity_read = chain_identity.read().await; + chain_identity_read.build_controller_client(); + chain_identity_read.build_coordinator_client(coordinator_address); + } +} \ No newline at end of file diff --git a/crates/arpa-node/src/subscriber/mod.rs b/crates/arpa-node/src/subscriber/mod.rs index 7c65a30..6624dd0 100644 --- a/crates/arpa-node/src/subscriber/mod.rs +++ b/crates/arpa-node/src/subscriber/mod.rs @@ -23,3 +23,253 @@ pub trait Subscriber { async fn subscribe(self); } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + error::NodeResult, + event::{types::Topic, Event}, + }; + use async_trait::async_trait; + use std::any::Any; + + #[derive(Debug, Clone)] + struct MockEvent { + topic: Topic, + data: String, + } + + impl MockEvent { + fn new(topic: Topic, data: String) -> Self { + Self { topic, data } + } + } + + impl Event for MockEvent { + fn topic(&self) -> Topic { + self.topic.clone() + } + + fn as_any(&self) -> &dyn Any { + self + } + } + + impl DebuggableEvent for MockEvent {} + + #[derive(Debug)] + struct MockSubscriber { + notify_count: std::sync::Arc, + subscribe_called: std::sync::Arc, + last_topic: std::sync::Arc>>, + } + + impl MockSubscriber { + fn new() -> Self { + Self { + notify_count: std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0)), + subscribe_called: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), + last_topic: std::sync::Arc::new(std::sync::Mutex::new(None)), + } + } + + fn get_notify_count(&self) -> usize { + self.notify_count.load(std::sync::atomic::Ordering::SeqCst) + } + + fn is_subscribe_called(&self) -> bool { + self.subscribe_called.load(std::sync::atomic::Ordering::SeqCst) + } + + fn get_last_topic(&self) -> Option { + self.last_topic.lock().unwrap().clone() + } + } + + #[async_trait] + impl Subscriber for MockSubscriber { + async fn notify(&self, topic: Topic, _payload: &dyn DebuggableEvent) -> NodeResult<()> { + self.notify_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + *self.last_topic.lock().unwrap() = Some(topic); + Ok(()) + } + + async fn subscribe(self) { + self.subscribe_called.store(true, std::sync::atomic::Ordering::SeqCst); + } + } + + impl DebuggableSubscriber for MockSubscriber {} + + #[derive(Debug)] + struct ErrorSubscriber { + should_error: bool, + } + + impl ErrorSubscriber { + fn new(should_error: bool) -> Self { + Self { should_error } + } + } + + #[async_trait] + impl Subscriber for ErrorSubscriber { + async fn notify(&self, _topic: Topic, _payload: &dyn DebuggableEvent) -> NodeResult<()> { + if self.should_error { + Err(crate::error::NodeError::InvalidTaskType.into()) + } else { + Ok(()) + } + } + + async fn subscribe(self) {} + } + + impl DebuggableSubscriber for ErrorSubscriber {} + + #[tokio::test] + async fn test_subscriber_notify_success() { + let subscriber = MockSubscriber::new(); + let event = MockEvent::new(Topic::NewBlock(1), "test_data".to_string()); + let result = subscriber.notify(Topic::NewBlock(1), &event).await; + assert!(result.is_ok()); + assert_eq!(subscriber.get_notify_count(), 1); + assert_eq!(subscriber.get_last_topic(), Some(Topic::NewBlock(1))); + } + + #[tokio::test] + async fn test_subscriber_notify_multiple_times() { + let subscriber = MockSubscriber::new(); + let event1 = MockEvent::new(Topic::NewBlock(1), "test_data1".to_string()); + let event2 = MockEvent::new(Topic::NewBlock(2), "test_data2".to_string()); + let result1 = subscriber.notify(Topic::NewBlock(1), &event1).await; + let result2 = subscriber.notify(Topic::NewBlock(2), &event2).await; + assert!(result1.is_ok()); + assert!(result2.is_ok()); + assert_eq!(subscriber.get_notify_count(), 2); + assert_eq!(subscriber.get_last_topic(), Some(Topic::NewBlock(2))); + } + + #[tokio::test] + async fn test_subscriber_notify_error() { + let subscriber = ErrorSubscriber::new(true); + let event = MockEvent::new(Topic::NewBlock(1), "test_data".to_string()); + let result = subscriber.notify(Topic::NewBlock(1), &event).await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_subscriber_subscribe() { + let subscriber = MockSubscriber::new(); + assert!(!subscriber.is_subscribe_called()); + subscriber.subscribe().await; + } + + #[tokio::test] + async fn test_debuggable_event_trait() { + let event = MockEvent::new(Topic::NewBlock(1), "test_data".to_string()); + let _: &dyn Event = &event; + let _: &dyn std::fmt::Debug = &event; + let _: &dyn DebuggableEvent = &event; + let debug_str = format!("{:?}", event); + assert!(debug_str.contains("MockEvent")); + } + + #[tokio::test] + async fn test_debuggable_subscriber_trait() { + let subscriber = MockSubscriber::new(); + let _: &dyn Subscriber = &subscriber; + let _: &dyn std::fmt::Debug = &subscriber; + let _: &dyn DebuggableSubscriber = &subscriber; + let debug_str = format!("{:?}", subscriber); + assert!(debug_str.contains("MockSubscriber")); + } + + #[tokio::test] + async fn test_event_topic_consistency() { + let topic = Topic::NewBlock(1); + let event = MockEvent::new(topic.clone(), "test_data".to_string()); + assert_eq!(event.topic(), topic); + } + + #[tokio::test] + async fn test_event_as_any() { + let event = MockEvent::new(Topic::NewBlock(1), "test_data".to_string()); + let any_ref = event.as_any(); + let downcast_result = any_ref.downcast_ref::(); + assert!(downcast_result.is_some()); + let downcast_event = downcast_result.unwrap(); + assert_eq!(downcast_event.data, "test_data"); + } + + #[tokio::test] + async fn test_different_topics() { + let subscriber = MockSubscriber::new(); + let topics = vec![Topic::NewBlock(1), Topic::NewBlock(2)]; + for (i, topic) in topics.iter().enumerate() { + let event = MockEvent::new(topic.clone(), format!("data_{}", i)); + let result = subscriber.notify(topic.clone(), &event).await; + assert!(result.is_ok()); + } + assert_eq!(subscriber.get_notify_count(), topics.len()); + } + + #[tokio::test] + async fn test_trait_object_usage() { + let subscriber: Box = Box::new(MockSubscriber::new()); + let event: Box = Box::new(MockEvent::new(Topic::NewBlock(1), "boxed_data".to_string())); + let result = subscriber.notify(Topic::NewBlock(1), event.as_ref()).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_send_sync_requirements() { + let subscriber = MockSubscriber::new(); + let event = MockEvent::new(Topic::NewBlock(1), "test_data".to_string()); + let handle = tokio::spawn(async move { + subscriber.notify(Topic::NewBlock(1), &event).await + }); + let result = handle.await.unwrap(); + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_many_notifications() { + let subscriber = MockSubscriber::new(); + let count = 1000; + for i in 0..count { + let event = MockEvent::new(Topic::NewBlock(1), format!("data_{}", i)); + let result = subscriber.notify(Topic::NewBlock(1), &event).await; + assert!(result.is_ok()); + } + assert_eq!(subscriber.get_notify_count(), count); + } + + #[cfg(test)] + mod integration_tests { + use super::*; + + #[tokio::test] + async fn test_multiple_subscribers_with_same_event() { + let subscriber1 = tests::MockSubscriber::new(); + let subscriber2 = tests::MockSubscriber::new(); + let event = tests::MockEvent::new(Topic::NewBlock(1), "shared_data".to_string()); + let result1 = subscriber1.notify(Topic::NewBlock(1), &event).await; + let result2 = subscriber2.notify(Topic::NewBlock(1), &event).await; + assert!(result1.is_ok()); + assert!(result2.is_ok()); + assert_eq!(subscriber1.get_notify_count(), 1); + assert_eq!(subscriber2.get_notify_count(), 1); + } + + #[tokio::test] + async fn test_subscriber_lifecycle() { + let subscriber = tests::MockSubscriber::new(); + let event = tests::MockEvent::new(Topic::NewBlock(1), "test_data".to_string()); + let notify_result = subscriber.notify(Topic::NewBlock(1), &event).await; + assert!(notify_result.is_ok()); + subscriber.subscribe().await; + } + } +} \ No newline at end of file diff --git a/crates/arpa-node/src/subscriber/post_grouping.rs b/crates/arpa-node/src/subscriber/post_grouping.rs index 9de9769..a82e4fe 100644 --- a/crates/arpa-node/src/subscriber/post_grouping.rs +++ b/crates/arpa-node/src/subscriber/post_grouping.rs @@ -93,7 +93,6 @@ impl DKGPostProcessHandler let chain_id = self.chain_identity.read().await.get_chain_id(); - // sync up the members in the group if !self .group_cache .write() @@ -226,3 +225,747 @@ impl DebuggableSubscriber for PostGroupingSubscriber { } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + event::{dkg_post_process::DKGPostProcess, types::Topic}, + queue::event_queue::EventQueue, + scheduler::dynamic::SimpleDynamicTaskScheduler, + }; + use alloy::node_bindings::{Anvil, AnvilInstance}; + use alloy::primitives::{Address, U256}; + use alloy::providers::WsConnect; + use alloy::signers::local::PrivateKeySigner; + use alloy::sol; + use arpa_core::{ + build_client, Config, DKGStatus, GeneralMainChainIdentity, Group, Member, + ProviderClientWithSigner, PLACEHOLDER_ADDRESS + }; + use arpa_dal::{cache::InMemoryGroupInfoCache, GroupInfoHandler}; + use std::{collections::BTreeMap, sync::Arc}; + use threshold_bls::schemes::bn254::G2Curve; + use tokio::sync::RwLock; + + const DEFAULT_GROUP_INDEX: usize = 1; + const DEFAULT_EPOCH: usize = 1; + const DEFAULT_GROUP_SIZE: usize = 3; + const DEFAULT_THRESHOLD: usize = 2; + const DEFAULT_BLOCK_HEIGHT: usize = 100; + const DEFAULT_RPC_ENDPOINT: &str = "http://localhost:8545"; + const DEFAULT_SUPPORTED_CHAINS: [u64; 2] = [2, 3]; + + sol! { + #[sol(ignore_unlinked)] + #[sol(rpc)] + MockController, + "test-contract/MockController.json" + } + + sol! { + #[sol(ignore_unlinked)] + #[sol(rpc)] + MockControllerRelayer, + "test-contract/MockControllerRelayer.json" + } + + struct TestEnvironment { + _anvil: AnvilInstance, + client: ProviderClientWithSigner, + wallet: PrivateKeySigner, + chain_id: u64, + ws_endpoint: String, + } + + impl TestEnvironment { + async fn new() -> Self { + let anvil = Anvil::new().spawn(); + let ws_endpoint = anvil.ws_endpoint(); + let ws_connect = WsConnect::new(&ws_endpoint); + let wallet: PrivateKeySigner = anvil.keys()[0].clone().into(); + let chain_id = anvil.chain_id(); + let client = build_client(wallet.clone(), chain_id, ws_connect) + .await + .unwrap(); + + TestEnvironment { + _anvil: anvil, + client, + wallet, + chain_id, + ws_endpoint, + } + } + + async fn deploy_mock_controller(&self) -> (Address, MockController::MockControllerInstance) { + let contract = MockController::deploy(self.client.clone(), Address::ZERO) + .await + .unwrap(); + (*contract.address(), contract) + } + + async fn deploy_mock_controller_relayer(&self) -> (Address, MockControllerRelayer::MockControllerRelayerInstance) { + let contract = MockControllerRelayer::deploy(self.client.clone()) + .await + .unwrap(); + (*contract.address(), contract) + } + + async fn create_chain_identity( + &self, + controller_address: Address, + relayer_address: Address, + ) -> Arc>> { + let config = Config::default(); + let ws_connect = WsConnect::new(&self.ws_endpoint); + let general_chain_identity = GeneralMainChainIdentity::new( + self.chain_id.try_into().unwrap(), + self.wallet.clone(), + ws_connect, + self.client.clone(), + self.ws_endpoint.clone(), + controller_address, + relayer_address, + Address::ZERO, + config + .get_time_limits() + .contract_transaction_retry_descriptor, + config.get_time_limits().contract_view_retry_descriptor, + None, + ); + Arc::new(RwLock::new(Box::new(general_chain_identity))) + } + } + + async fn setup_group_cache( + id_address: Address, + group_index: usize, + epoch: usize, + size: usize, + threshold: usize, + member_addresses: Vec
, + dkg_status: DKGStatus, + state: bool, + ) -> NodeResult>>>> { + let group_cache: Arc>>> = Arc::new(RwLock::new( + Box::new(InMemoryGroupInfoCache::::new(id_address)), + )); + + { + let mut group_cache_write = group_cache.write().await; + let dkg_task = arpa_core::DKGTask { + group_index, + epoch, + size, + threshold, + assignment_block_height: DEFAULT_BLOCK_HEIGHT, + members: member_addresses.clone(), + coordinator_address: Address::ZERO, + }; + + group_cache_write.save_task_info(0, dkg_task).await?; + group_cache_write + .update_dkg_status(group_index, epoch, dkg_status) + .await?; + + let mut group = Group:: { + index: group_index, + epoch, + size, + threshold, + state, + public_key: None, + members: BTreeMap::new(), + committers: vec![], + c: std::marker::PhantomData, + }; + + for (i, addr) in member_addresses.iter().enumerate() { + group.members.insert( + *addr, + Member { + index: i, + dkg_index: Some(i), + id_address: *addr, + rpc_endpoint: Some(DEFAULT_RPC_ENDPOINT.to_string()), + partial_public_key: None, + }, + ); + } + + group_cache_write + .sync_up_members(group_index, epoch, group.members) + .await?; + } + + Ok(group_cache) + } + + fn create_schedulers() -> ( + Arc>, + Arc>, + ) { + ( + Arc::new(RwLock::new(EventQueue::new())), + Arc::new(RwLock::new(SimpleDynamicTaskScheduler::new())), + ) + } + + fn create_test_group( + group_index: usize, + epoch: usize, + state: bool, + member_addresses: Vec
, + ) -> Group { + let mut members = BTreeMap::new(); + for (i, addr) in member_addresses.iter().enumerate() { + members.insert( + *addr, + Member { + index: i, + dkg_index: Some(i), + id_address: *addr, + rpc_endpoint: Some(DEFAULT_RPC_ENDPOINT.to_string()), + partial_public_key: None, + }, + ); + } + + Group { + index: group_index, + epoch, + size: member_addresses.len(), + threshold: (member_addresses.len() * 2 / 3) + 1, + state, + public_key: None, + members, + committers: member_addresses, + c: std::marker::PhantomData, + } + } + + async fn create_test_setup() -> ( + Arc>>, + Arc>>>, + Address, + ) { + let env = TestEnvironment::new().await; + let (controller_address, _controller) = env.deploy_mock_controller().await; + let (relayer_address, _relayer) = env.deploy_mock_controller_relayer().await; + + let chain_identity = env + .create_chain_identity(controller_address, relayer_address) + .await; + + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::WaitForPostProcess, + true, + ) + .await + .unwrap(); + + (chain_identity, group_cache, id_address) + } + + #[tokio::test] + async fn test_post_grouping_subscriber_creation() { + let (chain_identity, group_cache, _id_address) = create_test_setup().await; + let (eq, ts) = create_schedulers(); + let supported_chains = DEFAULT_SUPPORTED_CHAINS.to_vec(); + + let subscriber = PostGroupingSubscriber::new( + chain_identity, + supported_chains.clone(), + group_cache, + eq, + ts, + ); + + assert_eq!(subscriber.supported_relayed_chains, supported_chains); + } + + #[tokio::test] + async fn test_dkg_post_process_handler_creation() { + let (chain_identity, group_cache, _id_address) = create_test_setup().await; + let supported_chains = DEFAULT_SUPPORTED_CHAINS.to_vec(); + + let handler = GeneralDKGPostProcessHandler { + chain_identity, + supported_relayed_chains: supported_chains.clone(), + group_cache, + c: PhantomData, + }; + + assert_eq!(handler.supported_relayed_chains, supported_chains); + } + + #[tokio::test] + async fn test_post_process_handler_with_no_coordinator() { + let env = TestEnvironment::new().await; + let (controller_address, controller) = env.deploy_mock_controller().await; + let (relayer_address, _relayer) = env.deploy_mock_controller_relayer().await; + + controller + .setCoordinator(U256::from(DEFAULT_GROUP_INDEX), PLACEHOLDER_ADDRESS) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let chain_identity = env + .create_chain_identity(controller_address, relayer_address) + .await; + + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::WaitForPostProcess, + true, + ) + .await + .unwrap(); + + let handler = GeneralDKGPostProcessHandler { + chain_identity, + supported_relayed_chains: DEFAULT_SUPPORTED_CHAINS.to_vec(), + group_cache, + c: PhantomData, + }; + + let group = create_test_group( + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + true, + vec![id_address, Address::ZERO, Address::ZERO], + ); + let result = handler + .handle(DEFAULT_GROUP_INDEX, DEFAULT_EPOCH, group) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_post_process_handler_with_coordinator_success() { + let env = TestEnvironment::new().await; + let (controller_address, controller) = env.deploy_mock_controller().await; + let (relayer_address, relayer) = env.deploy_mock_controller_relayer().await; + + let coordinator_addr = Address::ZERO; + controller + .setCoordinator(U256::from(DEFAULT_GROUP_INDEX), coordinator_addr) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + controller + .setShouldSucceed(true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + relayer + .setShouldSucceed(true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let chain_identity = env + .create_chain_identity(controller_address, relayer_address) + .await; + + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::WaitForPostProcess, + true, + ) + .await + .unwrap(); + + let handler = GeneralDKGPostProcessHandler { + chain_identity, + supported_relayed_chains: DEFAULT_SUPPORTED_CHAINS.to_vec(), + group_cache, + c: PhantomData, + }; + + let group = create_test_group( + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + true, + vec![id_address, Address::ZERO, Address::ZERO], + ); + let result = handler + .handle(DEFAULT_GROUP_INDEX, DEFAULT_EPOCH, group) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_post_process_handler_with_inactive_group() { + let env = TestEnvironment::new().await; + let (controller_address, controller) = env.deploy_mock_controller().await; + let (relayer_address, relayer) = env.deploy_mock_controller_relayer().await; + + let coordinator_addr = Address::ZERO; + controller + .setCoordinator(U256::from(DEFAULT_GROUP_INDEX), coordinator_addr) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + controller + .setShouldSucceed(true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + relayer + .setShouldSucceed(true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let chain_identity = env + .create_chain_identity(controller_address, relayer_address) + .await; + + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::WaitForPostProcess, + false, + ) + .await + .unwrap(); + + let handler = GeneralDKGPostProcessHandler { + chain_identity, + supported_relayed_chains: DEFAULT_SUPPORTED_CHAINS.to_vec(), + group_cache, + c: PhantomData, + }; + + let group = create_test_group( + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + false, + vec![id_address, Address::ZERO, Address::ZERO], + ); + let result = handler + .handle(DEFAULT_GROUP_INDEX, DEFAULT_EPOCH, group) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_post_process_handler_with_contract_failure() { + let env = TestEnvironment::new().await; + let (controller_address, controller) = env.deploy_mock_controller().await; + let (relayer_address, relayer) = env.deploy_mock_controller_relayer().await; + + let coordinator_addr = Address::ZERO; + controller + .setCoordinator(U256::from(DEFAULT_GROUP_INDEX), coordinator_addr) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + controller + .setShouldSucceed(false) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + controller + .setFailureMessage("Controller failure".to_string()) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + relayer + .setShouldSucceed(false) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + relayer + .setFailureMessage("Relayer failure".to_string()) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let chain_identity = env + .create_chain_identity(controller_address, relayer_address) + .await; + + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::WaitForPostProcess, + true, + ) + .await + .unwrap(); + + let handler = GeneralDKGPostProcessHandler { + chain_identity, + supported_relayed_chains: DEFAULT_SUPPORTED_CHAINS.to_vec(), + group_cache, + c: PhantomData, + }; + + let group = create_test_group( + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + true, + vec![id_address, Address::ZERO, Address::ZERO], + ); + let result = handler + .handle(DEFAULT_GROUP_INDEX, DEFAULT_EPOCH, group) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_subscriber_notify() { + let (chain_identity, group_cache, id_address) = create_test_setup().await; + let (eq, ts) = create_schedulers(); + + let subscriber = PostGroupingSubscriber::new( + chain_identity, + DEFAULT_SUPPORTED_CHAINS.to_vec(), + group_cache, + eq, + ts, + ); + + let group = create_test_group( + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + true, + vec![id_address, Address::ZERO, Address::ZERO], + ); + let post_process_event = DKGPostProcess { + group_index: DEFAULT_GROUP_INDEX, + group_epoch: DEFAULT_EPOCH, + group, + }; + + let result = subscriber + .notify(Topic::DKGPostProcess, &post_process_event) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_subscriber_subscribe() { + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::WaitForPostProcess, + true, + ) + .await + .unwrap(); + + let (eq, ts) = create_schedulers(); + let env = TestEnvironment::new().await; + let chain_identity = env + .create_chain_identity(Address::ZERO, Address::ZERO) + .await; + + let subscriber = PostGroupingSubscriber::new( + chain_identity, + DEFAULT_SUPPORTED_CHAINS.to_vec(), + group_cache, + eq.clone(), + ts, + ); + + subscriber.subscribe().await; + } + + #[tokio::test] + async fn test_multiple_relayed_chains() { + let env = TestEnvironment::new().await; + let (controller_address, controller) = env.deploy_mock_controller().await; + let (relayer_address, relayer) = env.deploy_mock_controller_relayer().await; + + let coordinator_addr = Address::ZERO; + controller + .setCoordinator(U256::from(DEFAULT_GROUP_INDEX), coordinator_addr) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + controller + .setShouldSucceed(true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + relayer + .setShouldSucceed(true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let chain_identity = env + .create_chain_identity(controller_address, relayer_address) + .await; + + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::WaitForPostProcess, + true, + ) + .await + .unwrap(); + + let multiple_chains = vec![2, 3, 4, 5, 6]; + let handler = GeneralDKGPostProcessHandler { + chain_identity, + supported_relayed_chains: multiple_chains.clone(), + group_cache, + c: PhantomData, + }; + + let group = create_test_group( + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + true, + vec![id_address, Address::ZERO, Address::ZERO], + ); + let result = handler + .handle(DEFAULT_GROUP_INDEX, DEFAULT_EPOCH, group) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_dkg_status_update_failure() { + let env = TestEnvironment::new().await; + let (controller_address, _controller) = env.deploy_mock_controller().await; + let (relayer_address, _relayer) = env.deploy_mock_controller_relayer().await; + + let chain_identity = env + .create_chain_identity(controller_address, relayer_address) + .await; + + let id_address = Address::ZERO; + let group_cache = setup_group_cache( + id_address, + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + DKGStatus::None, + true, + ) + .await + .unwrap(); + + let handler = GeneralDKGPostProcessHandler { + chain_identity, + supported_relayed_chains: DEFAULT_SUPPORTED_CHAINS.to_vec(), + group_cache, + c: PhantomData, + }; + + let group = create_test_group( + DEFAULT_GROUP_INDEX, + DEFAULT_EPOCH, + true, + vec![id_address, Address::ZERO, Address::ZERO], + ); + let result = handler + .handle(DEFAULT_GROUP_INDEX, DEFAULT_EPOCH, group) + .await; + assert!(result.is_ok()); + } +} \ No newline at end of file diff --git a/crates/arpa-node/src/subscriber/post_success_grouping.rs b/crates/arpa-node/src/subscriber/post_success_grouping.rs index 610130f..1824952 100644 --- a/crates/arpa-node/src/subscriber/post_success_grouping.rs +++ b/crates/arpa-node/src/subscriber/post_success_grouping.rs @@ -92,7 +92,6 @@ impl Subscriber return Err(NodeError::DKGGroupingTwisted); } - // sync up the members in the group if !self .group_cache .write() @@ -110,8 +109,6 @@ impl Subscriber ) ); } - - // save the committers and update the state of the group self.group_cache .write() .await @@ -145,3 +142,266 @@ impl DebuggableSubscriber for PostSuccessGroupingSubscriber { } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + event::{dkg_success::DKGSuccess, types::Topic, Event}, + queue::event_queue::EventQueue, + }; + use arpa_core::{Group, Member, DKGTask}; + use alloy::primitives::{Address}; + use arpa_dal::{GroupInfoHandler, cache::InMemoryGroupInfoCache}; + use std::{ + any::Any, + collections::BTreeMap, + marker::PhantomData, + sync::Arc, + }; + use threshold_bls::schemes::bn254::G2Curve; + use tokio::sync::RwLock; + + const TEST_GROUP_INDEX: usize = 1; + const TEST_EPOCH: usize = 1; + const TEST_SIZE: usize = 3; + const TEST_THRESHOLD: usize = 2; + const TEST_CHAIN_ID: usize = 0; + const TEST_ASSIGNMENT_BLOCK_HEIGHT: usize = 100; + const TEST_RPC_ENDPOINT: &str = "http://localhost:8545"; + + fn create_test_group(id_address: Address, has_public_key: bool) -> Group { + let mut members = BTreeMap::new(); + members.insert(id_address, Member { + index: 0, + dkg_index: Some(0), + id_address, + rpc_endpoint: Some(TEST_RPC_ENDPOINT.to_string()), + partial_public_key: Some(G2Curve::point()), + }); + + Group { + index: TEST_GROUP_INDEX, + epoch: TEST_EPOCH, + size: TEST_SIZE, + threshold: TEST_THRESHOLD, + state: true, + public_key: if has_public_key { Some(G2Curve::point()) } else { None }, + members, + committers: vec![id_address], + c: PhantomData, + } + } + + fn create_test_dkg_success( + chain_id: u64, + id_address: Address, + has_public_key: bool, + ) -> DKGSuccess { + DKGSuccess { + chain_id, + id_address, + group: create_test_group(id_address, has_public_key), + } + } + + fn create_group_cache(id_address: Address) -> Arc>>> { + Arc::new(RwLock::new(Box::new(InMemoryGroupInfoCache::::new(id_address)))) + } + + fn create_event_queue() -> Arc> { + Arc::new(RwLock::new(EventQueue::new())) + } + + async fn setup_group_cache_with_group( + id_address: Address, + group: Group, + ) -> Arc>>> { + let group_cache = create_group_cache(id_address); + { + let mut cache = group_cache.write().await; + let dkg_task = DKGTask { + group_index: group.index, + epoch: group.epoch, + size: group.size, + threshold: group.threshold, + members: group.members.keys().copied().collect(), + assignment_block_height: TEST_ASSIGNMENT_BLOCK_HEIGHT, + coordinator_address: Address::ZERO, + }; + cache.save_task_info(TEST_CHAIN_ID, dkg_task).await.unwrap(); + } + group_cache + } + + #[tokio::test] + async fn test_post_success_grouping_subscriber_creation() { + let id_address = Address::ZERO; + let group_cache = create_group_cache(id_address); + let eq = create_event_queue(); + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + assert!(format!("{:?}", subscriber).contains("PostSuccessGroupingSubscriber")); + } + + #[tokio::test] + async fn test_notify_successful_flow() { + let id_address = Address::ZERO; + let group_cache = create_group_cache(id_address); + let eq = create_event_queue(); + + { + let mut cache = group_cache.write().await; + let dkg_task = DKGTask { + group_index: TEST_GROUP_INDEX, + epoch: TEST_EPOCH, + size: TEST_SIZE, + threshold: TEST_THRESHOLD, + members: vec![id_address], + assignment_block_height: TEST_ASSIGNMENT_BLOCK_HEIGHT, + coordinator_address: Address::ZERO, + }; + cache.save_task_info(TEST_CHAIN_ID, dkg_task).await.unwrap(); + } + + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + let dkg_success = create_test_dkg_success(1, id_address, true); + let result = subscriber.notify(Topic::DKGSuccess, &dkg_success).await; + + match result { + Ok(_) => println!("Success!"), + Err(e) => println!("Error: {:?}", e), + } + } + + #[tokio::test] + async fn test_notify_node_not_in_group_error() { + let id_address = Address::ZERO; + let different_address = Address::ZERO; + let group = create_test_group(id_address, true); + let group_cache = setup_group_cache_with_group(id_address, group).await; + let eq = create_event_queue(); + + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + let dkg_success = create_test_dkg_success(1, different_address, true); + let result = subscriber.notify(Topic::DKGSuccess, &dkg_success).await; + + assert!(result.is_err()); + if let Err(e) = result { + println!("Error type: {:?}", e); + } + } + + #[tokio::test] + async fn test_notify_different_public_key_error() { + let id_address = Address::ZERO; + let group = create_test_group(id_address, true); + let group_cache = setup_group_cache_with_group(id_address, group).await; + let eq = create_event_queue(); + + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + let dkg_success = create_test_dkg_success(1, id_address, false); + let result = subscriber.notify(Topic::DKGSuccess, &dkg_success).await; + + assert!(result.is_err()); + if let Err(e) = result { + println!("Error type: {:?}", e); + } + } + + #[tokio::test] + async fn test_subscribe() { + let id_address = Address::ZERO; + let group_cache = create_group_cache(id_address); + let eq = create_event_queue(); + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq.clone()); + subscriber.subscribe().await; + } + + #[tokio::test] + async fn test_debuggable_subscriber_trait() { + let id_address = Address::ZERO; + let group_cache = create_group_cache(id_address); + let eq = create_event_queue(); + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + + let _: &dyn DebuggableSubscriber = &subscriber; + let _: &dyn Subscriber = &subscriber; + } + + #[tokio::test] + #[should_panic] + async fn test_notify_with_wrong_event_type() { + let id_address = Address::ZERO; + let group_cache = create_group_cache(id_address); + let eq = create_event_queue(); + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + + #[derive(Debug)] + struct WrongEvent; + + impl Event for WrongEvent { + fn topic(&self) -> Topic { + Topic::DKGSuccess + } + + fn as_any(&self) -> &dyn Any { + self + } + } + + impl DebuggableEvent for WrongEvent {} + + let wrong_event = WrongEvent; + let _result = subscriber.notify(Topic::DKGSuccess, &wrong_event).await; + } + + #[tokio::test] + async fn test_multiple_notifications() { + let id_address = Address::ZERO; + let group_cache = create_group_cache(id_address); + let eq = create_event_queue(); + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + + for i in 0..3 { + let dkg_success = create_test_dkg_success(1, id_address, true); + let result = subscriber.notify(Topic::DKGSuccess, &dkg_success).await; + println!("Notification {}: {:?}", i, result); + } + } + + #[tokio::test] + async fn test_with_different_chain_ids() { + let id_address = Address::ZERO; + let group_cache = create_group_cache(id_address); + let eq = create_event_queue(); + let subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + + let chain_ids = vec![1, 2, 3]; + for chain_id in chain_ids { + let dkg_success = create_test_dkg_success(chain_id, id_address, true); + let result = subscriber.notify(Topic::DKGSuccess, &dkg_success).await; + println!("Chain ID {}: {:?}", chain_id, result); + } + } + + #[cfg(test)] + mod integration_tests { + use super::*; + + #[tokio::test] + async fn test_full_workflow() { + let id_address = Address::ZERO; + let group_cache = create_group_cache(id_address); + let eq = create_event_queue(); + + let subscriber = PostSuccessGroupingSubscriber::new(group_cache.clone(), eq.clone()); + subscriber.subscribe().await; + + let test_subscriber = PostSuccessGroupingSubscriber::new(group_cache, eq); + let dkg_success = create_test_dkg_success(1, id_address, true); + let result = test_subscriber.notify(Topic::DKGSuccess, &dkg_success).await; + + println!("Full workflow result: {:?}", result); + } + } +} \ No newline at end of file diff --git a/crates/arpa-node/src/subscriber/pre_grouping.rs b/crates/arpa-node/src/subscriber/pre_grouping.rs index 45aaabc..a2a1fa9 100644 --- a/crates/arpa-node/src/subscriber/pre_grouping.rs +++ b/crates/arpa-node/src/subscriber/pre_grouping.rs @@ -110,3 +110,200 @@ impl DebuggableSubscriber for PreGroupingSubscriber { } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + event::{new_dkg_task::NewDKGTask, run_dkg::RunDKG, types::Topic, Event}, + queue::{event_queue::EventQueue, EventPublisher}, + }; + use arpa_core::DKGTask; + use arpa_dal::{GroupInfoHandler, cache::InMemoryGroupInfoCache}; + use alloy::primitives::{Address}; + use std::{any::Any, sync::Arc}; + use threshold_bls::schemes::bn254::G2Curve; + use tokio::sync::RwLock; + + const CHAIN_ID: u64 = 1; + const GROUP_SIZE: usize = 3; + const THRESHOLD: usize = 2; + const ASSIGNMENT_BLOCK_HEIGHT: usize = 100; + const SELF_INDEX: usize = 0; + + fn create_test_dkg_task(group_index: usize, epoch: usize) -> DKGTask { + DKGTask { + group_index, + epoch, + size: GROUP_SIZE, + threshold: THRESHOLD, + members: vec![Address::ZERO, Address::ZERO, Address::ZERO], + assignment_block_height: ASSIGNMENT_BLOCK_HEIGHT, + coordinator_address: Address::ZERO, + } + } + + fn create_test_new_dkg_task(group_index: usize, epoch: usize) -> NewDKGTask { + NewDKGTask { + chain_id: CHAIN_ID, + dkg_task: create_test_dkg_task(group_index, epoch), + self_index: SELF_INDEX, + } + } + + fn create_subscriber() -> (PreGroupingSubscriber, Arc>) { + let id_address = Address::ZERO; + let group_cache: Arc>>> = Arc::new(RwLock::new( + Box::new(InMemoryGroupInfoCache::::new(id_address)), + )); + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = PreGroupingSubscriber::new(group_cache, eq.clone()); + (subscriber, eq) + } + + #[tokio::test] + async fn test_pre_grouping_subscriber_creation() { + let (subscriber, _) = create_subscriber(); + assert!(format!("{:?}", subscriber).contains("PreGroupingSubscriber")); + } + + #[tokio::test] + async fn test_notify_with_different_group_index() { + let (subscriber, _) = create_subscriber(); + let new_dkg_task = create_test_new_dkg_task(1, 1); + let result = subscriber.notify(Topic::NewDKGTask, &new_dkg_task).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_notify_with_different_epoch() { + let (subscriber, _) = create_subscriber(); + let new_dkg_task = create_test_new_dkg_task(0, 1); + let result = subscriber.notify(Topic::NewDKGTask, &new_dkg_task).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_notify_with_same_group_index_and_epoch() { + let (subscriber, _) = create_subscriber(); + let new_dkg_task = create_test_new_dkg_task(0, 0); + let result = subscriber.notify(Topic::NewDKGTask, &new_dkg_task).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_publish_functionality() { + let (subscriber, _) = create_subscriber(); + let run_dkg_event = RunDKG { + dkg_task: create_test_dkg_task(1, 1), + }; + subscriber.publish(run_dkg_event).await; + } + + #[tokio::test] + async fn test_subscribe() { + let (subscriber, _) = create_subscriber(); + subscriber.subscribe().await; + } + + #[tokio::test] + async fn test_event_publisher_trait() { + let (subscriber, _) = create_subscriber(); + let _: &dyn EventPublisher = &subscriber; + } + + #[tokio::test] + async fn test_debuggable_subscriber_trait() { + let (subscriber, _) = create_subscriber(); + let _: &dyn DebuggableSubscriber = &subscriber; + let _: &dyn Subscriber = &subscriber; + } + + #[tokio::test] + #[should_panic] + async fn test_notify_with_wrong_event_type() { + let (subscriber, _) = create_subscriber(); + + #[derive(Debug)] + struct WrongEvent; + + impl Event for WrongEvent { + fn topic(&self) -> Topic { + Topic::NewDKGTask + } + fn as_any(&self) -> &dyn Any { + self + } + } + + impl DebuggableEvent for WrongEvent {} + + let wrong_event = WrongEvent; + let _result = subscriber.notify(Topic::NewDKGTask, &wrong_event).await; + } + + #[tokio::test] + async fn test_multiple_notifications() { + let (subscriber, _) = create_subscriber(); + for i in 0..3 { + let new_dkg_task = create_test_new_dkg_task(i + 1, i + 1); + let result = subscriber.notify(Topic::NewDKGTask, &new_dkg_task).await; + assert!(result.is_ok()); + } + } + + #[tokio::test] + async fn test_error_handling_in_notify() { + let (subscriber, _) = create_subscriber(); + let new_dkg_task = create_test_new_dkg_task(1, 1); + let result = subscriber.notify(Topic::NewDKGTask, &new_dkg_task).await; + match result { + Ok(_) => println!("Notification succeeded"), + Err(e) => println!("Notification failed with error: {:?}", e), + } + } + + #[tokio::test] + async fn test_concurrent_notifications() { + let (subscriber, _) = create_subscriber(); + let subscriber = Arc::new(subscriber); + let mut handles = vec![]; + + for i in 0..5 { + let subscriber_clone = subscriber.clone(); + let handle = tokio::spawn(async move { + let new_dkg_task = create_test_new_dkg_task(i + 1, i + 1); + subscriber_clone.notify(Topic::NewDKGTask, &new_dkg_task).await + }); + handles.push(handle); + } + + for handle in handles { + let result = handle.await.unwrap(); + println!("Concurrent notification result: {:?}", result); + } + } + + #[cfg(test)] + mod integration_tests { + use super::*; + + #[tokio::test] + async fn test_full_workflow() { + let (subscriber, _) = create_subscriber(); + subscriber.subscribe().await; + let (test_subscriber, _) = create_subscriber(); + let new_dkg_task = create_test_new_dkg_task(1, 1); + let result = test_subscriber.notify(Topic::NewDKGTask, &new_dkg_task).await; + println!("Full workflow result: {:?}", result); + } + + #[tokio::test] + async fn test_publish_and_notify_integration() { + let (subscriber, _) = create_subscriber(); + let new_dkg_task = create_test_new_dkg_task(1, 1); + let result = subscriber.notify(Topic::NewDKGTask, &new_dkg_task).await; + assert!(result.is_ok()); + } + } +} \ No newline at end of file diff --git a/crates/arpa-node/src/subscriber/randomness_signature_aggregation.rs b/crates/arpa-node/src/subscriber/randomness_signature_aggregation.rs index 1c25ba9..f80327f 100644 --- a/crates/arpa-node/src/subscriber/randomness_signature_aggregation.rs +++ b/crates/arpa-node/src/subscriber/randomness_signature_aggregation.rs @@ -149,7 +149,6 @@ impl FulfillRandomnessHandler for GeneralFulfillRandomnessHandler ) .await?; - // TODO add a special retry mechanism for gas price too high self.randomness_signature_cache .write() .await @@ -415,3 +414,666 @@ where ::Error: Sync + Send, { } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + event::{ready_to_fulfill_randomness_task::ReadyToFulfillRandomnessTask, types::Topic}, + queue::event_queue::EventQueue, + scheduler::dynamic::SimpleDynamicTaskScheduler, + }; + use alloy::node_bindings::{Anvil, AnvilInstance}; + use alloy::primitives::{Address, U256, FixedBytes}; + use alloy::providers::WsConnect; + use alloy::signers::local::PrivateKeySigner; + use alloy::sol; + use arpa_core::{ + build_client, Config, GeneralMainChainIdentity, RandomnessTask, PartialSignature, + ProviderClientWithSigner, + }; + use arpa_dal::{ + cache::{InMemoryBlockInfoCache, InMemorySignatureResultCache}, + BlockInfoHandler, BlockInfoUpdater, SignatureResultCacheHandler, + }; + use std::{collections::BTreeMap, sync::Arc}; + use threshold_bls::{poly::Eval, schemes::bn254::{G2Curve, G2Scheme}}; + use tokio::sync::RwLock; + + const TEST_CHAIN_ID: u64 = 1; + const TEST_BLOCK_HEIGHT: usize = 1000; + const TEST_BLOCK_TIME: usize = 1000; + const TEST_SUBSCRIPTION_ID: u64 = 1; + const TEST_GROUP_INDEX: u32 = 1; + const TEST_SEED: usize = 12345; + const TEST_REQUEST_CONFIRMATIONS: u16 = 6; + const TEST_CALLBACK_GAS_LIMIT: u32 = 100000; + const TEST_CALLBACK_MAX_GAS_PRICE: usize = 20000000000; + const TEST_ASSIGNMENT_BLOCK_HEIGHT: usize = 100; + const TEST_THRESHOLD: usize = 2; + const HIGH_BLOCK_HEIGHT: usize = 100000; + const LOW_GAS_PRICE: usize = 1; + const SIGNATURE_SIZE: usize = 32; + const RANDOMNESS_SIZE: usize = 96; + const NUM_SIGNERS: usize = 3; + + sol! { + #[sol(rpc)] + MockAdapter, + "test-contract/MockAdapter.json" + } + + struct TestEnvironment { + _anvil: AnvilInstance, + client: ProviderClientWithSigner, + wallet: PrivateKeySigner, + chain_id: u64, + ws_endpoint: String, + } + + impl TestEnvironment { + async fn new() -> Self { + let anvil = Anvil::new().spawn(); + let ws_endpoint = anvil.ws_endpoint(); + let ws_connect = WsConnect::new(&ws_endpoint); + let wallet: PrivateKeySigner = anvil.keys()[0].clone().into(); + let chain_id = anvil.chain_id(); + let client = build_client(wallet.clone(), chain_id, ws_connect) + .await + .unwrap(); + + TestEnvironment { + _anvil: anvil, + client, + wallet, + chain_id, + ws_endpoint, + } + } + + async fn deploy_mock_adapter(&self) -> (Address, MockAdapter::MockAdapterInstance) { + let contract = MockAdapter::deploy(self.client.clone()) + .await + .unwrap(); + (*contract.address(), contract) + } + + async fn create_chain_identity( + &self, + adapter_address: Address, + ) -> Arc>> { + let config = Config::default(); + let ws_connect = WsConnect::new(&self.ws_endpoint); + let general_chain_identity = GeneralMainChainIdentity::new( + self.chain_id.try_into().unwrap(), + self.wallet.clone(), + ws_connect, + self.client.clone(), + self.ws_endpoint.clone(), + Address::ZERO, + Address::ZERO, + adapter_address, + config.get_time_limits().contract_transaction_retry_descriptor, + config.get_time_limits().contract_view_retry_descriptor, + None, + ); + Arc::new(RwLock::new(Box::new(general_chain_identity))) + } + } + + fn create_block_cache( + chain_id: u64, + block_height: usize, + block_time: usize, + ) -> Arc>> { + let mut cache = InMemoryBlockInfoCache::new(chain_id, block_time); + cache.set_block_height(block_height); + Arc::new(RwLock::new(Box::new(cache))) + } + + fn create_signature_cache() -> Arc>>> { + let cache = InMemorySignatureResultCache::new(); + Arc::new(RwLock::new(Box::new(cache))) + } + + fn create_schedulers() -> (Arc>, Arc>) { + ( + Arc::new(RwLock::new(EventQueue::new())), + Arc::new(RwLock::new(SimpleDynamicTaskScheduler::new())) + ) + } + + fn create_test_randomness_task(request_id: Vec) -> RandomnessTask { + let mut full_request_id = vec![0u8; 32]; + let copy_len = std::cmp::min(request_id.len(), 32); + full_request_id[..copy_len].copy_from_slice(&request_id[..copy_len]); + + RandomnessTask { + request_id: full_request_id, + subscription_id: TEST_SUBSCRIPTION_ID, + group_index: TEST_GROUP_INDEX, + request_type: arpa_core::RandomnessRequestType::Randomness, + params: vec![], + requester: Address::ZERO, + seed: U256::from(TEST_SEED), + request_confirmations: TEST_REQUEST_CONFIRMATIONS, + callback_gas_limit: TEST_CALLBACK_GAS_LIMIT, + callback_max_gas_price: TEST_CALLBACK_MAX_GAS_PRICE as u128, + assignment_block_height: TEST_ASSIGNMENT_BLOCK_HEIGHT, + } + } + + fn create_test_partial_signatures() -> BTreeMap { + let mut partial_signatures = BTreeMap::new(); + + for i in 0..NUM_SIGNERS { + let addr = Address::ZERO; + let eval = Eval { + value: vec![i as u8; SIGNATURE_SIZE], + index: i as u32, + }; + let serialized = bincode::serialize(&eval).unwrap(); + partial_signatures.insert(addr, PartialSignature { + index: i, + signed_partial_signature: serialized, + }); + } + partial_signatures + } + + async fn setup_signature_cache_with_task( + cache: Arc>>>, + randomness_task: RandomnessTask, + partial_signatures: BTreeMap, + committed_times: usize, + ) { + cache.write().await.add( + randomness_task.group_index as usize, + randomness_task.clone(), + vec![1, 2, 3], + TEST_THRESHOLD, + ).await.unwrap(); + + for (address, partial_sig) in partial_signatures { + cache.write().await.add_partial_signature( + randomness_task.request_id.clone(), + address, + partial_sig.index, + partial_sig.signed_partial_signature, + ).await.unwrap(); + } + + for _ in 0..committed_times { + cache.write().await.incr_committed_times(&randomness_task.request_id).await.unwrap(); + } + } + + async fn create_signature_cache_with_task( + randomness_task: RandomnessTask, + partial_signatures: BTreeMap, + committed_times: usize, + ) -> Arc>>> { + let cache = create_signature_cache(); + setup_signature_cache_with_task(cache.clone(), randomness_task, partial_signatures, committed_times).await; + cache + } + + #[tokio::test] + async fn test_subscriber_creation() { + let env = TestEnvironment::new().await; + let (adapter_address, _adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let signature_cache = create_signature_cache(); + let (eq, ts) = create_schedulers(); + let id_address = Address::ZERO; + + let subscriber = RandomnessSignatureAggregationSubscriber::::new( + TEST_CHAIN_ID.try_into().unwrap(), id_address, chain_identity, block_cache, signature_cache, eq, ts, + ); + + assert_eq!(subscriber.chain_id, TEST_CHAIN_ID); + assert_eq!(subscriber.id_address, id_address); + } + + #[tokio::test] + async fn test_fulfill_randomness_handler_creation() { + let env = TestEnvironment::new().await; + let (adapter_address, _adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let signature_cache = create_signature_cache(); + let id_address = Address::ZERO; + + let handler = GeneralFulfillRandomnessHandler { + id_address, + chain_identity, + block_cache, + randomness_signature_cache: signature_cache, + pc: PhantomData, + }; + + assert_eq!(handler.id_address, id_address); + } + + #[tokio::test] + async fn test_fulfill_randomness_handler_task_not_pending() { + let env = TestEnvironment::new().await; + let (adapter_address, adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let randomness_task = create_test_randomness_task(vec![1, 2, 3, 4]); + let partial_signatures = create_test_partial_signatures(); + let signature_cache = create_signature_cache_with_task( + randomness_task.clone(), partial_signatures.clone(), 0, + ).await; + let id_address = Address::ZERO; + + let request_id = FixedBytes::<32>::from_slice(&randomness_task.request_id); + adapter.setRequestCommitment(request_id, FixedBytes::<32>::ZERO) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let handler = GeneralFulfillRandomnessHandler { + id_address, + chain_identity, + block_cache, + randomness_signature_cache: signature_cache.clone(), + pc: PhantomData, + }; + + let result = handler.handle( + randomness_task.group_index as usize, + randomness_task.clone(), + vec![1; RANDOMNESS_SIZE], + partial_signatures, + ).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_fulfill_randomness_handler_task_expired() { + let env = TestEnvironment::new().await; + let (adapter_address, adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, HIGH_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let randomness_task = create_test_randomness_task(vec![1, 2, 3, 4]); + let partial_signatures = create_test_partial_signatures(); + let signature_cache = create_signature_cache_with_task( + randomness_task.clone(), partial_signatures.clone(), 0, + ).await; + let id_address = Address::ZERO; + + let request_id = FixedBytes::<32>::from_slice(&randomness_task.request_id); + let mut commitment = [0u8; 32]; + commitment[31] = 1; + adapter.setRequestCommitment(request_id, FixedBytes::<32>::from(commitment)) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let handler = GeneralFulfillRandomnessHandler { + id_address, + chain_identity, + block_cache, + randomness_signature_cache: signature_cache.clone(), + pc: PhantomData, + }; + + let result = handler.handle( + randomness_task.group_index as usize, + randomness_task.clone(), + vec![1; RANDOMNESS_SIZE], + partial_signatures, + ).await; + + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_fulfill_randomness_handler_gas_price_too_high() { + let env = TestEnvironment::new().await; + let (adapter_address, adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let mut randomness_task = create_test_randomness_task(vec![1, 2, 3, 4]); + let partial_signatures = create_test_partial_signatures(); + let signature_cache = create_signature_cache_with_task( + randomness_task.clone(), partial_signatures.clone(), 0, + ).await; + let id_address = Address::ZERO; + randomness_task.callback_max_gas_price = LOW_GAS_PRICE as u128; + + let request_id = FixedBytes::<32>::from_slice(&randomness_task.request_id); + let mut commitment = [0u8; 32]; + commitment[31] = 1; + adapter.setRequestCommitment(request_id, FixedBytes::<32>::from(commitment)) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let handler = GeneralFulfillRandomnessHandler { + id_address, + chain_identity, + block_cache, + randomness_signature_cache: signature_cache.clone(), + pc: PhantomData, + }; + + let result = handler.handle( + randomness_task.group_index as usize, + randomness_task.clone(), + vec![1; RANDOMNESS_SIZE], + partial_signatures, + ).await; + + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_fulfill_randomness_handler_success() { + let env = TestEnvironment::new().await; + let (adapter_address, adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let randomness_task = create_test_randomness_task(vec![1, 2, 3, 4]); + let partial_signatures = create_test_partial_signatures(); + let signature_cache = create_signature_cache_with_task( + randomness_task.clone(), partial_signatures.clone(), 0, + ).await; + let id_address = Address::ZERO; + + let request_id = FixedBytes::<32>::from_slice(&randomness_task.request_id); + let mut commitment = [0u8; 32]; + commitment[31] = 1; + adapter.setRequestCommitment(request_id, FixedBytes::<32>::from(commitment)) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + adapter.setShouldRevert(request_id, false) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + adapter.setShouldRevertWithCustomError(request_id, false) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let handler = GeneralFulfillRandomnessHandler { + id_address, + chain_identity, + block_cache, + randomness_signature_cache: signature_cache.clone(), + pc: PhantomData, + }; + + let result = handler.handle( + randomness_task.group_index as usize, + randomness_task.clone(), + vec![1; SIGNATURE_SIZE], + partial_signatures, + ).await; + + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_fulfill_randomness_handler_transaction_failed() { + let env = TestEnvironment::new().await; + let (adapter_address, adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let randomness_task = create_test_randomness_task(vec![1, 2, 3, 4]); + let partial_signatures = create_test_partial_signatures(); + let signature_cache = create_signature_cache_with_task( + randomness_task.clone(), partial_signatures.clone(), 0, + ).await; + let id_address = Address::ZERO; + + let request_id = FixedBytes::<32>::from_slice(&randomness_task.request_id); + let mut commitment = [0u8; 32]; + commitment[31] = 1; + adapter.setRequestCommitment(request_id, FixedBytes::<32>::from(commitment)) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + adapter.setShouldRevert(request_id, true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let handler = GeneralFulfillRandomnessHandler { + id_address, + chain_identity, + block_cache, + randomness_signature_cache: signature_cache.clone(), + pc: PhantomData, + }; + + let result = handler.handle( + randomness_task.group_index as usize, + randomness_task.clone(), + vec![1; SIGNATURE_SIZE], + partial_signatures, + ).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_fulfill_randomness_handler_custom_error() { + let env = TestEnvironment::new().await; + let (adapter_address, adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let randomness_task = create_test_randomness_task(vec![1, 2, 3, 4]); + let partial_signatures = create_test_partial_signatures(); + let signature_cache = create_signature_cache_with_task( + randomness_task.clone(), partial_signatures.clone(), 0, + ).await; + let id_address = Address::ZERO; + + let request_id = FixedBytes::<32>::from_slice(&randomness_task.request_id); + let mut commitment = [0u8; 32]; + commitment[31] = 1; + adapter.setRequestCommitment(request_id, FixedBytes::<32>::from(commitment)) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + adapter.setShouldRevertWithCustomError(request_id, true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let handler = GeneralFulfillRandomnessHandler { + id_address, + chain_identity, + block_cache, + randomness_signature_cache: signature_cache.clone(), + pc: PhantomData, + }; + + let result = handler.handle( + randomness_task.group_index as usize, + randomness_task.clone(), + vec![1; SIGNATURE_SIZE], + partial_signatures, + ).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_subscriber_notify_with_faulty_task() { + let env = TestEnvironment::new().await; + let (adapter_address, _adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let (eq, ts) = create_schedulers(); + let id_address = Address::ZERO; + + let randomness_task = create_test_randomness_task(vec![1, 2, 3, 4]); + let partial_signatures = create_test_partial_signatures(); + + let signature_cache = create_signature_cache_with_task( + randomness_task.clone(), + partial_signatures.clone(), + DEFAULT_MAX_RANDOMNESS_FULFILLMENT_ATTEMPTS, + ).await; + + let subscriber = RandomnessSignatureAggregationSubscriber::::new( + TEST_CHAIN_ID, id_address, chain_identity, block_cache, signature_cache.clone(), eq, ts, + ); + + let result_cache = RandomnessResultCache { + group_index: randomness_task.group_index as usize, + randomness_task: randomness_task.clone(), + message: vec![1, 2, 3], + threshold: TEST_THRESHOLD, + partial_signatures, + committed_times: DEFAULT_MAX_RANDOMNESS_FULFILLMENT_ATTEMPTS, + }; + + let event = ReadyToFulfillRandomnessTask { + chain_id: TEST_CHAIN_ID.try_into().unwrap(), + tasks: vec![result_cache], + }; + + let result = subscriber.notify(Topic::ReadyToFulfillRandomnessTask(TEST_CHAIN_ID), &event).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_subscriber_notify_with_valid_task() { + let env = TestEnvironment::new().await; + let (adapter_address, _adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let signature_cache = create_signature_cache(); + let (eq, ts) = create_schedulers(); + let id_address = Address::ZERO; + + let subscriber = RandomnessSignatureAggregationSubscriber::::new( + TEST_CHAIN_ID, id_address, chain_identity, block_cache, signature_cache.clone(), eq, ts, + ); + + let randomness_task = create_test_randomness_task(vec![1, 2, 3, 4]); + let partial_signatures = create_test_partial_signatures(); + + let result_cache = RandomnessResultCache { + group_index: randomness_task.group_index as usize, + randomness_task: randomness_task.clone(), + message: vec![1, 2, 3], + threshold: TEST_THRESHOLD, + partial_signatures, + committed_times: 0, + }; + + let event = ReadyToFulfillRandomnessTask { + chain_id: TEST_CHAIN_ID, + tasks: vec![result_cache], + }; + + let result = subscriber.notify(Topic::ReadyToFulfillRandomnessTask(TEST_CHAIN_ID), &event).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_subscriber_subscribe() { + let env = TestEnvironment::new().await; + let (adapter_address, _adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let signature_cache = create_signature_cache(); + let (eq, ts) = create_schedulers(); + let id_address = Address::ZERO; + + let subscriber = RandomnessSignatureAggregationSubscriber::::new( + TEST_CHAIN_ID, id_address, chain_identity, block_cache, signature_cache, eq.clone(), ts, + ); + + subscriber.subscribe().await; + } + + #[tokio::test] + async fn test_subscriber_notify_with_multiple_tasks() { + let env = TestEnvironment::new().await; + let (adapter_address, _adapter) = env.deploy_mock_adapter().await; + let chain_identity = env.create_chain_identity(adapter_address).await; + + let block_cache = create_block_cache(TEST_CHAIN_ID, TEST_BLOCK_HEIGHT, TEST_BLOCK_TIME); + let signature_cache = create_signature_cache(); + let (eq, ts) = create_schedulers(); + let id_address = Address::ZERO; + + let subscriber = RandomnessSignatureAggregationSubscriber::::new( + TEST_CHAIN_ID, id_address, chain_identity, block_cache, signature_cache.clone(), eq, ts, + ); + + let mut tasks = Vec::new(); + for i in 0..NUM_SIGNERS { + let randomness_task = create_test_randomness_task(vec![i as u8, i as u8+1, i as u8+2, i as u8+3]); + let partial_signatures = create_test_partial_signatures(); + + let result_cache = RandomnessResultCache { + group_index: randomness_task.group_index as usize, + randomness_task: randomness_task.clone(), + message: vec![i as u8, i as u8+1, i as u8+2], + threshold: TEST_THRESHOLD, + partial_signatures, + committed_times: 0, + }; + + tasks.push(result_cache); + } + + let event = ReadyToFulfillRandomnessTask { chain_id: TEST_CHAIN_ID, tasks }; + + let result = subscriber.notify(Topic::ReadyToFulfillRandomnessTask(TEST_CHAIN_ID), &event).await; + assert!(result.is_ok()); + } +} \ No newline at end of file diff --git a/crates/arpa-node/src/subscriber/ready_to_handle_randomness_task.rs b/crates/arpa-node/src/subscriber/ready_to_handle_randomness_task.rs index b4ba3d2..462b650 100644 --- a/crates/arpa-node/src/subscriber/ready_to_handle_randomness_task.rs +++ b/crates/arpa-node/src/subscriber/ready_to_handle_randomness_task.rs @@ -406,3 +406,730 @@ where ::Error: Sync + Send, { } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + algorithm::bls::SimpleBLSCore, + committer::CommitterClient, + event::{ready_to_handle_randomness_task::ReadyToHandleRandomnessTask, types::Topic}, + queue::event_queue::EventQueue, + scheduler::dynamic::SimpleDynamicTaskScheduler + }; + use alloy::primitives::{Address, U256}; + use arpa_core::{ExponentialBackoffRetryDescriptor, RandomnessTask}; + use arpa_dal::{ + cache::{InMemoryGroupInfoCache, InMemoryBLSTasksQueue, InMemorySignatureResultCache, RandomnessResultCache}, + BLSTasksHandler, GroupInfoHandler, SignatureResultCacheHandler, + }; + use std::{sync::Arc, time::Duration}; + use threshold_bls::schemes::bn254::{G2Curve, G2Scheme}; + use tokio::sync::RwLock; + use tonic::{transport::Server, Request, Response, Status}; + use crate::rpc_stub::committer::{ + committer_service_server::{CommitterService, CommitterServiceServer}, + CommitPartialSignatureRequest, CommitPartialSignatureReply, + committer_service_client::CommitterServiceClient, + commit_partial_signature_request::BlsTaskType, + }; + + const DEFAULT_BASE_PORT: u16 = 50051; + const DEFAULT_RETRY_BASE: u64 = 1000; + const DEFAULT_RETRY_FACTOR: u64 = 2; + const DEFAULT_RETRY_ATTEMPTS: usize = 3; + const DEFAULT_GROUP_SIZE: usize = 3; + const DEFAULT_THRESHOLD: usize = 2; + const DEFAULT_GROUP_INDEX: u32 = 1; + const DEFAULT_EPOCH: usize = 1; + const DEFAULT_CHAIN_ID: u64 = 1; + const DEFAULT_BLOCK_HEIGHT: usize = 100; + const DEFAULT_SUBSCRIPTION_ID: u64 = 1; + const DEFAULT_CONFIRMATIONS: u16 = 6; + const DEFAULT_GAS_LIMIT: u32 = 200000; + const DEFAULT_GAS_PRICE: u64 = 1000000000; + const DEFAULT_SEED: u64 = 12345; + + #[derive(Debug, Clone)] + pub struct MockCommitterService { + pub should_accept: bool, + pub response_delay: Option, + pub call_count: Arc>, + pub received_requests: Arc>>, + } + + impl MockCommitterService { + pub fn new(should_accept: bool) -> Self { + Self { + should_accept, + response_delay: None, + call_count: Arc::new(std::sync::Mutex::new(0)), + received_requests: Arc::new(std::sync::Mutex::new(Vec::new())), + } + } + + pub fn with_delay(mut self, delay: Duration) -> Self { + self.response_delay = Some(delay); + self + } + + pub fn get_call_count(&self) -> usize { + *self.call_count.lock().unwrap() + } + + pub fn get_received_requests(&self) -> Vec { + self.received_requests.lock().unwrap().clone() + } + } + + #[tonic::async_trait] + impl CommitterService for MockCommitterService { + async fn commit_partial_signature( + &self, + request: Request, + ) -> Result, Status> { + *self.call_count.lock().unwrap() += 1; + self.received_requests.lock().unwrap().push(request.get_ref().clone()); + + if let Some(delay) = self.response_delay { + tokio::time::sleep(delay).await; + } + + Ok(Response::new(CommitPartialSignatureReply { + result: self.should_accept, + })) + } + } + + #[derive(Debug, Clone)] + pub struct MockCommitterClient { + pub id_address: Address, + pub committer_id_address: Address, + pub committer_endpoint: String, + pub grpc_client: Arc>>, + } + + impl MockCommitterClient { + pub async fn new( + id_address: Address, + committer_id_address: Address, + server_address: String, + ) -> Result> { + let channel = tonic::transport::Channel::from_shared(server_address.clone())? + .connect() + .await?; + + Ok(Self { + id_address, + committer_id_address, + committer_endpoint: server_address, + grpc_client: Arc::new(tokio::sync::Mutex::new(CommitterServiceClient::new(channel))), + }) + } + + pub async fn commit_partial_signature( + &self, + chain_id: usize, + task_type: arpa_core::BLSTaskType, + request_id: Vec, + message: Vec, + partial_signature: Vec, + ) -> crate::error::NodeResult { + let grpc_task_type = match task_type { + arpa_core::BLSTaskType::Randomness => BlsTaskType::Randomness, + arpa_core::BLSTaskType::GroupRelay => BlsTaskType::GroupRelay, + arpa_core::BLSTaskType::GroupRelayConfirmation => BlsTaskType::GroupRelayConfirmation, + }; + + let request = CommitPartialSignatureRequest { + id_address: format!("{:?}", self.id_address), + chain_id: chain_id as u32, + task_type: grpc_task_type as i32, + request_id, + message, + partial_signature, + }; + + let response = self.grpc_client.lock().await + .commit_partial_signature(request) + .await + .map_err(|e| crate::error::NodeError::RpcResponseError(e))?; + Ok(response.into_inner().result) + } + } + + impl CommitterClient for MockCommitterClient { + fn get_id_address(&self) -> Address { + self.id_address + } + + fn get_committer_id_address(&self) -> Address { + self.committer_id_address + } + + fn get_committer_endpoint(&self) -> &str { + &self.committer_endpoint + } + + fn build( + _id_address: Address, + _committer_id_address: Address, + _committer_endpoint: String, + _commit_partial_signature_retry_descriptor: ExponentialBackoffRetryDescriptor, + ) -> Self { + panic!("Use MockCommitterClient::new() instead for async construction") + } + } + + fn default_retry_descriptor() -> ExponentialBackoffRetryDescriptor { + ExponentialBackoffRetryDescriptor { + base: DEFAULT_RETRY_BASE, + factor: DEFAULT_RETRY_FACTOR, + max_attempts: DEFAULT_RETRY_ATTEMPTS, + use_jitter: false, + } + } + + async fn start_mock_grpc_server( + service: MockCommitterService, + port: u16, + ) -> tokio::task::JoinHandle<()> { + tokio::spawn(async move { + let addr = format!("127.0.0.1:{}", port).parse().unwrap(); + if let Err(e) = Server::builder() + .add_service(CommitterServiceServer::new(service)) + .serve(addr) + .await + { + eprintln!("Mock gRPC server error: {}", e); + } + }) + } + + async fn setup_group_cache_with_secret( + id_address: Address, + chain_id: usize, + group_index: usize, + epoch: usize, + size: usize, + threshold: usize, + member_addresses: Vec
, + ) -> NodeResult>>>> { + let group_cache: Arc>>> = Arc::new(RwLock::new( + Box::new(InMemoryGroupInfoCache::::new(id_address)), + )); + { + let mut group_cache_write = group_cache.write().await; + + let dkg_task = arpa_core::DKGTask { + group_index, + epoch, + size, + threshold, + assignment_block_height: DEFAULT_BLOCK_HEIGHT, + members: member_addresses.clone(), + coordinator_address: Address::ZERO, + }; + + group_cache_write.save_task_info(chain_id, dkg_task).await?; + group_cache_write.update_dkg_status(group_index, epoch, arpa_core::DKGStatus::InPhase).await?; + + use rand::thread_rng; + use threshold_bls::{group::Element, sig::Share}; + use dkg_core::primitives::{DKGOutput, Group as DKGGroup, Node}; + use threshold_bls::poly::{PublicPoly, Idx}; + + let secret_scalar = ::Scalar::rand(&mut thread_rng()); + + let mut dkg_nodes = Vec::new(); + for (i, &_addr) in member_addresses.iter().enumerate() { + let mut node_public_key = ::Point::one(); + let node_secret = ::Scalar::rand(&mut thread_rng()); + node_public_key.mul(&node_secret); + dkg_nodes.push(Node::new(i as Idx, node_public_key)); + } + + let qual = DKGGroup { + nodes: dkg_nodes, + threshold: threshold, + }; + + let public = PublicPoly::::new(threshold - 1); + let self_index = member_addresses + .iter() + .position(|&addr| addr == id_address) + .unwrap_or(0) as Idx; + + let share = Share { + index: self_index, + private: secret_scalar, + }; + + let dkg_output = DKGOutput { + qual, + public, + share, + disqualified_node_indices: vec![], + }; + + group_cache_write.save_successful_output(group_index, epoch, dkg_output).await?; + + let committers = member_addresses.iter().take(2).cloned().collect::>(); + group_cache_write.save_committers(group_index, epoch, committers).await?; + } + Ok(group_cache) + } + + async fn setup_group_cache_simple( + id_address: Address, + chain_id: usize, + group_index: usize, + epoch: usize, + size: usize, + threshold: usize, + member_addresses: Vec
, + ) -> NodeResult>>>> { + let group_cache: Arc>>> = Arc::new(RwLock::new( + Box::new(InMemoryGroupInfoCache::::new(id_address)), + )); + + let dkg_task = arpa_core::DKGTask { + group_index, + epoch, + size, + threshold, + assignment_block_height: DEFAULT_BLOCK_HEIGHT, + members: member_addresses.clone(), + coordinator_address: Address::ZERO, + }; + + { + let mut group_cache_write = group_cache.write().await; + group_cache_write.save_task_info(chain_id, dkg_task).await?; + + let committers = member_addresses.iter().take(2).cloned().collect::>(); + group_cache_write.save_committers(group_index, epoch, committers).await?; + group_cache_write.update_dkg_status(group_index, epoch, arpa_core::DKGStatus::InPhase).await?; + } + Ok(group_cache) + } + + async fn setup_randomness_tasks_cache( + tasks: Vec, + ) -> Arc>>> { + let cache: Arc>>> = Arc::new(RwLock::new( + Box::new(InMemoryBLSTasksQueue::::new()), + )); + + { + let mut cache_write = cache.write().await; + for task in tasks { + cache_write.add(task).await.unwrap(); + } + } + cache + } + + async fn setup_randomness_signature_cache() -> Arc>>> { + Arc::new(RwLock::new( + Box::new(InMemorySignatureResultCache::::new()), + )) + } + + fn create_test_randomness_task() -> RandomnessTask { + RandomnessTask { + request_id: vec![1, 2, 3, 4], + subscription_id: DEFAULT_SUBSCRIPTION_ID, + group_index: DEFAULT_GROUP_INDEX, + request_type: arpa_core::RandomnessRequestType::Randomness, + params: vec![], + requester: Address::ZERO, + seed: U256::from(DEFAULT_SEED), + request_confirmations: DEFAULT_CONFIRMATIONS, + callback_gas_limit: DEFAULT_GAS_LIMIT, + callback_max_gas_price: DEFAULT_GAS_PRICE as u128, + assignment_block_height: DEFAULT_BLOCK_HEIGHT, + } + } + + fn create_schedulers() -> (Arc>, Arc>) { + ( + Arc::new(RwLock::new(EventQueue::new())), + Arc::new(RwLock::new(SimpleDynamicTaskScheduler::new())), + ) + } + + #[tokio::test] + async fn test_randomness_task_subscriber_creation() { + let id_address = Address::ZERO; + + let group_cache = setup_group_cache_simple( + id_address, + DEFAULT_CHAIN_ID as usize, + DEFAULT_GROUP_INDEX as usize, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + ).await.unwrap(); + + let randomness_tasks_cache = setup_randomness_tasks_cache(vec![]).await; + let randomness_signature_cache = setup_randomness_signature_cache().await; + let (eq, ts) = create_schedulers(); + + let subscriber = ReadyToHandleRandomnessTaskSubscriber::::new( + DEFAULT_CHAIN_ID, + id_address, + group_cache, + randomness_tasks_cache, + randomness_signature_cache, + eq, + ts, + default_retry_descriptor(), + ); + + assert_eq!(subscriber.chain_id, DEFAULT_CHAIN_ID); + assert_eq!(subscriber.id_address, id_address); + } + + #[tokio::test] + async fn test_mock_grpc_committer_client_success() { + let service = MockCommitterService::new(true); + let port = DEFAULT_BASE_PORT; + + let _server_handle = start_mock_grpc_server(service.clone(), port).await; + tokio::time::sleep(Duration::from_millis(100)).await; + + let id_address = Address::ZERO; + let committer_id_address = Address::ZERO; + let server_address = format!("http://127.0.0.1:{}", port); + + let mock_client = MockCommitterClient::new( + id_address, + committer_id_address, + server_address, + ).await.expect("Failed to create mock client"); + + let result = mock_client + .commit_partial_signature( + DEFAULT_CHAIN_ID as usize, + arpa_core::BLSTaskType::Randomness, + vec![1, 2, 3], + vec![4, 5, 6], + vec![7, 8, 9], + ) + .await; + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), true); + assert_eq!(mock_client.get_committer_id_address(), committer_id_address); + + tokio::time::sleep(Duration::from_millis(50)).await; + assert_eq!(service.get_call_count(), 1); + + let received_requests = service.get_received_requests(); + assert_eq!(received_requests.len(), 1); + assert_eq!(received_requests[0].chain_id, DEFAULT_CHAIN_ID as u32); + assert_eq!(received_requests[0].task_type, BlsTaskType::Randomness as i32); + assert_eq!(received_requests[0].request_id, vec![1, 2, 3]); + assert_eq!(received_requests[0].message, vec![4, 5, 6]); + assert_eq!(received_requests[0].partial_signature, vec![7, 8, 9]); + } + + #[tokio::test] + async fn test_mock_grpc_committer_client_rejection() { + let service = MockCommitterService::new(false); + let port = DEFAULT_BASE_PORT + 1; + + let _server_handle = start_mock_grpc_server(service.clone(), port).await; + tokio::time::sleep(Duration::from_millis(100)).await; + + let id_address = Address::ZERO; + let committer_id_address = Address::ZERO; + let server_address = format!("http://127.0.0.1:{}", port); + + let mock_client = MockCommitterClient::new( + id_address, + committer_id_address, + server_address, + ).await.expect("Failed to create mock client"); + + let result = mock_client + .commit_partial_signature( + DEFAULT_CHAIN_ID as usize, + arpa_core::BLSTaskType::Randomness, + vec![1, 2, 3], + vec![4, 5, 6], + vec![7, 8, 9], + ) + .await; + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), false); + + tokio::time::sleep(Duration::from_millis(50)).await; + assert_eq!(service.get_call_count(), 1); + } + + #[tokio::test] + async fn test_mock_grpc_committer_with_delay() { + let service = MockCommitterService::new(true) + .with_delay(Duration::from_millis(100)); + let port = DEFAULT_BASE_PORT + 2; + + let _server_handle = start_mock_grpc_server(service.clone(), port).await; + tokio::time::sleep(Duration::from_millis(100)).await; + + let id_address = Address::ZERO; + let committer_id_address = Address::ZERO; + let server_address = format!("http://127.0.0.1:{}", port); + + let mock_client = MockCommitterClient::new( + id_address, + committer_id_address, + server_address, + ).await.expect("Failed to create mock client"); + + let start_time = std::time::Instant::now(); + + let result = mock_client + .commit_partial_signature( + DEFAULT_CHAIN_ID as usize, + arpa_core::BLSTaskType::Randomness, + vec![1, 2, 3], + vec![4, 5, 6], + vec![7, 8, 9], + ) + .await; + + let elapsed = start_time.elapsed(); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), true); + assert!(elapsed >= Duration::from_millis(100)); + } + + #[tokio::test] + async fn test_multiple_task_types() { + let service = MockCommitterService::new(true); + let port = DEFAULT_BASE_PORT + 3; + + let _server_handle = start_mock_grpc_server(service.clone(), port).await; + tokio::time::sleep(Duration::from_millis(100)).await; + + let id_address = Address::ZERO; + let committer_id_address = Address::ZERO; + let server_address = format!("http://127.0.0.1:{}", port); + + let mock_client = MockCommitterClient::new( + id_address, + committer_id_address, + server_address, + ).await.expect("Failed to create mock client"); + + let task_types = vec![ + arpa_core::BLSTaskType::Randomness, + arpa_core::BLSTaskType::GroupRelay, + arpa_core::BLSTaskType::GroupRelayConfirmation, + ]; + + for (i, task_type) in task_types.iter().enumerate() { + let result = mock_client + .commit_partial_signature( + DEFAULT_CHAIN_ID as usize, + task_type.clone(), + vec![i as u8], + vec![i as u8 + 10], + vec![i as u8 + 20], + ) + .await; + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), true); + } + + tokio::time::sleep(Duration::from_millis(50)).await; + assert_eq!(service.get_call_count(), 3); + + let received_requests = service.get_received_requests(); + assert_eq!(received_requests.len(), 3); + + assert_eq!(received_requests[0].task_type, BlsTaskType::Randomness as i32); + assert_eq!(received_requests[1].task_type, BlsTaskType::GroupRelay as i32); + assert_eq!(received_requests[2].task_type, BlsTaskType::GroupRelayConfirmation as i32); + } + + #[tokio::test] + async fn test_subscriber_notify_with_mock_grpc() { + let id_address = Address::ZERO; + let tasks = vec![create_test_randomness_task()]; + + let group_cache = setup_group_cache_with_secret( + id_address, + DEFAULT_CHAIN_ID as usize, + DEFAULT_GROUP_INDEX as usize, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + ).await.unwrap(); + + let randomness_tasks_cache = setup_randomness_tasks_cache(tasks.clone()).await; + let randomness_signature_cache = setup_randomness_signature_cache().await; + let (eq, ts) = create_schedulers(); + + let subscriber = ReadyToHandleRandomnessTaskSubscriber::::new( + DEFAULT_CHAIN_ID, + id_address, + group_cache, + randomness_tasks_cache, + randomness_signature_cache, + eq, + ts, + default_retry_descriptor(), + ); + + let event = ReadyToHandleRandomnessTask { chain_id: DEFAULT_CHAIN_ID, tasks }; + + let result = subscriber + .notify(Topic::ReadyToHandleRandomnessTask(DEFAULT_CHAIN_ID), &event) + .await; + + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_partial_signature_generation() { + let id_address = Address::ZERO; + let task = create_test_randomness_task(); + + let group_cache = setup_group_cache_with_secret( + id_address, + DEFAULT_CHAIN_ID as usize, + DEFAULT_GROUP_INDEX as usize, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, Address::ZERO, Address::ZERO], + ).await.unwrap(); + + let actual_seed = [ + &arpa_core::u256_to_vec(&task.seed)[..], + &arpa_core::u256_to_vec(&U256::from(task.assignment_block_height))[..], + ] + .concat(); + + let group_cache_guard = group_cache.read().await; + let secret_share = group_cache_guard.get_secret_share().unwrap(); + let partial_signature_result = SimpleBLSCore::::partial_sign( + secret_share, + &actual_seed, + ); + + assert!(partial_signature_result.is_ok()); + } + + #[tokio::test] + async fn test_signature_cache_operations() { + let randomness_signature_cache = setup_randomness_signature_cache().await; + let task = create_test_randomness_task(); + let message = vec![1, 2, 3, 4]; + + let result = randomness_signature_cache + .write() + .await + .add(DEFAULT_GROUP_INDEX as usize, task.clone(), message, DEFAULT_THRESHOLD) + .await; + + assert!(result.is_ok()); + + let contains_result = randomness_signature_cache + .read() + .await + .contains(&task.request_id) + .await; + + assert!(contains_result.is_ok()); + assert!(contains_result.unwrap()); + } + + #[tokio::test] + async fn test_group_cache_committer_operations() { + let id_address = Address::ZERO; + let committer_address = Address::ZERO; + let non_committer_address = Address::ZERO; + + let group_cache = setup_group_cache_simple( + id_address, + DEFAULT_CHAIN_ID as usize, + DEFAULT_GROUP_INDEX as usize, + DEFAULT_EPOCH, + DEFAULT_GROUP_SIZE, + DEFAULT_THRESHOLD, + vec![id_address, committer_address, non_committer_address], + ).await.unwrap(); + + let result_id = group_cache.read().await.is_committer(id_address); + let result_committer = group_cache.read().await.is_committer(committer_address); + let result_non_committer = group_cache.read().await.is_committer(non_committer_address); + + assert!(result_id.is_ok()); + assert!(result_committer.is_ok()); + assert!(result_non_committer.is_ok()); + } + + #[tokio::test] + async fn test_multiple_grpc_clients() { + let service1 = MockCommitterService::new(true); + let service2 = MockCommitterService::new(false); + let port1 = DEFAULT_BASE_PORT + 4; + let port2 = DEFAULT_BASE_PORT + 5; + + let _server_handle1 = start_mock_grpc_server(service1.clone(), port1).await; + let _server_handle2 = start_mock_grpc_server(service2.clone(), port2).await; + + tokio::time::sleep(Duration::from_millis(100)).await; + + let client1 = MockCommitterClient::new( + Address::ZERO, + Address::ZERO, + format!("http://127.0.0.1:{}", port1), + ).await.unwrap(); + + let client2 = MockCommitterClient::new( + Address::ZERO, + Address::ZERO, + format!("http://127.0.0.1:{}", port2), + ).await.unwrap(); + + let result1 = client1 + .commit_partial_signature( + DEFAULT_CHAIN_ID as usize, + arpa_core::BLSTaskType::Randomness, + vec![1], + vec![2], + vec![3], + ) + .await; + + let result2 = client2 + .commit_partial_signature( + DEFAULT_CHAIN_ID as usize, + arpa_core::BLSTaskType::Randomness, + vec![4], + vec![5], + vec![6], + ) + .await; + + assert!(result1.is_ok()); + assert_eq!(result1.unwrap(), true); + + assert!(result2.is_ok()); + assert_eq!(result2.unwrap(), false); + + tokio::time::sleep(Duration::from_millis(50)).await; + assert_eq!(service1.get_call_count(), 1); + assert_eq!(service2.get_call_count(), 1); + } +} \ No newline at end of file diff --git a/crates/arpa-node/src/subscriber/schedule_node_activation.rs b/crates/arpa-node/src/subscriber/schedule_node_activation.rs index 35997df..3a35281 100644 --- a/crates/arpa-node/src/subscriber/schedule_node_activation.rs +++ b/crates/arpa-node/src/subscriber/schedule_node_activation.rs @@ -121,3 +121,397 @@ impl DebuggableSubscriber for NodeActivationSubscriber { } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + event::{node_activation::NodeActivation, types::Topic}, + queue::event_queue::EventQueue, + }; + use alloy::node_bindings::{Anvil, AnvilInstance}; + use alloy::primitives::{Address, U256, B256}; + use alloy::providers::{WsConnect}; + use alloy::signers::local::PrivateKeySigner; + use alloy::sol; + use arpa_core::{build_client, Config, GeneralMainChainIdentity, ProviderClientWithSigner}; + use std::sync::Arc; + use threshold_bls::schemes::bn254::G2Curve; + use tokio::sync::RwLock; + + const TEST_DKG_KEY: &[u8] = b"test_dkg_key"; + const TEST_SALT: [u8; 32] = [1u8; 32]; + const TEST_EXPIRY: u64 = 1000; + const FIRST_GROUP_INDEX: u64 = 1; + + sol! { + #[sol(rpc)] + MockAVSDirectory, + "test-contract/MockAVSDirectory.json" + } + + sol! { + #[sol(rpc)] + MockServiceManager, + "test-contract/MockServiceManager.json" + } + + sol! { + #[sol(ignore_unlinked)] + #[sol(rpc)] + MockNodeRegistry, + "test-contract/MockNodeRegistry.json" + } + + struct TestEnvironment { + _anvil: AnvilInstance, + client: ProviderClientWithSigner, + wallet: PrivateKeySigner, + chain_id: u64, + ws_endpoint: String, + } + + + impl TestEnvironment { + async fn new() -> Self { + let anvil = Anvil::new().spawn(); + let ws_endpoint = anvil.ws_endpoint(); + let ws_connect = WsConnect::new(&ws_endpoint); + let wallet: PrivateKeySigner = anvil.keys()[0].clone().into(); + let chain_id = anvil.chain_id(); + let client = build_client(wallet.clone(), chain_id, ws_connect) + .await + .unwrap(); + + TestEnvironment { + _anvil: anvil, + client, + wallet, + chain_id, + ws_endpoint, + } + } + + async fn deploy_mock_avs_directory(&self,) -> Address { + let contract = MockAVSDirectory::deploy(self.client.clone()).await.unwrap(); + *contract.address() + } + + async fn deploy_mock_service_manager(&self, avs_directory: Address) -> Address { + let contract = MockServiceManager::deploy(self.client.clone(), avs_directory).await.unwrap(); + *contract.address() + } + + async fn deploy_mock_node_registry( + &self, + service_manager: Address, + ) -> (Address, MockNodeRegistry::MockNodeRegistryInstance) { + let contract = MockNodeRegistry::deploy( + self.client.clone(), + Address::ZERO, + Address::ZERO, + service_manager + ) + .await + .unwrap(); + + (*contract.address(), contract) + } + + async fn setup_full_contracts(&self) -> (Address, Address, Address, MockNodeRegistry::MockNodeRegistryInstance) { + let avs_directory = self.deploy_mock_avs_directory().await; + let service_manager = self.deploy_mock_service_manager(avs_directory).await; + let (node_registry, registry_instance) = + self.deploy_mock_node_registry(service_manager).await; + (node_registry, service_manager, avs_directory, registry_instance) + } + + async fn register_node( + &self, + registry: &MockNodeRegistry::MockNodeRegistryInstance, + node_address: Address, + is_eigenlayer: bool, + ) { + registry + .registerNode(node_address, TEST_DKG_KEY.to_vec().into(), is_eigenlayer) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + } + + async fn create_chain_identity( + &self, + node_registry_address: Address, + ) -> Arc>> { + let config = Config::default(); + let ws_connect = WsConnect::new(&self.ws_endpoint); + let general_chain_identity = GeneralMainChainIdentity::new( + self.chain_id.try_into().unwrap(), + self.wallet.clone(), + ws_connect, + self.client.clone(), + self.ws_endpoint.clone(), + Address::ZERO, + Address::ZERO, + node_registry_address, + config + .get_time_limits() + .contract_transaction_retry_descriptor, + config.get_time_limits().contract_view_retry_descriptor, + None, + ); + Arc::new(RwLock::new(Box::new(general_chain_identity))) + } + } + + #[tokio::test] + async fn test_node_activation_subscriber_creation() { + let env = TestEnvironment::new().await; + let (node_registry_address, _, _, _) = env.setup_full_contracts().await; + let chain_identity = env.create_chain_identity(node_registry_address).await; + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq); + assert!(format!("{:?}", subscriber).contains("NodeActivationSubscriber")); + } + + #[tokio::test] + async fn test_successful_eigenlayer_node_activation() { + let env = TestEnvironment::new().await; + let node_address = env.wallet.address(); + let (node_registry_address, service_manager_address, avs_directory_address, registry_contract) = + env.setup_full_contracts().await; + + env.register_node(®istry_contract, node_address, true) + .await; + + let chain_identity = env.create_chain_identity(node_registry_address).await; + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq); + + let activation_event = NodeActivation { + chain_id: env.chain_id, + is_eigenlayer: true, + node_registry_address, + }; + + let node_before = registry_contract.getNode(node_address).call().await.unwrap(); + assert!(!node_before.state); + + let service_manager = MockServiceManager::new(service_manager_address, &env.client); + let returned_avs_directory = service_manager.avsDirectory().call().await.unwrap().0; + assert_eq!(Address::from(returned_avs_directory), avs_directory_address); + + let avs_directory = MockAVSDirectory::new(avs_directory_address, &env.client); + let test_hash = avs_directory + .calculateOperatorAVSRegistrationDigestHash( + node_address, + service_manager_address, + TEST_SALT.into(), + U256::from(TEST_EXPIRY), + ) + .call() + .await + .unwrap() + .0; + + assert_ne!(test_hash, B256::ZERO); + + let result = subscriber + .notify(Topic::NodeActivation, &activation_event) + .await; + assert!(result.is_ok()); + + let node_after = registry_contract.getNode(node_address).call().await.unwrap(); + assert!(node_after.state); + assert!(node_after.isEigenlayerNode); + } + + #[tokio::test] + async fn test_successful_native_staking_node_activation() { + let env = TestEnvironment::new().await; + let node_address = env.wallet.address(); + let (node_registry_address, _, _, registry_contract) = env.setup_full_contracts().await; + + env.register_node(®istry_contract, node_address, false) + .await; + + let chain_identity = env.create_chain_identity(node_registry_address).await; + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq); + + let activation_event = NodeActivation { + chain_id: env.chain_id, + is_eigenlayer: false, + node_registry_address, + }; + + let node_before = registry_contract.getNode(node_address).call().await.unwrap(); + assert!(!node_before.state); + + let result = subscriber + .notify(Topic::NodeActivation, &activation_event) + .await; + assert!(result.is_ok()); + + let node_after = registry_contract.getNode(node_address).call().await.unwrap(); + assert!(node_after.state); + assert!(!node_after.isEigenlayerNode); + } + + #[tokio::test] + async fn test_node_activation_already_active_error() { + let env = TestEnvironment::new().await; + let node_address = env.wallet.address(); + let (node_registry_address, _, _, registry_contract) = env.setup_full_contracts().await; + + env.register_node(®istry_contract, node_address, false) + .await; + + registry_contract + .setNodeState(node_address, true) + .send() + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + + let chain_identity = env.create_chain_identity(node_registry_address).await; + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq); + + let activation_event = NodeActivation { + chain_id: env.chain_id, + is_eigenlayer: false, + node_registry_address, + }; + + let result = subscriber + .notify(Topic::NodeActivation, &activation_event) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_node_activation_not_registered_error() { + let env = TestEnvironment::new().await; + let (node_registry_address, _, _, _) = env.setup_full_contracts().await; + + let chain_identity = env.create_chain_identity(node_registry_address).await; + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq); + + let activation_event = NodeActivation { + chain_id: env.chain_id, + is_eigenlayer: false, + node_registry_address, + }; + + let result = subscriber + .notify(Topic::NodeActivation, &activation_event) + .await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_node_activation_event_emission() { + let env = TestEnvironment::new().await; + let node_address = env.wallet.address(); + let (node_registry_address, _, _, registry_contract) = env.setup_full_contracts().await; + + env.register_node(®istry_contract, node_address, false) + .await; + + let chain_identity = env.create_chain_identity(node_registry_address).await; + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq); + + let activation_event = NodeActivation { + chain_id: env.chain_id, + is_eigenlayer: false, + node_registry_address, + }; + + let result = subscriber + .notify(Topic::NodeActivation, &activation_event) + .await; + assert!(result.is_ok()); + + let event_filter = registry_contract.NodeActivated_filter().from_block(0); + let events = event_filter.query().await.unwrap(); + assert_eq!(events.len(), 1); + assert_eq!(events[0].0.nodeAddress, node_address); + assert_eq!(events[0].0.groupIndex, U256::from(FIRST_GROUP_INDEX)); + } + + #[tokio::test] + async fn test_subscriber_subscribe() { + let env = TestEnvironment::new().await; + let (node_registry_address, _, _, _) = env.setup_full_contracts().await; + let chain_identity = env.create_chain_identity(node_registry_address).await; + + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq.clone()); + subscriber.subscribe().await; + } + + #[tokio::test] + async fn test_different_chain_ids() { + let env = TestEnvironment::new().await; + let node_address = env.wallet.address(); + let (node_registry_address, _, _, registry_contract) = env.setup_full_contracts().await; + + env.register_node(®istry_contract, node_address, false) + .await; + + let chain_identity = env.create_chain_identity(node_registry_address).await; + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq); + + let test_chain_ids = vec![1, 137, 42161, 10]; + + for chain_id in test_chain_ids { + let activation_event = NodeActivation { + chain_id, + is_eigenlayer: false, + node_registry_address, + }; + + let result = subscriber + .notify(Topic::NodeActivation, &activation_event) + .await; + assert!(result.is_ok()); + } + } + + #[tokio::test] + async fn test_node_activation_with_pending_status() { + let env = TestEnvironment::new().await; + let node_address = env.wallet.address(); + let (node_registry_address, _, _, registry_contract) = env.setup_full_contracts().await; + + env.register_node(®istry_contract, node_address, false) + .await; + + let chain_identity = env.create_chain_identity(node_registry_address).await; + let eq = Arc::new(RwLock::new(EventQueue::new())); + let subscriber = NodeActivationSubscriber::new(chain_identity, eq); + + let activation_event = NodeActivation { + chain_id: env.chain_id, + is_eigenlayer: false, + node_registry_address, + }; + + let result = subscriber + .notify(Topic::NodeActivation, &activation_event) + .await; + assert!(result.is_ok()); + + let node_after = registry_contract.getNode(node_address).call().await.unwrap(); + assert!(node_after.state); + } +} \ No newline at end of file diff --git a/crates/arpa-node/test-contract/IController.sol b/crates/arpa-node/test-contract/IController.sol new file mode 100644 index 0000000..6e659ae --- /dev/null +++ b/crates/arpa-node/test-contract/IController.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IController { + struct Member { + address nodeIdAddress; + uint256[4] partialPublicKey; + } + + struct CommitResult { + uint256 groupEpoch; + uint256[4] publicKey; + address[] disqualifiedNodes; + } + + struct CommitCache { + address[] nodeIdAddress; + CommitResult commitResult; + } + + struct Group { + uint256 index; + uint256 epoch; + uint256 size; + uint256 threshold; + Member[] members; + address[] committers; + CommitCache[] commitCacheList; + bool isStrictlyMajorityConsensusReached; + uint256[4] publicKey; + } + + struct CommitDkgParams { + uint256 groupIndex; + uint256 groupEpoch; + bytes publicKey; + bytes partialPublicKey; + address[] disqualifiedNodes; + } + + function getGroup(uint256 groupIndex) external view returns (Group memory); + + function commitDkg(CommitDkgParams memory params) external; + + function getCoordinator(uint256 groupIndex) external view returns (address); +} \ No newline at end of file diff --git a/crates/arpa-node/test-contract/MockAVSDirectory.json b/crates/arpa-node/test-contract/MockAVSDirectory.json new file mode 100644 index 0000000..5a03c1c --- /dev/null +++ b/crates/arpa-node/test-contract/MockAVSDirectory.json @@ -0,0 +1,157 @@ +{ + "abi": [ + { + "inputs": [], + "name": "OPERATOR_AVS_REGISTRATION_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "avs", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + } + ], + "name": "calculateOperatorAVSRegistrationDigestHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": { + "object": "0x6080604052348015600e575f5ffd5b506102528061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063a1060c8814610038578063d79aceab1461005d575b5f5ffd5b61004b6100463660046101dd565b610084565b60405190815260200160405180910390f35b61004b7fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd81565b604080517fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd60208201526001600160a01b038087169282019290925290841660608201526080810183905260a081018290525f906100fa9060c00160405160208183030381529060405280519060200120610103565b95945050505050565b5f610185604080517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86660208201527fb90ba67d9f9e2595b7716388c2098bad993c6f9bf167b3949b5ceb5cbd4111a5918101919091524660608201523060808201525f9060a00160405160208183030381529060405280519060200120905090565b60405161190160f01b6020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b80356001600160a01b03811681146101d8575f5ffd5b919050565b5f5f5f5f608085870312156101f0575f5ffd5b6101f9856101c2565b9350610207602086016101c2565b9396939550505050604082013591606001359056fea26469706673582212201bb5b69d81dc4e6e7a6bbea304a87080c309b9e588f0d6a74bef5f9b9fb0878864736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c8063a1060c8814610038578063d79aceab1461005d575b5f5ffd5b61004b6100463660046101dd565b610084565b60405190815260200160405180910390f35b61004b7fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd81565b604080517fda2c89bafdd34776a2b8bb9c83c82f419e20cc8c67207f70edd58249b92661bd60208201526001600160a01b038087169282019290925290841660608201526080810183905260a081018290525f906100fa9060c00160405160208183030381529060405280519060200120610103565b95945050505050565b5f610185604080517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86660208201527fb90ba67d9f9e2595b7716388c2098bad993c6f9bf167b3949b5ceb5cbd4111a5918101919091524660608201523060808201525f9060a00160405160208183030381529060405280519060200120905090565b60405161190160f01b6020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b80356001600160a01b03811681146101d8575f5ffd5b919050565b5f5f5f5f608085870312156101f0575f5ffd5b6101f9856101c2565b9350610207602086016101c2565b9396939550505050604082013591606001359056fea26469706673582212201bb5b69d81dc4e6e7a6bbea304a87080c309b9e588f0d6a74bef5f9b9fb0878864736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "methodIdentifiers": {}, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"OPERATOR_AVS_REGISTRATION_TYPEHASH\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"avs\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"salt\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"}],\"name\":\"calculateOperatorAVSRegistrationDigestHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"MockAVSDirectory.sol\":\"MockAVSDirectory\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":300},\"remappings\":[]},\"sources\":{\"MockAVSDirectory.sol\":{\"keccak256\":\"0xcdb7ea8e372ba79a263c09b789f2ae208d0be87147372d9213ea8f1e1bc44f41\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://30c8869a37deee832ad1e59a5e7d330251ffb02396f181c8de4f516b2bceb9ab\",\"dweb:/ipfs/QmfAGeyoBBXyPcvUSaqEhJpg3HNqo1vURokurzebDvjvyZ\"]}},\"version\":1}", + "metadata": { + "compiler": { + "version": "0.8.27+commit.40a35a09" + }, + "language": "Solidity", + "output": { + "abi": [ + { + "inputs": [], + "name": "OPERATOR_AVS_REGISTRATION_TYPEHASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "avs", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + } + ], + "name": "calculateOperatorAVSRegistrationDigestHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + } + }, + "settings": { + "compilationTarget": { + "MockAVSDirectory.sol": "MockAVSDirectory" + }, + "evmVersion": "cancun", + "libraries": {}, + "metadata": { + "bytecodeHash": "ipfs" + }, + "optimizer": { + "enabled": true, + "runs": 300 + }, + "remappings": [] + }, + "sources": { + "MockAVSDirectory.sol": { + "keccak256": "0xcdb7ea8e372ba79a263c09b789f2ae208d0be87147372d9213ea8f1e1bc44f41", + "license": "MIT", + "urls": [ + "bzz-raw://30c8869a37deee832ad1e59a5e7d330251ffb02396f181c8de4f516b2bceb9ab", + "dweb:/ipfs/QmfAGeyoBBXyPcvUSaqEhJpg3HNqo1vURokurzebDvjvyZ" + ] + } + }, + "version": 1 + }, + "id": 1 +} diff --git a/crates/arpa-node/test-contract/MockAVSDirectory.sol b/crates/arpa-node/test-contract/MockAVSDirectory.sol new file mode 100644 index 0000000..ac9e3c3 --- /dev/null +++ b/crates/arpa-node/test-contract/MockAVSDirectory.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract MockAVSDirectory { + bytes32 public constant OPERATOR_AVS_REGISTRATION_TYPEHASH = + keccak256("OperatorAVSRegistration(address operator,address avs,bytes32 salt,uint256 expiry)"); + + bytes32 private constant _TYPE_HASH = + keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); + + function calculateOperatorAVSRegistrationDigestHash( + address operator, + address avs, + bytes32 salt, + uint256 expiry + ) public view returns (bytes32) { + return _calculateSignableDigest( + keccak256(abi.encode(OPERATOR_AVS_REGISTRATION_TYPEHASH, operator, avs, salt, expiry)) + ); + } + + function _calculateSignableDigest(bytes32 structHash) internal view returns (bytes32) { + return keccak256(abi.encodePacked("\x19\x01", _domainSeparator(), structHash)); + } + + function _domainSeparator() internal view returns (bytes32) { + return keccak256(abi.encode( + _TYPE_HASH, + keccak256("MockAVSDirectory"), + block.chainid, + address(this) + )); + } +} \ No newline at end of file diff --git a/crates/arpa-node/test-contract/MockAdapter.json b/crates/arpa-node/test-contract/MockAdapter.json index 3d9aa4e..746a3c5 100644 --- a/crates/arpa-node/test-contract/MockAdapter.json +++ b/crates/arpa-node/test-contract/MockAdapter.json @@ -1 +1,371 @@ -{"abi":[{"type":"function","name":"_requestCommitments","inputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"emitRandomnessRequest","inputs":[{"name":"requestId","type":"bytes32","internalType":"bytes32"},{"name":"subId","type":"uint64","internalType":"uint64"},{"name":"groupIndex","type":"uint32","internalType":"uint32"},{"name":"requestType","type":"uint8","internalType":"enum MockAdapter.RequestType"},{"name":"params","type":"bytes","internalType":"bytes"},{"name":"sender","type":"address","internalType":"address"},{"name":"seed","type":"uint256","internalType":"uint256"},{"name":"requestConfirmations","type":"uint16","internalType":"uint16"},{"name":"callbackGasLimit","type":"uint32","internalType":"uint32"},{"name":"callbackMaxGasPrice","type":"uint256","internalType":"uint256"},{"name":"estimatedPayment","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getPendingRequestCommitment","inputs":[{"name":"requestId","type":"bytes32","internalType":"bytes32"}],"outputs":[{"name":"","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"setRequestCommitment","inputs":[{"name":"requestId","type":"bytes32","internalType":"bytes32"},{"name":"commitment","type":"bytes32","internalType":"bytes32"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"RandomnessRequest","inputs":[{"name":"requestId","type":"bytes32","indexed":true,"internalType":"bytes32"},{"name":"subId","type":"uint64","indexed":true,"internalType":"uint64"},{"name":"groupIndex","type":"uint32","indexed":true,"internalType":"uint32"},{"name":"requestType","type":"uint8","indexed":false,"internalType":"enum MockAdapter.RequestType"},{"name":"params","type":"bytes","indexed":false,"internalType":"bytes"},{"name":"sender","type":"address","indexed":false,"internalType":"address"},{"name":"seed","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"requestConfirmations","type":"uint16","indexed":false,"internalType":"uint16"},{"name":"callbackGasLimit","type":"uint32","indexed":false,"internalType":"uint32"},{"name":"callbackMaxGasPrice","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"estimatedPayment","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false}],"bytecode":{"object":"0x608060405234801561001057600080fd5b506103be806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631565034c14610051578063561949031461008357806368c50d52146100a3578063b3af18b4146100c5575b600080fd5b61007161005f36600461013b565b60009081526020819052604090205490565b60405190815260200160405180910390f35b61007161009136600461013b565b60006020819052908152604090205481565b6100c36100b1366004610154565b60009182526020829052604090912055565b005b6100c36100d3366004610210565b8963ffffffff168b67ffffffffffffffff168d7fd26299589dd9197a8dc30a0fa17b0fe7dd432bc3441aa5f5631ea1e14c1af7448c8c8c8c8c8c8c8c8c604051610125999897969594939291906102f0565b60405180910390a4505050505050505050505050565b60006020828403121561014d57600080fd5b5035919050565b6000806040838503121561016757600080fd5b50508035926020909101359150565b803563ffffffff8116811461018a57600080fd5b919050565b80356003811061018a57600080fd5b60008083601f8401126101b057600080fd5b50813567ffffffffffffffff8111156101c857600080fd5b6020830191508360208285010111156101e057600080fd5b9250929050565b80356001600160a01b038116811461018a57600080fd5b803561ffff8116811461018a57600080fd5b6000806000806000806000806000806000806101608d8f03121561023357600080fd5b8c359b5060208d013567ffffffffffffffff8116811461025257600080fd5b9a5061026060408e01610176565b995061026e60608e0161018f565b985067ffffffffffffffff60808e0135111561028957600080fd5b6102998e60808f01358f0161019e565b90985096506102aa60a08e016101e7565b955060c08d013594506102bf60e08e016101fe565b93506102ce6101008e01610176565b92506101208d013591506101408d013590509295989b509295989b509295989b565b600061010060038c1061031357634e487b7160e01b600052602160045260246000fd5b8b8352806020840152898184015250610120898b8285013760008a84018201526001600160a01b0389166040840152601f19601f8b01168301019050866060830152610365608083018761ffff169052565b63ffffffff851660a083015260c082019390935260e0015297965050505050505056fea26469706673582212207d4b9ed03db6758ebaac596c9c5f990d60c583ed61ec02f4bf25ccb7e6c02ddd64736f6c63430008120033","sourceMap":"57:1542:0:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80631565034c14610051578063561949031461008357806368c50d52146100a3578063b3af18b4146100c5575b600080fd5b61007161005f36600461013b565b60009081526020819052604090205490565b60405190815260200160405180910390f35b61007161009136600461013b565b60006020819052908152604090205481565b6100c36100b1366004610154565b60009182526020829052604090912055565b005b6100c36100d3366004610210565b8963ffffffff168b67ffffffffffffffff168d7fd26299589dd9197a8dc30a0fa17b0fe7dd432bc3441aa5f5631ea1e14c1af7448c8c8c8c8c8c8c8c8c604051610125999897969594939291906102f0565b60405180910390a4505050505050505050505050565b60006020828403121561014d57600080fd5b5035919050565b6000806040838503121561016757600080fd5b50508035926020909101359150565b803563ffffffff8116811461018a57600080fd5b919050565b80356003811061018a57600080fd5b60008083601f8401126101b057600080fd5b50813567ffffffffffffffff8111156101c857600080fd5b6020830191508360208285010111156101e057600080fd5b9250929050565b80356001600160a01b038116811461018a57600080fd5b803561ffff8116811461018a57600080fd5b6000806000806000806000806000806000806101608d8f03121561023357600080fd5b8c359b5060208d013567ffffffffffffffff8116811461025257600080fd5b9a5061026060408e01610176565b995061026e60608e0161018f565b985067ffffffffffffffff60808e0135111561028957600080fd5b6102998e60808f01358f0161019e565b90985096506102aa60a08e016101e7565b955060c08d013594506102bf60e08e016101fe565b93506102ce6101008e01610176565b92506101208d013591506101408d013590509295989b509295989b509295989b565b600061010060038c1061031357634e487b7160e01b600052602160045260246000fd5b8b8352806020840152898184015250610120898b8285013760008a84018201526001600160a01b0389166040840152601f19601f8b01168301019050866060830152610365608083018761ffff169052565b63ffffffff851660a083015260c082019390935260e0015297965050505050505056fea26469706673582212207d4b9ed03db6758ebaac596c9c5f990d60c583ed61ec02f4bf25ccb7e6c02ddd64736f6c63430008120033","sourceMap":"57:1542:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1315:140;;;;;;:::i;:::-;1392:7;1418:30;;;;;;;;;;;;1315:140;;;;345:25:3;;;333:2;318:18;1315:140:0;;;;;;;550:54;;;;;;:::i;:::-;;;;;;;;;;;;;;;1461:136;;;;;;:::i;:::-;1547:19;:30;;;;;;;;;;;:43;1461:136;;;611:698;;;;;;:::i;:::-;1072:10;999:303;;1053:5;999:303;;1030:9;999:303;1096:11;1121:6;;1141;1161:4;1179:20;1213:16;1243:19;1276:16;999:303;;;;;;;;;;;;;;:::i;:::-;;;;;;;;611:698;;;;;;;;;;;;:::o;14:180:3:-;73:6;126:2;114:9;105:7;101:23;97:32;94:52;;;142:1;139;132:12;94:52;-1:-1:-1;165:23:3;;14:180;-1:-1:-1;14:180:3:o;381:248::-;449:6;457;510:2;498:9;489:7;485:23;481:32;478:52;;;526:1;523;516:12;478:52;-1:-1:-1;;549:23:3;;;619:2;604:18;;;591:32;;-1:-1:-1;381:248:3:o;634:163::-;701:20;;761:10;750:22;;740:33;;730:61;;787:1;784;777:12;730:61;634:163;;;:::o;802:152::-;879:20;;928:1;918:12;;908:40;;944:1;941;934:12;959:347;1010:8;1020:6;1074:3;1067:4;1059:6;1055:17;1051:27;1041:55;;1092:1;1089;1082:12;1041:55;-1:-1:-1;1115:20:3;;1158:18;1147:30;;1144:50;;;1190:1;1187;1180:12;1144:50;1227:4;1219:6;1215:17;1203:29;;1279:3;1272:4;1263:6;1255;1251:19;1247:30;1244:39;1241:59;;;1296:1;1293;1286:12;1241:59;959:347;;;;;:::o;1311:196::-;1379:20;;-1:-1:-1;;;;;1428:54:3;;1418:65;;1408:93;;1497:1;1494;1487:12;1512:159;1579:20;;1639:6;1628:18;;1618:29;;1608:57;;1661:1;1658;1651:12;1676:1249;1845:6;1853;1861;1869;1877;1885;1893;1901;1909;1917;1925:7;1934;1988:3;1976:9;1967:7;1963:23;1959:33;1956:53;;;2005:1;2002;1995:12;1956:53;2041:9;2028:23;2018:33;;2101:2;2090:9;2086:18;2073:32;2145:18;2138:5;2134:30;2127:5;2124:41;2114:69;;2179:1;2176;2169:12;2114:69;2202:5;-1:-1:-1;2226:37:3;2259:2;2244:18;;2226:37;:::i;:::-;2216:47;;2282;2325:2;2314:9;2310:18;2282:47;:::i;:::-;2272:57;;2379:18;2372:3;2361:9;2357:19;2344:33;2341:57;2338:77;;;2411:1;2408;2401:12;2338:77;2450:85;2527:7;2519:3;2508:9;2504:19;2491:33;2480:9;2476:49;2450:85;:::i;:::-;2554:8;;-1:-1:-1;2581:8:3;-1:-1:-1;2608:39:3;2642:3;2627:19;;2608:39;:::i;:::-;2598:49;;2694:3;2683:9;2679:19;2666:33;2656:43;;2718:38;2751:3;2740:9;2736:19;2718:38;:::i;:::-;2708:48;;2775:38;2808:3;2797:9;2793:19;2775:38;:::i;:::-;2765:48;;2861:3;2850:9;2846:19;2833:33;2822:44;;2914:3;2903:9;2899:19;2886:33;2875:44;;1676:1249;;;;;;;;;;;;;;:::o;3256:1127::-;3579:4;3608:3;3641:1;3633:6;3630:13;3620:144;;3686:10;3681:3;3677:20;3674:1;3667:31;3721:4;3718:1;3711:15;3749:4;3746:1;3739:15;3620:144;3791:6;3780:9;3773:25;3834:2;3829;3818:9;3814:18;3807:30;3873:6;3868:2;3857:9;3853:18;3846:34;;3899:3;3952:6;3944;3939:2;3928:9;3924:18;3911:48;4008:1;3979:22;;;3975:31;;3968:42;-1:-1:-1;;;;;2996:54:3;;4132:2;4117:18;;2984:67;-1:-1:-1;;4071:2:3;4050:15;;4046:29;4031:45;;4027:54;;-1:-1:-1;4172:6:3;4167:2;4156:9;4152:18;4145:34;4188:46;4229:3;4218:9;4214:19;4206:6;3138;3127:18;3115:31;;3062:90;4188:46;3233:10;3222:22;;4284:3;4269:19;;3210:35;4320:3;4305:19;;4298:35;;;;4364:3;4349:19;4342:35;3256:1127;;-1:-1:-1;;;;;;;3256:1127:3:o","linkReferences":{}},"methodIdentifiers":{"_requestCommitments(bytes32)":"56194903","emitRandomnessRequest(bytes32,uint64,uint32,uint8,bytes,address,uint256,uint16,uint32,uint256,uint256)":"b3af18b4","getPendingRequestCommitment(bytes32)":"1565034c","setRequestCommitment(bytes32,bytes32)":"68c50d52"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"groupIndex\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"enum MockAdapter.RequestType\",\"name\":\"requestType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callbackMaxGasPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"estimatedPayment\",\"type\":\"uint256\"}],\"name\":\"RandomnessRequest\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"_requestCommitments\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"groupIndex\",\"type\":\"uint32\"},{\"internalType\":\"enum MockAdapter.RequestType\",\"name\":\"requestType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"params\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"seed\",\"type\":\"uint256\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"callbackMaxGasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"estimatedPayment\",\"type\":\"uint256\"}],\"name\":\"emitRandomnessRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"getPendingRequestCommitment\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"commitment\",\"type\":\"bytes32\"}],\"name\":\"setRequestCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"test/mock/MockAdapter.sol\":\"MockAdapter\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":300},\"remappings\":[\":Randcast-User-Contract/=lib/Randcast-User-Contract/contracts/\",\":Staking-v0.1/=lib/Staking-v0.1/src/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":fx-portal/=lib/fx-portal/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"test/mock/MockAdapter.sol\":{\"keccak256\":\"0x4cac908426179b5465b1f2f3c55e77957c0eccbcd5999987e59295f7a98fe37a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://daa8aeef6f05922c93d7b5ba4f0f4d05745823f3d8b8cecb934ce977617379ad\",\"dweb:/ipfs/QmSS67iCNrQpnk83ivDVDuF1CmP19utjGoJuyHsQ3GSgWg\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.18+commit.87f61d96"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32","indexed":true},{"internalType":"uint64","name":"subId","type":"uint64","indexed":true},{"internalType":"uint32","name":"groupIndex","type":"uint32","indexed":true},{"internalType":"enum MockAdapter.RequestType","name":"requestType","type":"uint8","indexed":false},{"internalType":"bytes","name":"params","type":"bytes","indexed":false},{"internalType":"address","name":"sender","type":"address","indexed":false},{"internalType":"uint256","name":"seed","type":"uint256","indexed":false},{"internalType":"uint16","name":"requestConfirmations","type":"uint16","indexed":false},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32","indexed":false},{"internalType":"uint256","name":"callbackMaxGasPrice","type":"uint256","indexed":false},{"internalType":"uint256","name":"estimatedPayment","type":"uint256","indexed":false}],"type":"event","name":"RandomnessRequest","anonymous":false},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function","name":"_requestCommitments","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"uint64","name":"subId","type":"uint64"},{"internalType":"uint32","name":"groupIndex","type":"uint32"},{"internalType":"enum MockAdapter.RequestType","name":"requestType","type":"uint8"},{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint16","name":"requestConfirmations","type":"uint16"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"},{"internalType":"uint256","name":"callbackMaxGasPrice","type":"uint256"},{"internalType":"uint256","name":"estimatedPayment","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"emitRandomnessRequest"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"}],"stateMutability":"view","type":"function","name":"getPendingRequestCommitment","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}]},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"stateMutability":"nonpayable","type":"function","name":"setRequestCommitment"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["Randcast-User-Contract/=lib/Randcast-User-Contract/contracts/","Staking-v0.1/=lib/Staking-v0.1/src/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","fx-portal/=lib/fx-portal/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":300},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"test/mock/MockAdapter.sol":"MockAdapter"},"evmVersion":"paris","libraries":{}},"sources":{"test/mock/MockAdapter.sol":{"keccak256":"0x4cac908426179b5465b1f2f3c55e77957c0eccbcd5999987e59295f7a98fe37a","urls":["bzz-raw://daa8aeef6f05922c93d7b5ba4f0f4d05745823f3d8b8cecb934ce977617379ad","dweb:/ipfs/QmSS67iCNrQpnk83ivDVDuF1CmP19utjGoJuyHsQ3GSgWg"],"license":"MIT"}},"version":1},"id":0} \ No newline at end of file +{ + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "uint64", + "name": "subId", + "type": "uint64" + }, + { + "indexed": true, + "internalType": "uint32", + "name": "groupIndex", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "enum IRequestTypeBase.RequestType", + "name": "requestType", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "params", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "requestConfirmations", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "callbackGasLimit", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "callbackMaxGasPrice", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "estimatedPayment", + "type": "uint256" + } + ], + "name": "RandomnessRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "uint32", + "name": "groupIndex", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "address", + "name": "committer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "participantMembers", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "randomness", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "payment", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "flatFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "name": "RandomnessRequestResult", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "_requestCommitments", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "subId", + "type": "uint64" + }, + { + "internalType": "uint32", + "name": "groupIndex", + "type": "uint32" + }, + { + "internalType": "enum IRequestTypeBase.RequestType", + "name": "requestType", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "seed", + "type": "uint256" + }, + { + "internalType": "uint16", + "name": "requestConfirmations", + "type": "uint16" + }, + { + "internalType": "uint32", + "name": "callbackGasLimit", + "type": "uint32" + }, + { + "internalType": "uint256", + "name": "callbackMaxGasPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "estimatedPayment", + "type": "uint256" + } + ], + "name": "emitRandomnessRequest", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "groupIndex", + "type": "uint32" + }, + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "signature", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "fulfillRandomness", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + } + ], + "name": "getPendingRequestCommitment", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "commitment", + "type": "bytes32" + } + ], + "name": "setRequestCommitment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "_shouldRevert", + "type": "bool" + } + ], + "name": "setShouldRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "requestId", + "type": "bytes32" + }, + { + "internalType": "bool", + "name": "_shouldRevertWithCustomError", + "type": "bool" + } + ], + "name": "setShouldRevertWithCustomError", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "shouldRevert", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "shouldRevertWithCustomError", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": { + "object": "0x6080604052348015600e575f5ffd5b506107968061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610090575f3560e01c80638cffc3b7116100635780638cffc3b714610119578063993d491714610146578063b1a0dcea14610178578063b3af18b41461019a578063cecaffd6146101ad575f5ffd5b8063130288f5146100945780631565034c146100a957806356194903146100db57806368c50d52146100fa575b5f5ffd5b6100a76100a236600461041d565b6101da565b005b6100c86100b73660046104af565b5f9081526020819052604090205490565b6040519081526020015b60405180910390f35b6100c86100e93660046104af565b5f6020819052908152604090205481565b6100a76101083660046104c6565b5f9182526020829052604090912055565b6100a76101273660046104e6565b5f91825260026020526040909120805460ff1916911515919091179055565b6101686101543660046104af565b60026020525f908152604090205460ff1681565b60405190151581526020016100d2565b6101686101863660046104af565b60016020525f908152604090205460ff1681565b6100a76101a836600461054d565b610358565b6100a76101bb3660046104e6565b5f91825260016020526040909120805460ff1916911515919091179055565b5f8681526002602052604090205460ff161561022f5760405162461bcd60e51b815260206004820152600f60248201526e21bab9ba37b6aa32b9ba22b93937b960891b60448201526064015b60405180910390fd5b5f8681526001602052604090205460ff161561027a5760405162461bcd60e51b815260206004820152600a60248201526915195cdd14995d995c9d60b21b6044820152606401610226565b5f868152602081815260408083208390558051600180825281830190925291828101908036833701905050905033815f815181106102ba576102ba610629565b60200260200101906001600160a01b031690816001600160a01b0316815250508763ffffffff16877f6fc1bcb4bd7d5fdf4017f746304b61ae4472496256e906c6bb44682aa2c9a6d833848a60405160200161031891815260200190565b60408051601f198184030181529082905280516020909101206103469392916103e89060649060019061063d565b60405180910390a35050505050505050565b8963ffffffff168b67ffffffffffffffff168d7fd26299589dd9197a8dc30a0fa17b0fe7dd432bc3441aa5f5631ea1e14c1af7448c8c8c8c8c8c8c8c8c6040516103aa999897969594939291906106c2565b60405180910390a4505050505050505050505050565b803563ffffffff811681146103d3575f5ffd5b919050565b5f5f83601f8401126103e8575f5ffd5b50813567ffffffffffffffff8111156103ff575f5ffd5b602083019150836020828501011115610416575f5ffd5b9250929050565b5f5f5f5f5f5f5f60a0888a031215610433575f5ffd5b61043c886103c0565b96506020880135955060408801359450606088013567ffffffffffffffff811115610465575f5ffd5b6104718a828b016103d8565b909550935050608088013567ffffffffffffffff811115610490575f5ffd5b61049c8a828b016103d8565b989b979a50959850939692959293505050565b5f602082840312156104bf575f5ffd5b5035919050565b5f5f604083850312156104d7575f5ffd5b50508035926020909101359150565b5f5f604083850312156104f7575f5ffd5b823591506020830135801515811461050d575f5ffd5b809150509250929050565b8035600381106103d3575f5ffd5b80356001600160a01b03811681146103d3575f5ffd5b803561ffff811681146103d3575f5ffd5b5f5f5f5f5f5f5f5f5f5f5f5f6101608d8f031215610569575f5ffd5b8c359b5060208d013567ffffffffffffffff81168114610587575f5ffd5b9a5061059560408e016103c0565b99506105a360608e01610518565b985067ffffffffffffffff60808e013511156105bd575f5ffd5b6105cd8e60808f01358f016103d8565b90985096506105de60a08e01610526565b955060c08d013594506105f360e08e0161053c565b93506106026101008e016103c0565b9b9e9a9d50989b979a96999598509396929591949193505061012082013591610140013590565b634e487b7160e01b5f52603260045260245ffd5b5f60c082016001600160a01b038916835260c0602084015280885180835260e08501915060208a0192505f5b818110156106905783516001600160a01b0316835260209384019390920191600101610669565b505080925050508560408301528460608301528360808301526106b760a083018415159052565b979650505050505050565b5f60038b106106df57634e487b7160e01b5f52602160045260245ffd5b8a8252610100602083015288610100830152888a6101208401375f6101208a84010152610120601f19601f8b0116830101905061072760408301896001600160a01b03169052565b86606083015261073d608083018761ffff169052565b63ffffffff851660a083015260c082019390935260e0015297965050505050505056fea26469706673582212204e7b539f868e40176daa7ce798145ed3fdc789035b371ecd796e76c12b2241af64736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f5ffd5b5060043610610090575f3560e01c80638cffc3b7116100635780638cffc3b714610119578063993d491714610146578063b1a0dcea14610178578063b3af18b41461019a578063cecaffd6146101ad575f5ffd5b8063130288f5146100945780631565034c146100a957806356194903146100db57806368c50d52146100fa575b5f5ffd5b6100a76100a236600461041d565b6101da565b005b6100c86100b73660046104af565b5f9081526020819052604090205490565b6040519081526020015b60405180910390f35b6100c86100e93660046104af565b5f6020819052908152604090205481565b6100a76101083660046104c6565b5f9182526020829052604090912055565b6100a76101273660046104e6565b5f91825260026020526040909120805460ff1916911515919091179055565b6101686101543660046104af565b60026020525f908152604090205460ff1681565b60405190151581526020016100d2565b6101686101863660046104af565b60016020525f908152604090205460ff1681565b6100a76101a836600461054d565b610358565b6100a76101bb3660046104e6565b5f91825260016020526040909120805460ff1916911515919091179055565b5f8681526002602052604090205460ff161561022f5760405162461bcd60e51b815260206004820152600f60248201526e21bab9ba37b6aa32b9ba22b93937b960891b60448201526064015b60405180910390fd5b5f8681526001602052604090205460ff161561027a5760405162461bcd60e51b815260206004820152600a60248201526915195cdd14995d995c9d60b21b6044820152606401610226565b5f868152602081815260408083208390558051600180825281830190925291828101908036833701905050905033815f815181106102ba576102ba610629565b60200260200101906001600160a01b031690816001600160a01b0316815250508763ffffffff16877f6fc1bcb4bd7d5fdf4017f746304b61ae4472496256e906c6bb44682aa2c9a6d833848a60405160200161031891815260200190565b60408051601f198184030181529082905280516020909101206103469392916103e89060649060019061063d565b60405180910390a35050505050505050565b8963ffffffff168b67ffffffffffffffff168d7fd26299589dd9197a8dc30a0fa17b0fe7dd432bc3441aa5f5631ea1e14c1af7448c8c8c8c8c8c8c8c8c6040516103aa999897969594939291906106c2565b60405180910390a4505050505050505050505050565b803563ffffffff811681146103d3575f5ffd5b919050565b5f5f83601f8401126103e8575f5ffd5b50813567ffffffffffffffff8111156103ff575f5ffd5b602083019150836020828501011115610416575f5ffd5b9250929050565b5f5f5f5f5f5f5f60a0888a031215610433575f5ffd5b61043c886103c0565b96506020880135955060408801359450606088013567ffffffffffffffff811115610465575f5ffd5b6104718a828b016103d8565b909550935050608088013567ffffffffffffffff811115610490575f5ffd5b61049c8a828b016103d8565b989b979a50959850939692959293505050565b5f602082840312156104bf575f5ffd5b5035919050565b5f5f604083850312156104d7575f5ffd5b50508035926020909101359150565b5f5f604083850312156104f7575f5ffd5b823591506020830135801515811461050d575f5ffd5b809150509250929050565b8035600381106103d3575f5ffd5b80356001600160a01b03811681146103d3575f5ffd5b803561ffff811681146103d3575f5ffd5b5f5f5f5f5f5f5f5f5f5f5f5f6101608d8f031215610569575f5ffd5b8c359b5060208d013567ffffffffffffffff81168114610587575f5ffd5b9a5061059560408e016103c0565b99506105a360608e01610518565b985067ffffffffffffffff60808e013511156105bd575f5ffd5b6105cd8e60808f01358f016103d8565b90985096506105de60a08e01610526565b955060c08d013594506105f360e08e0161053c565b93506106026101008e016103c0565b9b9e9a9d50989b979a96999598509396929591949193505061012082013591610140013590565b634e487b7160e01b5f52603260045260245ffd5b5f60c082016001600160a01b038916835260c0602084015280885180835260e08501915060208a0192505f5b818110156106905783516001600160a01b0316835260209384019390920191600101610669565b505080925050508560408301528460608301528360808301526106b760a083018415159052565b979650505050505050565b5f60038b106106df57634e487b7160e01b5f52602160045260245ffd5b8a8252610100602083015288610100830152888a6101208401375f6101208a84010152610120601f19601f8b0116830101905061072760408301896001600160a01b03169052565b86606083015261073d608083018761ffff169052565b63ffffffff851660a083015260c082019390935260e0015297965050505050505056fea26469706673582212204e7b539f868e40176daa7ce798145ed3fdc789035b371ecd796e76c12b2241af64736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "methodIdentifiers": {}, + "metadata": {}, + "id": 1 +} diff --git a/crates/arpa-node/test-contract/MockAdapter.sol b/crates/arpa-node/test-contract/MockAdapter.sol index 1cdbdb5..b7b90a2 100644 --- a/crates/arpa-node/test-contract/MockAdapter.sol +++ b/crates/arpa-node/test-contract/MockAdapter.sol @@ -1,12 +1,19 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -contract MockAdapter { +interface IRequestTypeBase { enum RequestType { Randomness, RandomWords, Shuffling } +} + +interface IAdapter { + function getPendingRequestCommitment(bytes32 requestId) external view returns (bytes32); +} + +contract MockAdapter is IRequestTypeBase, IAdapter { event RandomnessRequest( bytes32 indexed requestId, uint64 indexed subId, @@ -21,8 +28,21 @@ contract MockAdapter { uint256 estimatedPayment ); - mapping(bytes32 => bytes32) public _requestCommitments; + event RandomnessRequestResult( + bytes32 indexed requestId, + uint32 indexed groupIndex, + address committer, + address[] participantMembers, + uint256 randomness, + uint256 payment, + uint256 flatFee, + bool success + ); + mapping(bytes32 => bytes32) public _requestCommitments; + mapping(bytes32 => bool) public shouldRevert; + mapping(bytes32 => bool) public shouldRevertWithCustomError; + function emitRandomnessRequest( bytes32 requestId, uint64 subId, @@ -50,12 +70,52 @@ contract MockAdapter { estimatedPayment ); } - - function getPendingRequestCommitment(bytes32 requestId) public view returns (bytes32) { + + function getPendingRequestCommitment(bytes32 requestId) public view override(IAdapter) returns (bytes32) { return _requestCommitments[requestId]; } - + function setRequestCommitment(bytes32 requestId, bytes32 commitment) public { _requestCommitments[requestId] = commitment; } -} + + function setShouldRevert(bytes32 requestId, bool _shouldRevert) public { + shouldRevert[requestId] = _shouldRevert; + } + + function setShouldRevertWithCustomError(bytes32 requestId, bool _shouldRevertWithCustomError) public { + shouldRevertWithCustomError[requestId] = _shouldRevertWithCustomError; + } + + function fulfillRandomness( + uint32 groupIndex, + bytes32 requestId, + uint256 signature, + bytes calldata /* requestDetail */, + bytes calldata /* partialSignatures */ + ) public { + if (shouldRevertWithCustomError[requestId]) { + revert("CustomTestError"); + } + + if (shouldRevert[requestId]) { + revert("TestRevert"); + } + + delete _requestCommitments[requestId]; + + address[] memory participantMembers = new address[](1); + participantMembers[0] = msg.sender; + + emit RandomnessRequestResult( + requestId, + groupIndex, + msg.sender, + participantMembers, + uint256(keccak256(abi.encode(signature))), + 1000, + 100, + true + ); + } +} \ No newline at end of file diff --git a/crates/arpa-node/test-contract/MockController.json b/crates/arpa-node/test-contract/MockController.json index f98e1db..e3c3114 100644 --- a/crates/arpa-node/test-contract/MockController.json +++ b/crates/arpa-node/test-contract/MockController.json @@ -1 +1,563 @@ -{"abi":[{"type":"constructor","inputs":[{"name":"_nodeRegistryAddress","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"adapterAddress","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"emitDkgTaskEvent","inputs":[{"name":"globalEpoch","type":"uint256","internalType":"uint256"},{"name":"groupIndex","type":"uint256","internalType":"uint256"},{"name":"groupEpoch","type":"uint256","internalType":"uint256"},{"name":"size","type":"uint256","internalType":"uint256"},{"name":"threshold","type":"uint256","internalType":"uint256"},{"name":"members","type":"address[]","internalType":"address[]"},{"name":"assignmentBlockHeight","type":"uint256","internalType":"uint256"},{"name":"coordinatorAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getControllerConfig","inputs":[],"outputs":[{"name":"nodeRegistryContractAddress","type":"address","internalType":"address"},{"name":"adapterContractAddress","type":"address","internalType":"address"},{"name":"disqualifiedNodePenaltyAmount","type":"uint256","internalType":"uint256"},{"name":"defaultNumberOfCommitters","type":"uint256","internalType":"uint256"},{"name":"defaultDkgPhaseDuration","type":"uint256","internalType":"uint256"},{"name":"groupMaxCapacity","type":"uint256","internalType":"uint256"},{"name":"idealNumberOfGroups","type":"uint256","internalType":"uint256"},{"name":"dkgPostProcessReward","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"getGroup","inputs":[{"name":"groupIndex","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"tuple","internalType":"struct MockController.Group","components":[{"name":"index","type":"uint256","internalType":"uint256"},{"name":"epoch","type":"uint256","internalType":"uint256"},{"name":"size","type":"uint256","internalType":"uint256"},{"name":"threshold","type":"uint256","internalType":"uint256"},{"name":"members","type":"tuple[]","internalType":"struct MockController.Member[]","components":[{"name":"nodeIdAddress","type":"address","internalType":"address"},{"name":"partialPublicKey","type":"uint256[4]","internalType":"uint256[4]"}]},{"name":"committers","type":"address[]","internalType":"address[]"},{"name":"commitCacheList","type":"tuple[]","internalType":"struct MockController.CommitCache[]","components":[{"name":"nodeIdAddress","type":"address[]","internalType":"address[]"},{"name":"commitResult","type":"tuple","internalType":"struct MockController.CommitResult","components":[{"name":"groupEpoch","type":"uint256","internalType":"uint256"},{"name":"publicKey","type":"uint256[4]","internalType":"uint256[4]"},{"name":"disqualifiedNodes","type":"address[]","internalType":"address[]"}]}]},{"name":"isStrictlyMajorityConsensusReached","type":"bool","internalType":"bool"},{"name":"publicKey","type":"uint256[4]","internalType":"uint256[4]"}]}],"stateMutability":"view"},{"type":"function","name":"nodeRegistryAddress","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"setAdapterAddress","inputs":[{"name":"_adapterAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setCommitters","inputs":[{"name":"groupIndex","type":"uint256","internalType":"uint256"},{"name":"committerAddresses","type":"address[]","internalType":"address[]"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setGroup","inputs":[{"name":"groupIndex","type":"uint256","internalType":"uint256"},{"name":"epoch","type":"uint256","internalType":"uint256"},{"name":"size","type":"uint256","internalType":"uint256"},{"name":"threshold","type":"uint256","internalType":"uint256"},{"name":"isStrictlyMajorityConsensusReached","type":"bool","internalType":"bool"},{"name":"publicKey","type":"uint256[4]","internalType":"uint256[4]"},{"name":"memberAddresses","type":"address[]","internalType":"address[]"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setMemberPartialPublicKey","inputs":[{"name":"groupIndex","type":"uint256","internalType":"uint256"},{"name":"memberIndex","type":"uint256","internalType":"uint256"},{"name":"partialPublicKey","type":"uint256[4]","internalType":"uint256[4]"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"DkgTask","inputs":[{"name":"globalEpoch","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"groupIndex","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"groupEpoch","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"size","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"threshold","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"members","type":"address[]","indexed":false,"internalType":"address[]"},{"name":"assignmentBlockHeight","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"coordinatorAddress","type":"address","indexed":false,"internalType":"address"}],"anonymous":false}],"bytecode":{"object":"0x608060405234801561001057600080fd5b50604051610e9b380380610e9b83398101604081905261002f9161005b565b600180546001600160a01b039092166001600160a01b031992831617905560028054909116905561008b565b60006020828403121561006d57600080fd5b81516001600160a01b038116811461008457600080fd5b9392505050565b610e018061009a6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80636971f096116100665780636971f09614610103578063736eede514610116578063ceb6065414610146578063d11b8e6814610166578063fec10aa9146101b957600080fd5b80630fc68a0c146100985780631bb1fd28146100ad57806326a93abe146100c057806366c9aba6146100d3575b600080fd5b6100ab6100a6366004610906565b6101cc565b005b6100ab6100bb36600461098e565b610218565b6100ab6100ce366004610a43565b610240565b6002546100e6906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ab610111366004610ad2565b610362565b6100ab610124366004610b08565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b610159610154366004610b2a565b6103ae565b6040516100fa9190610c99565b600154600254604080516001600160a01b0393841681529290911660208301526103e89082015260056060820152606460808201819052600a60a0830152600360c083015260e0820152610100016100fa565b6001546100e6906001600160a01b031681565b8587897fbbd25d64683f157b2e3544d3d6430e14102db1e49592cf4dcaf827e2ded517ee8888888888604051610206959493929190610d4e565b60405180910390a45050505050505050565b600082815260208181526040909120825161023b926005909201918401906106bb565b505050565b600087815260208190526040902087815560018101879055600281018690556003810185905560078101805460ff191685151517905561028560088201846004610720565b5061029460048201600061074e565b60005b8251811015610341576102a8610772565b8260040160405180604001604052808685815181106102c9576102c9610d8e565b6020908102919091018101516001600160a01b039081168352918101859052835460018082018655600095865294829020845160059092020180546001600160a01b031916919093161782558201519192909161032a918301906004610720565b50505050808061033990610da4565b915050610297565b50815161035790600583019060208501906106bb565b505050505050505050565b80600080858152602001908152602001600020600401838154811061038957610389610d8e565b90600052602060002090600502016001019060046103a8929190610720565b50505050565b6103b6610790565b6000828152602081815260408083208151610120810183528154815260018201548185015260028201548184015260038201546060820152600482018054845181870281018701909552808552919592946080870194939192919084015b8282101561048d5760008481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b8154815260200190600101908083116104625750505050508152505081526020019060010190610414565b505050508152602001600582018054806020026020016040519081016040528092919081815260200182805480156104ee57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116104d0575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b8282101561066557838290600052602060002090600702016040518060400160405290816000820180548060200260200160405190810160405280929190818152602001828054801561059857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161057a575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b8154815260200190600101908083116105d457505050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801561064957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161062b575b505050505081525050815250508152602001906001019061051c565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b815481526020019060010190808311610698575050505050815250509050919050565b828054828255906000526020600020908101928215610710579160200282015b8281111561071057825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906106db565b5061071c9291506107e3565b5090565b8260048101928215610710579160200282015b82811115610710578251825591602001919060010190610733565b508054600082556005029060005260206000209081019061076f91906107f8565b50565b60405180608001604052806004906020820280368337509192915050565b604051806101200160405280600081526020016000815260200160008152602001600081526020016060815260200160608152602001606081526020016000151581526020016107de610772565b905290565b5b8082111561071c57600081556001016107e4565b8082111561071c5780546001600160a01b0319168155600060018201819055600282018190556003820181905560048201556005016107f8565b634e487b7160e01b600052604160045260246000fd5b80356001600160a01b038116811461085f57600080fd5b919050565b600082601f83011261087557600080fd5b8135602067ffffffffffffffff8083111561089257610892610832565b8260051b604051601f19603f830116810181811084821117156108b7576108b7610832565b6040529384528581018301938381019250878511156108d557600080fd5b83870191505b848210156108fb576108ec82610848565b835291830191908301906108db565b979650505050505050565b600080600080600080600080610100898b03121561092357600080fd5b883597506020890135965060408901359550606089013594506080890135935060a089013567ffffffffffffffff81111561095d57600080fd5b6109698b828c01610864565b93505060c0890135915061097f60e08a01610848565b90509295985092959890939650565b600080604083850312156109a157600080fd5b82359150602083013567ffffffffffffffff8111156109bf57600080fd5b6109cb85828601610864565b9150509250929050565b600082601f8301126109e657600080fd5b6040516080810181811067ffffffffffffffff82111715610a0957610a09610832565b604052806080840185811115610a1e57600080fd5b845b81811015610a38578035835260209283019201610a20565b509195945050505050565b6000806000806000806000610140888a031215610a5f57600080fd5b8735965060208801359550604088013594506060880135935060808801358015158114610a8b57600080fd5b9250610a9a8960a08a016109d5565b915061012088013567ffffffffffffffff811115610ab757600080fd5b610ac38a828b01610864565b91505092959891949750929550565b600080600060c08486031215610ae757600080fd5b8335925060208401359150610aff85604086016109d5565b90509250925092565b600060208284031215610b1a57600080fd5b610b2382610848565b9392505050565b600060208284031215610b3c57600080fd5b5035919050565b8060005b60048110156103a8578151845260209384019390910190600101610b47565b600081518084526020808501945080840160005b83811015610bb457815180516001600160a01b03168852830151610ba084890182610b43565b5060a0969096019590820190600101610b7a565b509495945050505050565b600081518084526020808501945080840160005b83811015610bb45781516001600160a01b031687529582019590820190600101610bd3565b600081518084526020808501808196508360051b8101915082860160005b85811015610c8c578284038952815160408151818752610c3882880182610bbf565b90508783015192508681038888015260c08351825288840151610c5d8a840182610b43565b508284015193508060a0830152610c7681830185610bbf565b9c89019c97505050928601925050600101610c16565b5091979650505050505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201526000608083015161018060a0840152610cdf6101a0840182610b66565b905060a0840151601f19808584030160c0860152610cfd8383610bbf565b925060c08601519150808584030160e086015250610d1b8282610bf8565b91505060e0840151610100610d338186018315159052565b8501519050610d46610120850182610b43565b509392505050565b85815284602082015260a060408201526000610d6d60a0830186610bbf565b90508360608301526001600160a01b03831660808301529695505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201610dc457634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220d5275654e678068bd7262d977c899e65387d270e28fddbb0056b3e8d4ee8489364736f6c63430008120033","sourceMap":"57:3972:1:-:0;;;1113:138;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1165:19;:42;;-1:-1:-1;;;;;1165:42:1;;;-1:-1:-1;;;;;;1165:42:1;;;;;;1217:14;:27;;;;;;;57:3972;;14:290:3;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:3;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:3:o;:::-;57:3972:1;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100935760003560e01c80636971f096116100665780636971f09614610103578063736eede514610116578063ceb6065414610146578063d11b8e6814610166578063fec10aa9146101b957600080fd5b80630fc68a0c146100985780631bb1fd28146100ad57806326a93abe146100c057806366c9aba6146100d3575b600080fd5b6100ab6100a6366004610906565b6101cc565b005b6100ab6100bb36600461098e565b610218565b6100ab6100ce366004610a43565b610240565b6002546100e6906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100ab610111366004610ad2565b610362565b6100ab610124366004610b08565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b610159610154366004610b2a565b6103ae565b6040516100fa9190610c99565b600154600254604080516001600160a01b0393841681529290911660208301526103e89082015260056060820152606460808201819052600a60a0830152600360c083015260e0820152610100016100fa565b6001546100e6906001600160a01b031681565b8587897fbbd25d64683f157b2e3544d3d6430e14102db1e49592cf4dcaf827e2ded517ee8888888888604051610206959493929190610d4e565b60405180910390a45050505050505050565b600082815260208181526040909120825161023b926005909201918401906106bb565b505050565b600087815260208190526040902087815560018101879055600281018690556003810185905560078101805460ff191685151517905561028560088201846004610720565b5061029460048201600061074e565b60005b8251811015610341576102a8610772565b8260040160405180604001604052808685815181106102c9576102c9610d8e565b6020908102919091018101516001600160a01b039081168352918101859052835460018082018655600095865294829020845160059092020180546001600160a01b031916919093161782558201519192909161032a918301906004610720565b50505050808061033990610da4565b915050610297565b50815161035790600583019060208501906106bb565b505050505050505050565b80600080858152602001908152602001600020600401838154811061038957610389610d8e565b90600052602060002090600502016001019060046103a8929190610720565b50505050565b6103b6610790565b6000828152602081815260408083208151610120810183528154815260018201548185015260028201548184015260038201546060820152600482018054845181870281018701909552808552919592946080870194939192919084015b8282101561048d5760008481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b8154815260200190600101908083116104625750505050508152505081526020019060010190610414565b505050508152602001600582018054806020026020016040519081016040528092919081815260200182805480156104ee57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116104d0575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b8282101561066557838290600052602060002090600702016040518060400160405290816000820180548060200260200160405190810160405280929190818152602001828054801561059857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161057a575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b8154815260200190600101908083116105d457505050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801561064957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161062b575b505050505081525050815250508152602001906001019061051c565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b815481526020019060010190808311610698575050505050815250509050919050565b828054828255906000526020600020908101928215610710579160200282015b8281111561071057825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906106db565b5061071c9291506107e3565b5090565b8260048101928215610710579160200282015b82811115610710578251825591602001919060010190610733565b508054600082556005029060005260206000209081019061076f91906107f8565b50565b60405180608001604052806004906020820280368337509192915050565b604051806101200160405280600081526020016000815260200160008152602001600081526020016060815260200160608152602001606081526020016000151581526020016107de610772565b905290565b5b8082111561071c57600081556001016107e4565b8082111561071c5780546001600160a01b0319168155600060018201819055600282018190556003820181905560048201556005016107f8565b634e487b7160e01b600052604160045260246000fd5b80356001600160a01b038116811461085f57600080fd5b919050565b600082601f83011261087557600080fd5b8135602067ffffffffffffffff8083111561089257610892610832565b8260051b604051601f19603f830116810181811084821117156108b7576108b7610832565b6040529384528581018301938381019250878511156108d557600080fd5b83870191505b848210156108fb576108ec82610848565b835291830191908301906108db565b979650505050505050565b600080600080600080600080610100898b03121561092357600080fd5b883597506020890135965060408901359550606089013594506080890135935060a089013567ffffffffffffffff81111561095d57600080fd5b6109698b828c01610864565b93505060c0890135915061097f60e08a01610848565b90509295985092959890939650565b600080604083850312156109a157600080fd5b82359150602083013567ffffffffffffffff8111156109bf57600080fd5b6109cb85828601610864565b9150509250929050565b600082601f8301126109e657600080fd5b6040516080810181811067ffffffffffffffff82111715610a0957610a09610832565b604052806080840185811115610a1e57600080fd5b845b81811015610a38578035835260209283019201610a20565b509195945050505050565b6000806000806000806000610140888a031215610a5f57600080fd5b8735965060208801359550604088013594506060880135935060808801358015158114610a8b57600080fd5b9250610a9a8960a08a016109d5565b915061012088013567ffffffffffffffff811115610ab757600080fd5b610ac38a828b01610864565b91505092959891949750929550565b600080600060c08486031215610ae757600080fd5b8335925060208401359150610aff85604086016109d5565b90509250925092565b600060208284031215610b1a57600080fd5b610b2382610848565b9392505050565b600060208284031215610b3c57600080fd5b5035919050565b8060005b60048110156103a8578151845260209384019390910190600101610b47565b600081518084526020808501945080840160005b83811015610bb457815180516001600160a01b03168852830151610ba084890182610b43565b5060a0969096019590820190600101610b7a565b509495945050505050565b600081518084526020808501945080840160005b83811015610bb45781516001600160a01b031687529582019590820190600101610bd3565b600081518084526020808501808196508360051b8101915082860160005b85811015610c8c578284038952815160408151818752610c3882880182610bbf565b90508783015192508681038888015260c08351825288840151610c5d8a840182610b43565b508284015193508060a0830152610c7681830185610bbf565b9c89019c97505050928601925050600101610c16565b5091979650505050505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201526000608083015161018060a0840152610cdf6101a0840182610b66565b905060a0840151601f19808584030160c0860152610cfd8383610bbf565b925060c08601519150808584030160e086015250610d1b8282610bf8565b91505060e0840151610100610d338186018315159052565b8501519050610d46610120850182610b43565b509392505050565b85815284602082015260a060408201526000610d6d60a0830186610bbf565b90508360608301526001600160a01b03831660808301529695505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201610dc457634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220d5275654e678068bd7262d977c899e65387d270e28fddbb0056b3e8d4ee8489364736f6c63430008120033","sourceMap":"57:3972:1:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3470:441;;;;;;:::i;:::-;;:::i;:::-;;3187:156;;;;;;:::i;:::-;;:::i;2061:889::-;;;;;;:::i;:::-;;:::i;173:29::-;;;;;-1:-1:-1;;;;;173:29:1;;;;;;-1:-1:-1;;;;;4240:55:3;;;4222:74;;4210:2;4195:18;173:29:1;;;;;;;;2956:225;;;;;;:::i;:::-;;:::i;3917:110::-;;;;;;:::i;:::-;3988:14;:32;;-1:-1:-1;;;;;;3988:32:1;-1:-1:-1;;;;;3988:32:1;;;;;;;;;;3917:110;3349:115;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1257:798::-;1737:19;;1770:14;;1257:798;;;-1:-1:-1;;;;;1737:19:1;;;9631:34:3;;1770:14:1;;;;9696:2:3;9681:18;;9674:43;1798:4:1;9733:18:3;;;9726:34;1849:1:1;9791:2:3;9776:18;;9769:34;1893:3:1;9834::3;9819:19;;9812:35;;;1937:2:1;9878:3:3;9863:19;;9856:35;1973:1:1;9922:3:3;9907:19;;9900:35;9966:3;9951:19;;9944:35;9557:3;9542:19;1257:798:1;9227:758:3;133:34:1;;;;;-1:-1:-1;;;;;133:34:1;;;3470:441;3815:10;3803;3790:11;3769:135;3827:4;3833:9;3844:7;3853:21;3876:18;3769:135;;;;;;;;;;:::i;:::-;;;;;;;;3470:441;;;;;;;;:::o;3187:156::-;3286:6;:18;;;;;;;;;;;:50;;;;:29;;;;;:50;;;;:::i;:::-;;3187:156;;:::o;2061:889::-;2332:19;2354:18;;;;;;;;;;2382:24;;;2416:11;;;:19;;;2445:10;;;:17;;;2472:15;;;:27;;;2509:40;;;:77;;-1:-1:-1;;2509:77:1;;;;;;;2596:27;:15;;;2614:9;2596:27;;:::i;:::-;-1:-1:-1;2634:20:1;2641:13;;;;2634:20;:::i;:::-;2669:9;2664:235;2688:15;:22;2684:1;:26;2664:235;;;2731:39;;:::i;:::-;2784:5;:13;;2803:84;;;;;;;;2826:15;2842:1;2826:18;;;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;2803:84:1;;;;;;;;;;;2784:104;;;;;;;;-1:-1:-1;2784:104:1;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2784:104:1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;2717:182;2712:3;;;;;:::i;:::-;;;;2664:235;;;-1:-1:-1;2909:34:1;;;;:16;;;;:34;;;;;:::i;:::-;;2322:628;2061:889;;;;;;;:::o;2956:225::-;3158:16;3099:6;:18;3106:10;3099:18;;;;;;;;;;;:26;;3126:11;3099:39;;;;;;;;:::i;:::-;;;;;;;;;;;:56;;:75;;;;;;;:::i;:::-;;2956:225;;;:::o;3349:115::-;3408:12;;:::i;:::-;3439:6;:18;;;;;;;;;;;3432:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3439:18;;3432:25;;;;;;;;3439:6;3432:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3432:25:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3432:25:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3432:25:1;;;;;;;;;;;;;;;;-1:-1:-1;;;3432:25:1;;;-1:-1:-1;;3432:25:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3432:25:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;3432:25:1;;;-1:-1:-1;3432:25:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3349:115;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:127:3;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:196;214:20;;-1:-1:-1;;;;;263:54:3;;253:65;;243:93;;332:1;329;322:12;243:93;146:196;;;:::o;347:908::-;401:5;454:3;447:4;439:6;435:17;431:27;421:55;;472:1;469;462:12;421:55;508:6;495:20;534:4;557:18;594:2;590;587:10;584:36;;;600:18;;:::i;:::-;646:2;643:1;639:10;678:2;672:9;741:2;737:7;732:2;728;724:11;720:25;712:6;708:38;796:6;784:10;781:22;776:2;764:10;761:18;758:46;755:72;;;807:18;;:::i;:::-;843:2;836:22;893:18;;;969:15;;;965:24;;;927:15;;;;-1:-1:-1;1001:15:3;;;998:35;;;1029:1;1026;1019:12;998:35;1065:2;1057:6;1053:15;1042:26;;1077:148;1093:6;1088:3;1085:15;1077:148;;;1159:23;1178:3;1159:23;:::i;:::-;1147:36;;1203:12;;;;1110;;;;1077:148;;;1243:6;347:908;-1:-1:-1;;;;;;;347:908:3:o;1260:835::-;1407:6;1415;1423;1431;1439;1447;1455;1463;1516:3;1504:9;1495:7;1491:23;1487:33;1484:53;;;1533:1;1530;1523:12;1484:53;1569:9;1556:23;1546:33;;1626:2;1615:9;1611:18;1598:32;1588:42;;1677:2;1666:9;1662:18;1649:32;1639:42;;1728:2;1717:9;1713:18;1700:32;1690:42;;1779:3;1768:9;1764:19;1751:33;1741:43;;1835:3;1824:9;1820:19;1807:33;1863:18;1855:6;1852:30;1849:50;;;1895:1;1892;1885:12;1849:50;1918:61;1971:7;1962:6;1951:9;1947:22;1918:61;:::i;:::-;1908:71;;;2026:3;2015:9;2011:19;1998:33;1988:43;;2050:39;2084:3;2073:9;2069:19;2050:39;:::i;:::-;2040:49;;1260:835;;;;;;;;;;;:::o;2100:416::-;2193:6;2201;2254:2;2242:9;2233:7;2229:23;2225:32;2222:52;;;2270:1;2267;2260:12;2222:52;2306:9;2293:23;2283:33;;2367:2;2356:9;2352:18;2339:32;2394:18;2386:6;2383:30;2380:50;;;2426:1;2423;2416:12;2380:50;2449:61;2502:7;2493:6;2482:9;2478:22;2449:61;:::i;:::-;2439:71;;;2100:416;;;;;:::o;2521:648::-;2571:5;2624:3;2617:4;2609:6;2605:17;2601:27;2591:55;;2642:1;2639;2632:12;2591:55;2675:2;2669:9;2717:3;2709:6;2705:16;2787:6;2775:10;2772:22;2751:18;2739:10;2736:34;2733:62;2730:88;;;2798:18;;:::i;:::-;2834:2;2827:22;2869:6;2910:3;2898:16;;2926:15;;;2923:35;;;2954:1;2951;2944:12;2923:35;2978:6;2993:146;3009:6;3004:3;3001:15;2993:146;;;3077:17;;3065:30;;3124:4;3115:14;;;;3026;2993:146;;;-1:-1:-1;3157:6:3;;2521:648;-1:-1:-1;;;;;2521:648:3:o;3174:897::-;3332:6;3340;3348;3356;3364;3372;3380;3433:3;3421:9;3412:7;3408:23;3404:33;3401:53;;;3450:1;3447;3440:12;3401:53;3486:9;3473:23;3463:33;;3543:2;3532:9;3528:18;3515:32;3505:42;;3594:2;3583:9;3579:18;3566:32;3556:42;;3645:2;3634:9;3630:18;3617:32;3607:42;;3699:3;3688:9;3684:19;3671:33;3747:5;3740:13;3733:21;3726:5;3723:32;3713:60;;3769:1;3766;3759:12;3713:60;3792:5;-1:-1:-1;3816:54:3;3862:7;3856:3;3841:19;;3816:54;:::i;:::-;3806:64;;3921:3;3910:9;3906:19;3893:33;3949:18;3941:6;3938:30;3935:50;;;3981:1;3978;3971:12;3935:50;4004:61;4057:7;4048:6;4037:9;4033:22;4004:61;:::i;:::-;3994:71;;;3174:897;;;;;;;;;;:::o;4307:361::-;4407:6;4415;4423;4476:3;4464:9;4455:7;4451:23;4447:33;4444:53;;;4493:1;4490;4483:12;4444:53;4529:9;4516:23;4506:33;;4586:2;4575:9;4571:18;4558:32;4548:42;;4609:53;4654:7;4649:2;4638:9;4634:18;4609:53;:::i;:::-;4599:63;;4307:361;;;;;:::o;4673:186::-;4732:6;4785:2;4773:9;4764:7;4760:23;4756:32;4753:52;;;4801:1;4798;4791:12;4753:52;4824:29;4843:9;4824:29;:::i;:::-;4814:39;4673:186;-1:-1:-1;;;4673:186:3:o;4864:180::-;4923:6;4976:2;4964:9;4955:7;4951:23;4947:32;4944:52;;;4992:1;4989;4982:12;4944:52;-1:-1:-1;5015:23:3;;4864:180;-1:-1:-1;4864:180:3:o;5049:326::-;5142:5;5165:1;5175:194;5189:4;5186:1;5183:11;5175:194;;;5248:13;;5236:26;;5285:4;5309:12;;;;5344:15;;;;5209:1;5202:9;5175:194;;5380:640;5439:3;5477:5;5471:12;5504:6;5499:3;5492:19;5530:4;5559:2;5554:3;5550:12;5543:19;;5596:2;5589:5;5585:14;5617:1;5627:368;5641:6;5638:1;5635:13;5627:368;;;5700:13;;5742:9;;-1:-1:-1;;;;;5738:58:3;5726:71;;5836:11;;5830:18;5861:52;5900:12;;;5830:18;5861:52;:::i;:::-;-1:-1:-1;5942:4:3;5933:14;;;;;5970:15;;;;5663:1;5656:9;5627:368;;;-1:-1:-1;6011:3:3;;5380:640;-1:-1:-1;;;;;5380:640:3:o;6025:484::-;6078:3;6116:5;6110:12;6143:6;6138:3;6131:19;6169:4;6198:2;6193:3;6189:12;6182:19;;6235:2;6228:5;6224:14;6256:1;6266:218;6280:6;6277:1;6274:13;6266:218;;;6345:13;;-1:-1:-1;;;;;6341:62:3;6329:75;;6424:12;;;;6459:15;;;;6302:1;6295:9;6266:218;;6514:1294;6578:3;6616:5;6610:12;6643:6;6638:3;6631:19;6669:4;6710:2;6705:3;6701:12;6735:11;6762;6755:18;;6812:6;6809:1;6805:14;6798:5;6794:26;6782:38;;6854:2;6847:5;6843:14;6875:1;6885:897;6899:6;6896:1;6893:13;6885:897;;;6970:5;6964:4;6960:16;6955:3;6948:29;7006:6;7000:13;7036:4;7079:2;7073:9;7108:2;7102:4;7095:16;7138:57;7191:2;7185:4;7181:13;7167:12;7138:57;:::i;:::-;7124:71;;7244:2;7240;7236:11;7230:18;7208:40;;7295:4;7287:6;7283:17;7278:2;7272:4;7268:13;7261:40;7324:4;7362:14;7356:21;7348:6;7341:37;7439:2;7423:14;7419:23;7413:30;7456:57;7509:2;7501:6;7497:15;7481:14;7456:57;:::i;:::-;;7574:2;7558:14;7554:23;7548:30;7526:52;;7617:2;7610:4;7602:6;7598:17;7591:29;7641:61;7698:2;7690:6;7686:15;7670:14;7641:61;:::i;:::-;7760:12;;;;7633:69;-1:-1:-1;;;7725:15:3;;;;-1:-1:-1;;6921:1:3;6914:9;6885:897;;;-1:-1:-1;7798:4:3;;6514:1294;-1:-1:-1;;;;;;;6514:1294:3:o;7909:1313::-;8082:2;8071:9;8064:21;8127:6;8121:13;8116:2;8105:9;8101:18;8094:41;8189:2;8181:6;8177:15;8171:22;8166:2;8155:9;8151:18;8144:50;8248:2;8240:6;8236:15;8230:22;8225:2;8214:9;8210:18;8203:50;8308:2;8300:6;8296:15;8290:22;8284:3;8273:9;8269:19;8262:51;8045:4;8360:3;8352:6;8348:16;8342:23;8402:6;8396:3;8385:9;8381:19;8374:35;8432:69;8496:3;8485:9;8481:19;8467:12;8432:69;:::i;:::-;8418:83;;8550:3;8542:6;8538:16;8532:23;8578:2;8574:7;8646:2;8634:9;8626:6;8622:22;8618:31;8612:3;8601:9;8597:19;8590:60;8673:52;8718:6;8702:14;8673:52;:::i;:::-;8659:66;;8774:3;8766:6;8762:16;8756:23;8734:45;;8844:2;8832:9;8824:6;8820:22;8816:31;8810:3;8799:9;8795:19;8788:60;;8871:63;8927:6;8911:14;8871:63;:::i;:::-;8857:77;;;8983:3;8975:6;8971:16;8965:23;9007:3;9019:51;9066:2;9055:9;9051:18;9035:14;7883:13;7876:21;7864:34;;7813:91;9019:51;9107:15;;9101:22;;-1:-1:-1;9132:61:3;9188:3;9173:19;;9101:22;9132:61;:::i;:::-;-1:-1:-1;9210:6:3;7909:1313;-1:-1:-1;;;7909:1313:3:o;9990:597::-;10281:6;10270:9;10263:25;10324:6;10319:2;10308:9;10304:18;10297:34;10367:3;10362:2;10351:9;10347:18;10340:31;10244:4;10388:57;10440:3;10429:9;10425:19;10417:6;10388:57;:::i;:::-;10380:65;;10481:6;10476:2;10465:9;10461:18;10454:34;-1:-1:-1;;;;;10529:6:3;10525:55;10519:3;10508:9;10504:19;10497:84;9990:597;;;;;;;;:::o;10592:127::-;10653:10;10648:3;10644:20;10641:1;10634:31;10684:4;10681:1;10674:15;10708:4;10705:1;10698:15;10724:232;10763:3;10784:17;;;10781:140;;10843:10;10838:3;10834:20;10831:1;10824:31;10878:4;10875:1;10868:15;10906:4;10903:1;10896:15;10781:140;-1:-1:-1;10948:1:3;10937:13;;10724:232::o","linkReferences":{}},"methodIdentifiers":{"adapterAddress()":"66c9aba6","emitDkgTaskEvent(uint256,uint256,uint256,uint256,uint256,address[],uint256,address)":"0fc68a0c","getControllerConfig()":"d11b8e68","getGroup(uint256)":"ceb60654","nodeRegistryAddress()":"fec10aa9","setAdapterAddress(address)":"736eede5","setCommitters(uint256,address[])":"1bb1fd28","setGroup(uint256,uint256,uint256,uint256,bool,uint256[4],address[])":"26a93abe","setMemberPartialPublicKey(uint256,uint256,uint256[4])":"6971f096"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_nodeRegistryAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"globalEpoch\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"groupIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"groupEpoch\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"members\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"assignmentBlockHeight\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"DkgTask\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"adapterAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"globalEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"groupIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"groupEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"members\",\"type\":\"address[]\"},{\"internalType\":\"uint256\",\"name\":\"assignmentBlockHeight\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"emitDkgTaskEvent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getControllerConfig\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"nodeRegistryContractAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"adapterContractAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"disqualifiedNodePenaltyAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"defaultNumberOfCommitters\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"defaultDkgPhaseDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"groupMaxCapacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"idealNumberOfGroups\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dkgPostProcessReward\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"groupIndex\",\"type\":\"uint256\"}],\"name\":\"getGroup\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nodeIdAddress\",\"type\":\"address\"},{\"internalType\":\"uint256[4]\",\"name\":\"partialPublicKey\",\"type\":\"uint256[4]\"}],\"internalType\":\"struct MockController.Member[]\",\"name\":\"members\",\"type\":\"tuple[]\"},{\"internalType\":\"address[]\",\"name\":\"committers\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"address[]\",\"name\":\"nodeIdAddress\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"groupEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256[4]\",\"name\":\"publicKey\",\"type\":\"uint256[4]\"},{\"internalType\":\"address[]\",\"name\":\"disqualifiedNodes\",\"type\":\"address[]\"}],\"internalType\":\"struct MockController.CommitResult\",\"name\":\"commitResult\",\"type\":\"tuple\"}],\"internalType\":\"struct MockController.CommitCache[]\",\"name\":\"commitCacheList\",\"type\":\"tuple[]\"},{\"internalType\":\"bool\",\"name\":\"isStrictlyMajorityConsensusReached\",\"type\":\"bool\"},{\"internalType\":\"uint256[4]\",\"name\":\"publicKey\",\"type\":\"uint256[4]\"}],\"internalType\":\"struct MockController.Group\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nodeRegistryAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_adapterAddress\",\"type\":\"address\"}],\"name\":\"setAdapterAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"groupIndex\",\"type\":\"uint256\"},{\"internalType\":\"address[]\",\"name\":\"committerAddresses\",\"type\":\"address[]\"}],\"name\":\"setCommitters\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"groupIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isStrictlyMajorityConsensusReached\",\"type\":\"bool\"},{\"internalType\":\"uint256[4]\",\"name\":\"publicKey\",\"type\":\"uint256[4]\"},{\"internalType\":\"address[]\",\"name\":\"memberAddresses\",\"type\":\"address[]\"}],\"name\":\"setGroup\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"groupIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"memberIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256[4]\",\"name\":\"partialPublicKey\",\"type\":\"uint256[4]\"}],\"name\":\"setMemberPartialPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"test/mock/MockController.sol\":\"MockController\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":300},\"remappings\":[\":Randcast-User-Contract/=lib/Randcast-User-Contract/contracts/\",\":Staking-v0.1/=lib/Staking-v0.1/src/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":fx-portal/=lib/fx-portal/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"test/mock/MockController.sol\":{\"keccak256\":\"0x75a6fd1067d50fca998bdb718afeb498b37f0d775d67f6e163c813c9bbf8f92e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d8d53cb3b18e614c692a1a9f5d73965e843efeb2ace2d61203c749040a4c71da\",\"dweb:/ipfs/QmXuyWuV2hZxFsW1HFtuAzQcd4YSrixweM2cwYf5SeKEFd\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.18+commit.87f61d96"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"_nodeRegistryAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"globalEpoch","type":"uint256","indexed":true},{"internalType":"uint256","name":"groupIndex","type":"uint256","indexed":true},{"internalType":"uint256","name":"groupEpoch","type":"uint256","indexed":true},{"internalType":"uint256","name":"size","type":"uint256","indexed":false},{"internalType":"uint256","name":"threshold","type":"uint256","indexed":false},{"internalType":"address[]","name":"members","type":"address[]","indexed":false},{"internalType":"uint256","name":"assignmentBlockHeight","type":"uint256","indexed":false},{"internalType":"address","name":"coordinatorAddress","type":"address","indexed":false}],"type":"event","name":"DkgTask","anonymous":false},{"inputs":[],"stateMutability":"view","type":"function","name":"adapterAddress","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"uint256","name":"globalEpoch","type":"uint256"},{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"uint256","name":"groupEpoch","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"address[]","name":"members","type":"address[]"},{"internalType":"uint256","name":"assignmentBlockHeight","type":"uint256"},{"internalType":"address","name":"coordinatorAddress","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"emitDkgTaskEvent"},{"inputs":[],"stateMutability":"view","type":"function","name":"getControllerConfig","outputs":[{"internalType":"address","name":"nodeRegistryContractAddress","type":"address"},{"internalType":"address","name":"adapterContractAddress","type":"address"},{"internalType":"uint256","name":"disqualifiedNodePenaltyAmount","type":"uint256"},{"internalType":"uint256","name":"defaultNumberOfCommitters","type":"uint256"},{"internalType":"uint256","name":"defaultDkgPhaseDuration","type":"uint256"},{"internalType":"uint256","name":"groupMaxCapacity","type":"uint256"},{"internalType":"uint256","name":"idealNumberOfGroups","type":"uint256"},{"internalType":"uint256","name":"dkgPostProcessReward","type":"uint256"}]},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"}],"stateMutability":"view","type":"function","name":"getGroup","outputs":[{"internalType":"struct MockController.Group","name":"","type":"tuple","components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"struct MockController.Member[]","name":"members","type":"tuple[]","components":[{"internalType":"address","name":"nodeIdAddress","type":"address"},{"internalType":"uint256[4]","name":"partialPublicKey","type":"uint256[4]"}]},{"internalType":"address[]","name":"committers","type":"address[]"},{"internalType":"struct MockController.CommitCache[]","name":"commitCacheList","type":"tuple[]","components":[{"internalType":"address[]","name":"nodeIdAddress","type":"address[]"},{"internalType":"struct MockController.CommitResult","name":"commitResult","type":"tuple","components":[{"internalType":"uint256","name":"groupEpoch","type":"uint256"},{"internalType":"uint256[4]","name":"publicKey","type":"uint256[4]"},{"internalType":"address[]","name":"disqualifiedNodes","type":"address[]"}]}]},{"internalType":"bool","name":"isStrictlyMajorityConsensusReached","type":"bool"},{"internalType":"uint256[4]","name":"publicKey","type":"uint256[4]"}]}]},{"inputs":[],"stateMutability":"view","type":"function","name":"nodeRegistryAddress","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"address","name":"_adapterAddress","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"setAdapterAddress"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"address[]","name":"committerAddresses","type":"address[]"}],"stateMutability":"nonpayable","type":"function","name":"setCommitters"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"bool","name":"isStrictlyMajorityConsensusReached","type":"bool"},{"internalType":"uint256[4]","name":"publicKey","type":"uint256[4]"},{"internalType":"address[]","name":"memberAddresses","type":"address[]"}],"stateMutability":"nonpayable","type":"function","name":"setGroup"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"uint256","name":"memberIndex","type":"uint256"},{"internalType":"uint256[4]","name":"partialPublicKey","type":"uint256[4]"}],"stateMutability":"nonpayable","type":"function","name":"setMemberPartialPublicKey"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["Randcast-User-Contract/=lib/Randcast-User-Contract/contracts/","Staking-v0.1/=lib/Staking-v0.1/src/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","fx-portal/=lib/fx-portal/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":300},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"test/mock/MockController.sol":"MockController"},"evmVersion":"paris","libraries":{}},"sources":{"test/mock/MockController.sol":{"keccak256":"0x75a6fd1067d50fca998bdb718afeb498b37f0d775d67f6e163c813c9bbf8f92e","urls":["bzz-raw://d8d53cb3b18e614c692a1a9f5d73965e843efeb2ace2d61203c749040a4c71da","dweb:/ipfs/QmXuyWuV2hZxFsW1HFtuAzQcd4YSrixweM2cwYf5SeKEFd"],"license":"MIT"}},"version":1},"id":1} \ No newline at end of file +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_nodeRegistryAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "groupEpoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "committer", + "type": "address" + } + ], + "name": "CommitDkgSuccess", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "globalEpoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "groupEpoch", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "members", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "assignmentBlockHeight", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "coordinatorAddress", + "type": "address" + } + ], + "name": "DkgTask", + "type": "event" + }, + { + "inputs": [], + "name": "adapterAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupEpoch", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "publicKey", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "partialPublicKey", + "type": "bytes" + }, + { + "internalType": "address[]", + "name": "disqualifiedNodes", + "type": "address[]" + } + ], + "internalType": "struct IController.CommitDkgParams", + "name": "params", + "type": "tuple" + } + ], + "name": "commitDkg", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "globalEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupEpoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "members", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "assignmentBlockHeight", + "type": "uint256" + }, + { + "internalType": "address", + "name": "coordinatorAddress", + "type": "address" + } + ], + "name": "emitDkgTaskEvent", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "failureMessage", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getControllerConfig", + "outputs": [ + { + "internalType": "address", + "name": "nodeRegistryContractAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "adapterContractAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "disqualifiedNodePenaltyAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "defaultNumberOfCommitters", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "defaultDkgPhaseDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupMaxCapacity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "idealNumberOfGroups", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dkgPostProcessReward", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + } + ], + "name": "getCoordinator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + } + ], + "name": "getGroup", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "nodeIdAddress", + "type": "address" + }, + { + "internalType": "uint256[4]", + "name": "partialPublicKey", + "type": "uint256[4]" + } + ], + "internalType": "struct IController.Member[]", + "name": "members", + "type": "tuple[]" + }, + { + "internalType": "address[]", + "name": "committers", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "address[]", + "name": "nodeIdAddress", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "groupEpoch", + "type": "uint256" + }, + { + "internalType": "uint256[4]", + "name": "publicKey", + "type": "uint256[4]" + }, + { + "internalType": "address[]", + "name": "disqualifiedNodes", + "type": "address[]" + } + ], + "internalType": "struct IController.CommitResult", + "name": "commitResult", + "type": "tuple" + } + ], + "internalType": "struct IController.CommitCache[]", + "name": "commitCacheList", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "isStrictlyMajorityConsensusReached", + "type": "bool" + }, + { + "internalType": "uint256[4]", + "name": "publicKey", + "type": "uint256[4]" + } + ], + "internalType": "struct IController.Group", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nodeRegistryAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_adapterAddress", + "type": "address" + } + ], + "name": "setAdapterAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "committerAddresses", + "type": "address[]" + } + ], + "name": "setCommitters", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "internalType": "address", + "name": "coordinator", + "type": "address" + } + ], + "name": "setCoordinator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "setFailureMessage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "size", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isStrictlyMajorityConsensusReached", + "type": "bool" + }, + { + "internalType": "uint256[4]", + "name": "publicKey", + "type": "uint256[4]" + }, + { + "internalType": "address[]", + "name": "memberAddresses", + "type": "address[]" + } + ], + "name": "setGroup", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "memberIndex", + "type": "uint256" + }, + { + "internalType": "uint256[4]", + "name": "partialPublicKey", + "type": "uint256[4]" + } + ], + "name": "setMemberPartialPublicKey", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_shouldSucceed", + "type": "bool" + } + ], + "name": "setShouldSucceed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "shouldSucceed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": { + "object": "0x6003805460ff60a01b1916600160a01b17905560a06040525f608090815260049061002a9082610119565b50348015610036575f5ffd5b50604051611626380380611626833981016040819052610055916101d3565b600280546001600160a01b039092166001600160a01b0319928316179055600380549091169055610200565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806100a957607f821691505b6020821081036100c757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561011457805f5260205f20601f840160051c810160208510156100f25750805b601f840160051c820191505b81811015610111575f81556001016100fe565b50505b505050565b81516001600160401b0381111561013257610132610081565b610146816101408454610095565b846100cd565b6020601f821160018114610178575f83156101615750848201515b5f19600385901b1c1916600184901b178455610111565b5f84815260208120601f198516915b828110156101a75787850151825560209485019460019092019101610187565b50848210156101c457868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f602082840312156101e3575f5ffd5b81516001600160a01b03811681146101f9575f5ffd5b9392505050565b6114198061020d5f395ff3fe608060405234801561000f575f5ffd5b50600436106100fb575f3560e01c80639e31ddb611610093578063d11b8e6811610063578063d11b8e6814610284578063e37eb96c146102d9578063e77deb2c146102ec578063fec10aa914610310575f5ffd5b80639e31ddb6146101e8578063b8c4d6ec14610214578063bb95b9d414610229578063ceb6065414610264575f5ffd5b806342424d6f116100ce57806342424d6f1461014d57806366c9aba6146101925780636971f096146101a5578063736eede5146101b8575f5ffd5b80630fc68a0c146100ff5780631bb1fd281461011457806326a93abe14610127578063368271ee1461013a575b5f5ffd5b61011261010d366004610b78565b610323565b005b610112610122366004610bfa565b61036f565b610112610135366004610cb8565b610396565b610112610148366004610d93565b6104ad565b61017561015b366004610de0565b5f908152600160205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b600354610175906001600160a01b031681565b6101126101b3366004610df7565b6104bd565b6101126101c6366004610e2a565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6101126101f6366004610e4a565b60038054911515600160a01b0260ff60a01b19909216919091179055565b61021c610505565b6040516101899190610e63565b610112610237366004610e98565b5f9182526001602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b610277610272366004610de0565b610591565b6040516101899190611024565b60025460038054604080516001600160a01b0394851681529390911660208401526103e89083015260056060830152606460808301819052600a60a084015260c083019190915260e082015261010001610189565b6101126102e73660046110f6565b610892565b60035461030090600160a01b900460ff1681565b6040519015158152602001610189565b600254610175906001600160a01b031681565b8587897fbbd25d64683f157b2e3544d3d6430e14102db1e49592cf4dcaf827e2ded517ee888888888860405161035d9594939291906111cc565b60405180910390a45050505050505050565b5f828152602081815260409091208251610391926005909201918401906108fd565b505050565b5f87815260208190526040902087815560018101879055600281018690556003810185905560078101805460ff19168515151790556103da60088201846004610960565b506103e8600482015f61098e565b5f5b825181101561048c576103fb6109af565b82600401604051806040016040528086858151811061041c5761041c61120b565b6020908102919091018101516001600160a01b0390811683529181018590528354600180820186555f95865294829020845160059092020180546001600160a01b031916919093161782558201519192909161047c918301906004610960565b5050600190920191506103ea9050565b5081516104a290600583019060208501906108fd565b505050505050505050565b60046104b982826112a2565b5050565b805f5f8581526020019081526020015f2060040183815481106104e2576104e261120b565b905f5260205f2090600502016001019060046104ff929190610960565b50505050565b600480546105129061121f565b80601f016020809104026020016040519081016040528092919081815260200182805461053e9061121f565b80156105895780601f1061056057610100808354040283529160200191610589565b820191905f5260205f20905b81548152906001019060200180831161056c57829003601f168201915b505050505081565b6105996109cd565b5f828152602081815260408083208151610120810183528154815260018201548185015260028201548184015260038201546060820152600482018054845181870281018701909552808552919592946080870194939192919084015b8282101561066e575f8481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b81548152602001906001019080831161064357505050505081525050815260200190600101906105f6565b505050508152602001600582018054806020026020016040519081016040528092919081815260200182805480156106cd57602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116106af575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020015f905b8282101561083c578382905f5260205f2090600702016040518060400160405290815f820180548060200260200160405190810160405280929190818152602001828054801561077157602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610753575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b8154815260200190600101908083116107ad57505050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801561082057602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610802575b50505050508152505081525050815260200190600101906106fa565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b81548152602001906001019080831161086f575050505050815250509050919050565b600354600160a01b900460ff166108c757600460405162461bcd60e51b81526004016108be919061135d565b60405180910390fd5b60208101518151604051339291907fb6d83871231a16b87dc25f4380b04f133cde70e9335e505a082e351eb3c0d9ec905f90a450565b828054828255905f5260205f20908101928215610950579160200282015b8281111561095057825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061091b565b5061095c929150610a1b565b5090565b8260048101928215610950579160200282015b82811115610950578251825591602001919060010190610973565b5080545f8255600502905f5260205f20908101906109ac9190610a2f565b50565b60405180608001604052806004906020820280368337509192915050565b6040518061012001604052805f81526020015f81526020015f81526020015f81526020016060815260200160608152602001606081526020015f15158152602001610a166109af565b905290565b5b8082111561095c575f8155600101610a1c565b8082111561095c5780546001600160a01b03191681555f6001820181905560028201819055600382018190556004820155600501610a2f565b634e487b7160e01b5f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715610a9f57610a9f610a68565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610ace57610ace610a68565b604052919050565b80356001600160a01b0381168114610aec575f5ffd5b919050565b5f82601f830112610b00575f5ffd5b813567ffffffffffffffff811115610b1a57610b1a610a68565b8060051b610b2a60208201610aa5565b91825260208185018101929081019086841115610b45575f5ffd5b6020860192505b83831015610b6e57610b5d83610ad6565b825260209283019290910190610b4c565b9695505050505050565b5f5f5f5f5f5f5f5f610100898b031215610b90575f5ffd5b883597506020890135965060408901359550606089013594506080890135935060a089013567ffffffffffffffff811115610bc9575f5ffd5b610bd58b828c01610af1565b93505060c08901359150610beb60e08a01610ad6565b90509295985092959890939650565b5f5f60408385031215610c0b575f5ffd5b82359150602083013567ffffffffffffffff811115610c28575f5ffd5b610c3485828601610af1565b9150509250929050565b80358015158114610aec575f5ffd5b5f82601f830112610c5c575f5ffd5b6040516080810167ffffffffffffffff81118282101715610c7f57610c7f610a68565b604052806080840185811115610c93575f5ffd5b845b81811015610cad578035835260209283019201610c95565b509195945050505050565b5f5f5f5f5f5f5f610140888a031215610ccf575f5ffd5b87359650602088013595506040880135945060608801359350610cf460808901610c3e565b9250610d038960a08a01610c4d565b915061012088013567ffffffffffffffff811115610d1f575f5ffd5b610d2b8a828b01610af1565b91505092959891949750929550565b5f5f67ffffffffffffffff841115610d5457610d54610a68565b50601f8301601f1916602001610d6981610aa5565b915050828152838383011115610d7d575f5ffd5b828260208301375f602084830101529392505050565b5f60208284031215610da3575f5ffd5b813567ffffffffffffffff811115610db9575f5ffd5b8201601f81018413610dc9575f5ffd5b610dd884823560208401610d3a565b949350505050565b5f60208284031215610df0575f5ffd5b5035919050565b5f5f5f60c08486031215610e09575f5ffd5b8335925060208401359150610e218560408601610c4d565b90509250925092565b5f60208284031215610e3a575f5ffd5b610e4382610ad6565b9392505050565b5f60208284031215610e5a575f5ffd5b610e4382610c3e565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f5f60408385031215610ea9575f5ffd5b82359150610eb960208401610ad6565b90509250929050565b805f5b60048110156104ff578151845260209384019390910190600101610ec5565b5f8151808452602084019350602083015f5b82811015610f385781516001600160a01b03815116875260208101519050610f216020880182610ec2565b5060a0959095019460209190910190600101610ef6565b5093949350505050565b5f8151808452602084019350602083015f5b82811015610f385781516001600160a01b0316865260209586019590910190600101610f54565b5f82825180855260208501945060208160051b830101602085015f5b8381101561101857601f198584030188528151805160408552610fbd6040860182610f42565b9050602082015191508481036020860152815181526020820151610fe46020830182610ec2565b506040820151915060c060a082015261100060c0820183610f42565b60209a8b019a90955093909301925050600101610f97565b50909695505050505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201525f608083015161018060a08401526110696101a0840182610ee4565b905060a0840151601f198483030160c08501526110868282610f42565b91505060c0840151601f198483030160e08501526110a48282610f7b565b91505060e08401516110bb61010085018215159052565b506101008401516110d0610120850182610ec2565b509392505050565b5f82601f8301126110e7575f5ffd5b610e4383833560208501610d3a565b5f60208284031215611106575f5ffd5b813567ffffffffffffffff81111561111c575f5ffd5b820160a0818503121561112d575f5ffd5b611135610a7c565b8135815260208083013590820152604082013567ffffffffffffffff81111561115c575f5ffd5b611168868285016110d8565b604083015250606082013567ffffffffffffffff811115611187575f5ffd5b611193868285016110d8565b606083015250608082013567ffffffffffffffff8111156111b2575f5ffd5b6111be86828501610af1565b608083015250949350505050565b85815284602082015260a060408201525f6111ea60a0830186610f42565b90508360608301526001600160a01b03831660808301529695505050505050565b634e487b7160e01b5f52603260045260245ffd5b600181811c9082168061123357607f821691505b60208210810361125157634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561039157805f5260205f20601f840160051c8101602085101561127c5750805b601f840160051c820191505b8181101561129b575f8155600101611288565b5050505050565b815167ffffffffffffffff8111156112bc576112bc610a68565b6112d0816112ca845461121f565b84611257565b6020601f821160018114611302575f83156112eb5750848201515b5f19600385901b1c1916600184901b17845561129b565b5f84815260208120601f198516915b828110156113315787850151825560209485019460019092019101611311565b508482101561134e57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b602081525f5f835461136e8161121f565b806020860152600182165f811461138c57600181146113a857610cad565b60ff1983166040870152604082151560051b8701019350610cad565b865f5260205f205f5b838110156113d0578154888201604001526001909101906020016113b1565b870160400194505050919594505050505056fea264697066735822122039425e9b1165e299360925cb358b5f3eb6d4bfeb9812485ab2275ddb65f109ea64736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f5ffd5b50600436106100fb575f3560e01c80639e31ddb611610093578063d11b8e6811610063578063d11b8e6814610284578063e37eb96c146102d9578063e77deb2c146102ec578063fec10aa914610310575f5ffd5b80639e31ddb6146101e8578063b8c4d6ec14610214578063bb95b9d414610229578063ceb6065414610264575f5ffd5b806342424d6f116100ce57806342424d6f1461014d57806366c9aba6146101925780636971f096146101a5578063736eede5146101b8575f5ffd5b80630fc68a0c146100ff5780631bb1fd281461011457806326a93abe14610127578063368271ee1461013a575b5f5ffd5b61011261010d366004610b78565b610323565b005b610112610122366004610bfa565b61036f565b610112610135366004610cb8565b610396565b610112610148366004610d93565b6104ad565b61017561015b366004610de0565b5f908152600160205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b600354610175906001600160a01b031681565b6101126101b3366004610df7565b6104bd565b6101126101c6366004610e2a565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6101126101f6366004610e4a565b60038054911515600160a01b0260ff60a01b19909216919091179055565b61021c610505565b6040516101899190610e63565b610112610237366004610e98565b5f9182526001602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b610277610272366004610de0565b610591565b6040516101899190611024565b60025460038054604080516001600160a01b0394851681529390911660208401526103e89083015260056060830152606460808301819052600a60a084015260c083019190915260e082015261010001610189565b6101126102e73660046110f6565b610892565b60035461030090600160a01b900460ff1681565b6040519015158152602001610189565b600254610175906001600160a01b031681565b8587897fbbd25d64683f157b2e3544d3d6430e14102db1e49592cf4dcaf827e2ded517ee888888888860405161035d9594939291906111cc565b60405180910390a45050505050505050565b5f828152602081815260409091208251610391926005909201918401906108fd565b505050565b5f87815260208190526040902087815560018101879055600281018690556003810185905560078101805460ff19168515151790556103da60088201846004610960565b506103e8600482015f61098e565b5f5b825181101561048c576103fb6109af565b82600401604051806040016040528086858151811061041c5761041c61120b565b6020908102919091018101516001600160a01b0390811683529181018590528354600180820186555f95865294829020845160059092020180546001600160a01b031916919093161782558201519192909161047c918301906004610960565b5050600190920191506103ea9050565b5081516104a290600583019060208501906108fd565b505050505050505050565b60046104b982826112a2565b5050565b805f5f8581526020019081526020015f2060040183815481106104e2576104e261120b565b905f5260205f2090600502016001019060046104ff929190610960565b50505050565b600480546105129061121f565b80601f016020809104026020016040519081016040528092919081815260200182805461053e9061121f565b80156105895780601f1061056057610100808354040283529160200191610589565b820191905f5260205f20905b81548152906001019060200180831161056c57829003601f168201915b505050505081565b6105996109cd565b5f828152602081815260408083208151610120810183528154815260018201548185015260028201548184015260038201546060820152600482018054845181870281018701909552808552919592946080870194939192919084015b8282101561066e575f8481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b81548152602001906001019080831161064357505050505081525050815260200190600101906105f6565b505050508152602001600582018054806020026020016040519081016040528092919081815260200182805480156106cd57602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116106af575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020015f905b8282101561083c578382905f5260205f2090600702016040518060400160405290815f820180548060200260200160405190810160405280929190818152602001828054801561077157602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610753575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b8154815260200190600101908083116107ad57505050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801561082057602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610802575b50505050508152505081525050815260200190600101906106fa565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b81548152602001906001019080831161086f575050505050815250509050919050565b600354600160a01b900460ff166108c757600460405162461bcd60e51b81526004016108be919061135d565b60405180910390fd5b60208101518151604051339291907fb6d83871231a16b87dc25f4380b04f133cde70e9335e505a082e351eb3c0d9ec905f90a450565b828054828255905f5260205f20908101928215610950579160200282015b8281111561095057825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061091b565b5061095c929150610a1b565b5090565b8260048101928215610950579160200282015b82811115610950578251825591602001919060010190610973565b5080545f8255600502905f5260205f20908101906109ac9190610a2f565b50565b60405180608001604052806004906020820280368337509192915050565b6040518061012001604052805f81526020015f81526020015f81526020015f81526020016060815260200160608152602001606081526020015f15158152602001610a166109af565b905290565b5b8082111561095c575f8155600101610a1c565b8082111561095c5780546001600160a01b03191681555f6001820181905560028201819055600382018190556004820155600501610a2f565b634e487b7160e01b5f52604160045260245ffd5b60405160a0810167ffffffffffffffff81118282101715610a9f57610a9f610a68565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610ace57610ace610a68565b604052919050565b80356001600160a01b0381168114610aec575f5ffd5b919050565b5f82601f830112610b00575f5ffd5b813567ffffffffffffffff811115610b1a57610b1a610a68565b8060051b610b2a60208201610aa5565b91825260208185018101929081019086841115610b45575f5ffd5b6020860192505b83831015610b6e57610b5d83610ad6565b825260209283019290910190610b4c565b9695505050505050565b5f5f5f5f5f5f5f5f610100898b031215610b90575f5ffd5b883597506020890135965060408901359550606089013594506080890135935060a089013567ffffffffffffffff811115610bc9575f5ffd5b610bd58b828c01610af1565b93505060c08901359150610beb60e08a01610ad6565b90509295985092959890939650565b5f5f60408385031215610c0b575f5ffd5b82359150602083013567ffffffffffffffff811115610c28575f5ffd5b610c3485828601610af1565b9150509250929050565b80358015158114610aec575f5ffd5b5f82601f830112610c5c575f5ffd5b6040516080810167ffffffffffffffff81118282101715610c7f57610c7f610a68565b604052806080840185811115610c93575f5ffd5b845b81811015610cad578035835260209283019201610c95565b509195945050505050565b5f5f5f5f5f5f5f610140888a031215610ccf575f5ffd5b87359650602088013595506040880135945060608801359350610cf460808901610c3e565b9250610d038960a08a01610c4d565b915061012088013567ffffffffffffffff811115610d1f575f5ffd5b610d2b8a828b01610af1565b91505092959891949750929550565b5f5f67ffffffffffffffff841115610d5457610d54610a68565b50601f8301601f1916602001610d6981610aa5565b915050828152838383011115610d7d575f5ffd5b828260208301375f602084830101529392505050565b5f60208284031215610da3575f5ffd5b813567ffffffffffffffff811115610db9575f5ffd5b8201601f81018413610dc9575f5ffd5b610dd884823560208401610d3a565b949350505050565b5f60208284031215610df0575f5ffd5b5035919050565b5f5f5f60c08486031215610e09575f5ffd5b8335925060208401359150610e218560408601610c4d565b90509250925092565b5f60208284031215610e3a575f5ffd5b610e4382610ad6565b9392505050565b5f60208284031215610e5a575f5ffd5b610e4382610c3e565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f5f60408385031215610ea9575f5ffd5b82359150610eb960208401610ad6565b90509250929050565b805f5b60048110156104ff578151845260209384019390910190600101610ec5565b5f8151808452602084019350602083015f5b82811015610f385781516001600160a01b03815116875260208101519050610f216020880182610ec2565b5060a0959095019460209190910190600101610ef6565b5093949350505050565b5f8151808452602084019350602083015f5b82811015610f385781516001600160a01b0316865260209586019590910190600101610f54565b5f82825180855260208501945060208160051b830101602085015f5b8381101561101857601f198584030188528151805160408552610fbd6040860182610f42565b9050602082015191508481036020860152815181526020820151610fe46020830182610ec2565b506040820151915060c060a082015261100060c0820183610f42565b60209a8b019a90955093909301925050600101610f97565b50909695505050505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201525f608083015161018060a08401526110696101a0840182610ee4565b905060a0840151601f198483030160c08501526110868282610f42565b91505060c0840151601f198483030160e08501526110a48282610f7b565b91505060e08401516110bb61010085018215159052565b506101008401516110d0610120850182610ec2565b509392505050565b5f82601f8301126110e7575f5ffd5b610e4383833560208501610d3a565b5f60208284031215611106575f5ffd5b813567ffffffffffffffff81111561111c575f5ffd5b820160a0818503121561112d575f5ffd5b611135610a7c565b8135815260208083013590820152604082013567ffffffffffffffff81111561115c575f5ffd5b611168868285016110d8565b604083015250606082013567ffffffffffffffff811115611187575f5ffd5b611193868285016110d8565b606083015250608082013567ffffffffffffffff8111156111b2575f5ffd5b6111be86828501610af1565b608083015250949350505050565b85815284602082015260a060408201525f6111ea60a0830186610f42565b90508360608301526001600160a01b03831660808301529695505050505050565b634e487b7160e01b5f52603260045260245ffd5b600181811c9082168061123357607f821691505b60208210810361125157634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561039157805f5260205f20601f840160051c8101602085101561127c5750805b601f840160051c820191505b8181101561129b575f8155600101611288565b5050505050565b815167ffffffffffffffff8111156112bc576112bc610a68565b6112d0816112ca845461121f565b84611257565b6020601f821160018114611302575f83156112eb5750848201515b5f19600385901b1c1916600184901b17845561129b565b5f84815260208120601f198516915b828110156113315787850151825560209485019460019092019101611311565b508482101561134e57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b602081525f5f835461136e8161121f565b806020860152600182165f811461138c57600181146113a857610cad565b60ff1983166040870152604082151560051b8701019350610cad565b865f5260205f205f5b838110156113d0578154888201604001526001909101906020016113b1565b870160400194505050919594505050505056fea264697066735822122039425e9b1165e299360925cb358b5f3eb6d4bfeb9812485ab2275ddb65f109ea64736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "methodIdentifiers": {}, + "metadata": {}, + "id": 1 +} diff --git a/crates/arpa-node/test-contract/MockController.sol b/crates/arpa-node/test-contract/MockController.sol index ed9ffb7..5141a5e 100644 --- a/crates/arpa-node/test-contract/MockController.sol +++ b/crates/arpa-node/test-contract/MockController.sol @@ -1,39 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -contract MockController { +import "./IController.sol"; + +contract MockController is IController { mapping(uint256 => Group) private groups; + mapping(uint256 => address) private _coordinators; address public nodeRegistryAddress; address public adapterAddress; - - struct Member { - address nodeIdAddress; - uint256[4] partialPublicKey; - } - - struct CommitResult { - uint256 groupEpoch; - uint256[4] publicKey; - address[] disqualifiedNodes; - } - - struct CommitCache { - address[] nodeIdAddress; - CommitResult commitResult; - } - - struct Group { - uint256 index; - uint256 epoch; - uint256 size; - uint256 threshold; - Member[] members; - address[] committers; - CommitCache[] commitCacheList; - bool isStrictlyMajorityConsensusReached; - uint256[4] publicKey; - } - + + bool public shouldSucceed = true; + string public failureMessage = ""; + event DkgTask( uint256 indexed globalEpoch, uint256 indexed groupIndex, @@ -44,43 +22,45 @@ contract MockController { uint256 assignmentBlockHeight, address coordinatorAddress ); - + + event CommitDkgSuccess( + uint256 indexed groupIndex, + uint256 indexed groupEpoch, + address indexed committer + ); + constructor(address _nodeRegistryAddress) { nodeRegistryAddress = _nodeRegistryAddress; adapterAddress = address(0); } - - function getControllerConfig() - external - view - returns ( - address nodeRegistryContractAddress, - address adapterContractAddress, - uint256 disqualifiedNodePenaltyAmount, - uint256 defaultNumberOfCommitters, - uint256 defaultDkgPhaseDuration, - uint256 groupMaxCapacity, - uint256 idealNumberOfGroups, - uint256 dkgPostProcessReward - ) - { + + function getControllerConfig() external view returns ( + address nodeRegistryContractAddress, + address adapterContractAddress, + uint256 disqualifiedNodePenaltyAmount, + uint256 defaultNumberOfCommitters, + uint256 defaultDkgPhaseDuration, + uint256 groupMaxCapacity, + uint256 idealNumberOfGroups, + uint256 dkgPostProcessReward + ) { return ( nodeRegistryAddress, adapterAddress, - 1000, // disqualifiedNodePenaltyAmount - 5, // defaultNumberOfCommitters - 100, // defaultDkgPhaseDuration - 10, // groupMaxCapacity - 3, // idealNumberOfGroups - 100 // dkgPostProcessReward + 1000, // disqualifiedNodePenaltyAmount + 5, // defaultNumberOfCommitters + 100, // defaultDkgPhaseDuration + 10, // groupMaxCapacity + 3, // idealNumberOfGroups + 100 // dkgPostProcessReward ); } - + function setGroup( - uint256 groupIndex, - uint256 epoch, - uint256 size, - uint256 threshold, + uint256 groupIndex, + uint256 epoch, + uint256 size, + uint256 threshold, bool isStrictlyMajorityConsensusReached, uint256[4] memory publicKey, address[] memory memberAddresses @@ -92,30 +72,46 @@ contract MockController { group.threshold = threshold; group.isStrictlyMajorityConsensusReached = isStrictlyMajorityConsensusReached; group.publicKey = publicKey; - + delete group.members; - for (uint256 i = 0; i < memberAddresses.length; i++) { + for (uint i = 0; i < memberAddresses.length; i++) { uint256[4] memory emptyPartialPublicKey; - group.members.push(Member({nodeIdAddress: memberAddresses[i], partialPublicKey: emptyPartialPublicKey})); + group.members.push(Member({ + nodeIdAddress: memberAddresses[i], + partialPublicKey: emptyPartialPublicKey + })); } - + group.committers = memberAddresses; } - - function setMemberPartialPublicKey(uint256 groupIndex, uint256 memberIndex, uint256[4] memory partialPublicKey) - external - { + + function setMemberPartialPublicKey( + uint256 groupIndex, + uint256 memberIndex, + uint256[4] memory partialPublicKey + ) external { groups[groupIndex].members[memberIndex].partialPublicKey = partialPublicKey; } - - function setCommitters(uint256 groupIndex, address[] memory committerAddresses) external { + + function setCommitters( + uint256 groupIndex, + address[] memory committerAddresses + ) external { groups[groupIndex].committers = committerAddresses; } - - function getGroup(uint256 groupIndex) public view returns (Group memory) { + + function getGroup(uint256 groupIndex) public view override(IController) returns (Group memory) { return groups[groupIndex]; } - + + function setCoordinator(uint256 groupIndex, address coordinator) external { + _coordinators[groupIndex] = coordinator; + } + + function getCoordinator(uint256 groupIndex) public view override(IController) returns (address) { + return _coordinators[groupIndex]; + } + function emitDkgTaskEvent( uint256 globalEpoch, uint256 groupIndex, @@ -127,11 +123,38 @@ contract MockController { address coordinatorAddress ) external { emit DkgTask( - globalEpoch, groupIndex, groupEpoch, size, threshold, members, assignmentBlockHeight, coordinatorAddress + globalEpoch, + groupIndex, + groupEpoch, + size, + threshold, + members, + assignmentBlockHeight, + coordinatorAddress ); } - + function setAdapterAddress(address _adapterAddress) external { adapterAddress = _adapterAddress; } -} + + function commitDkg(CommitDkgParams memory params) external override(IController) { + if (!shouldSucceed) { + revert(failureMessage); + } + + emit CommitDkgSuccess( + params.groupIndex, + params.groupEpoch, + msg.sender + ); + } + + function setShouldSucceed(bool _shouldSucceed) external { + shouldSucceed = _shouldSucceed; + } + + function setFailureMessage(string memory _message) external { + failureMessage = _message; + } +} \ No newline at end of file diff --git a/crates/arpa-node/test-contract/MockControllerRelayer.json b/crates/arpa-node/test-contract/MockControllerRelayer.json new file mode 100644 index 0000000..7aa56e8 --- /dev/null +++ b/crates/arpa-node/test-contract/MockControllerRelayer.json @@ -0,0 +1,123 @@ +{ + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "groupEpoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "committer", + "type": "address" + } + ], + "name": "GroupRelayed", + "type": "event" + }, + { + "inputs": [], + "name": "failureMessage", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + } + ], + "name": "relayGroup", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_message", + "type": "string" + } + ], + "name": "setFailureMessage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_shouldSucceed", + "type": "bool" + } + ], + "name": "setShouldSucceed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "shouldSucceed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": { + "object": "0x5f805460ff19166001908117825560a060405260809182529061002290826100cc565b5034801561002e575f5ffd5b50610186565b634e487b7160e01b5f52604160045260245ffd5b600181811c9082168061005c57607f821691505b60208210810361007a57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156100c757805f5260205f20601f840160051c810160208510156100a55750805b601f840160051c820191505b818110156100c4575f81556001016100b1565b50505b505050565b81516001600160401b038111156100e5576100e5610034565b6100f9816100f38454610048565b84610080565b6020601f82116001811461012b575f83156101145750848201515b5f19600385901b1c1916600184901b1784556100c4565b5f84815260208120601f198516915b8281101561015a578785015182556020948501946001909201910161013a565b508482101561017757868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b61051f806101935f395ff3fe608060405234801561000f575f5ffd5b5060043610610055575f3560e01c8063368271ee146100595780639e31ddb61461006e578063b8c4d6ec1461008e578063ddc393dd146100ac578063e77deb2c146100bf575b5f5ffd5b61006c6100673660046101f5565b6100db565b005b61006c61007c3660046102a8565b5f805460ff1916911515919091179055565b6100966100eb565b6040516100a391906102ce565b60405180910390f35b61006c6100ba366004610303565b610177565b5f546100cb9060ff1681565b60405190151581526020016100a3565b60016100e782826103a7565b5050565b600180546100f890610323565b80601f016020809104026020016040519081016040528092919081815260200182805461012490610323565b801561016f5780601f106101465761010080835404028352916020019161016f565b820191905f5260205f20905b81548152906001019060200180831161015257829003601f168201915b505050505081565b5f5460ff166101a457600160405162461bcd60e51b815260040161019b9190610462565b60405180910390fd5b6040516001808252339183907ff8767d2ca0028e8ef4268cfb13b6e4f8c257b781b0dc13704a0204b2ad33acf19060200160405180910390a45050565b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215610205575f5ffd5b813567ffffffffffffffff81111561021b575f5ffd5b8201601f8101841361022b575f5ffd5b803567ffffffffffffffff811115610245576102456101e1565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610274576102746101e1565b60405281815282820160200186101561028b575f5ffd5b816020840160208301375f91810160200191909152949350505050565b5f602082840312156102b8575f5ffd5b813580151581146102c7575f5ffd5b9392505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f5f60408385031215610314575f5ffd5b50508035926020909101359150565b600181811c9082168061033757607f821691505b60208210810361035557634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156103a257805f5260205f20601f840160051c810160208510156103805750805b601f840160051c820191505b8181101561039f575f815560010161038c565b50505b505050565b815167ffffffffffffffff8111156103c1576103c16101e1565b6103d5816103cf8454610323565b8461035b565b6020601f821160018114610407575f83156103f05750848201515b5f19600385901b1c1916600184901b17845561039f565b5f84815260208120601f198516915b828110156104365787850151825560209485019460019092019101610416565b508482101561045357868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b602081525f5f835461047381610323565b806020860152600182165f811461049157600181146104ad576104de565b60ff1983166040870152604082151560051b87010193506104de565b865f5260205f205f5b838110156104d5578154888201604001526001909101906020016104b6565b87016040019450505b50919594505050505056fea2646970667358221220942970d25db035be21dd107b73f5689313711cc2300e91ac3a58446e9cef943164736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f5ffd5b5060043610610055575f3560e01c8063368271ee146100595780639e31ddb61461006e578063b8c4d6ec1461008e578063ddc393dd146100ac578063e77deb2c146100bf575b5f5ffd5b61006c6100673660046101f5565b6100db565b005b61006c61007c3660046102a8565b5f805460ff1916911515919091179055565b6100966100eb565b6040516100a391906102ce565b60405180910390f35b61006c6100ba366004610303565b610177565b5f546100cb9060ff1681565b60405190151581526020016100a3565b60016100e782826103a7565b5050565b600180546100f890610323565b80601f016020809104026020016040519081016040528092919081815260200182805461012490610323565b801561016f5780601f106101465761010080835404028352916020019161016f565b820191905f5260205f20905b81548152906001019060200180831161015257829003601f168201915b505050505081565b5f5460ff166101a457600160405162461bcd60e51b815260040161019b9190610462565b60405180910390fd5b6040516001808252339183907ff8767d2ca0028e8ef4268cfb13b6e4f8c257b781b0dc13704a0204b2ad33acf19060200160405180910390a45050565b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215610205575f5ffd5b813567ffffffffffffffff81111561021b575f5ffd5b8201601f8101841361022b575f5ffd5b803567ffffffffffffffff811115610245576102456101e1565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610274576102746101e1565b60405281815282820160200186101561028b575f5ffd5b816020840160208301375f91810160200191909152949350505050565b5f602082840312156102b8575f5ffd5b813580151581146102c7575f5ffd5b9392505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f5f60408385031215610314575f5ffd5b50508035926020909101359150565b600181811c9082168061033757607f821691505b60208210810361035557634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156103a257805f5260205f20601f840160051c810160208510156103805750805b601f840160051c820191505b8181101561039f575f815560010161038c565b50505b505050565b815167ffffffffffffffff8111156103c1576103c16101e1565b6103d5816103cf8454610323565b8461035b565b6020601f821160018114610407575f83156103f05750848201515b5f19600385901b1c1916600184901b17845561039f565b5f84815260208120601f198516915b828110156104365787850151825560209485019460019092019101610416565b508482101561045357868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b602081525f5f835461047381610323565b806020860152600182165f811461049157600181146104ad576104de565b60ff1983166040870152604082151560051b87010193506104de565b865f5260205f205f5b838110156104d5578154888201604001526001909101906020016104b6565b87016040019450505b50919594505050505056fea2646970667358221220942970d25db035be21dd107b73f5689313711cc2300e91ac3a58446e9cef943164736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "methodIdentifiers": {}, + "metadata": {}, + "id": 1 +} diff --git a/crates/arpa-node/test-contract/MockControllerRelayer.sol b/crates/arpa-node/test-contract/MockControllerRelayer.sol new file mode 100644 index 0000000..e10abf7 --- /dev/null +++ b/crates/arpa-node/test-contract/MockControllerRelayer.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IControllerRelayer { + function relayGroup(uint256 chainId, uint256 groupIndex) external; +} + +contract MockControllerRelayer is IControllerRelayer { + bool public shouldSucceed = true; + string public failureMessage = ""; + + event GroupRelayed( + uint256 epoch, + uint256 indexed groupIndex, + uint256 indexed groupEpoch, + address indexed committer + ); + + constructor() {} + + function relayGroup(uint256 chainId, uint256 groupIndex) external override { + if (!shouldSucceed) { + revert(failureMessage); + } + + emit GroupRelayed( + 1, // mock epoch + groupIndex, // actual groupIndex + 1, // mock groupEpoch + msg.sender // actual committer + ); + } + + function setShouldSucceed(bool _shouldSucceed) external { + shouldSucceed = _shouldSucceed; + } + + function setFailureMessage(string memory _message) external { + failureMessage = _message; + } +} \ No newline at end of file diff --git a/crates/arpa-node/test-contract/MockCoordinator.json b/crates/arpa-node/test-contract/MockCoordinator.json new file mode 100644 index 0000000..5f862ea --- /dev/null +++ b/crates/arpa-node/test-contract/MockCoordinator.json @@ -0,0 +1,393 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_threshold", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "clearAllData", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "currentPhase", + "outputs": [ + { + "internalType": "int8", + "name": "", + "type": "int8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "dkgKeys", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "dkgThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDataStats", + "outputs": [ + { + "internalType": "uint256", + "name": "keysCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "participantsCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sharesCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "responsesCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "justificationsCount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDkgKeys", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getJustifications", + "outputs": [ + { + "internalType": "bytes[]", + "name": "", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getParticipants", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getResponses", + "outputs": [ + { + "internalType": "bytes[]", + "name": "", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getShares", + "outputs": [ + { + "internalType": "bytes[]", + "name": "", + "type": "bytes[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "inPhase", + "outputs": [ + { + "internalType": "int8", + "name": "", + "type": "int8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "justificationsData", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "participants", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "responsesData", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int8", + "name": "_phase", + "type": "int8" + } + ], + "name": "setCurrentPhase", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_threshold", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "_keys", + "type": "bytes[]" + } + ], + "name": "setDkgKeys", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "_justifications", + "type": "bytes[]" + } + ], + "name": "setJustifications", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_participants", + "type": "address[]" + } + ], + "name": "setParticipants", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "_responses", + "type": "bytes[]" + } + ], + "name": "setResponses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "_shares", + "type": "bytes[]" + } + ], + "name": "setShares", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_threshold", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "_participants", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "_keys", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "_shares", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "_responses", + "type": "bytes[]" + }, + { + "internalType": "bytes[]", + "name": "_justifications", + "type": "bytes[]" + } + ], + "name": "setupTestScenario", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "sharesData", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": { + "object": "0x60806040526006805460ff191690553480156018575f5ffd5b506040516110fb3803806110fb833981016040819052603591603b565b5f556051565b5f60208284031215604a575f5ffd5b5051919050565b61109d8061005e5f395ff3fe608060405234801561000f575f5ffd5b506004361061015b575f3560e01c80639e174653116100c3578063cc5ef00911610088578063e004af5c11610063578063e004af5c14610314578063f24e816e14610327578063fb54cde11461033a575f5ffd5b8063cc5ef009146102f1578063d6b6cf20146102f9578063d73fe0aa1461030c575f5ffd5b80639e17465314610298578063a2012097146102ab578063b0ef8179146102b3578063bfeb1f3f146102c8578063c2704024146102db575f5ffd5b806342ab089e116101235780635aa68ac0116100fe5780635aa68ac01461025d57806361e1d923146102725780636489dc9014610285575f5ffd5b806342ab089e146101ec5780634e3874a01461021057806353c0fefd14610226575f5ffd5b8063055ad42e1461015f5780630d03e7be146101825780631ab78c3e14610197578063221f9511146101b757806335c1d349146101c1575b5f5ffd5b60065461016b905f0b81565b6040515f9190910b81526020015b60405180910390f35b610195610190366004610bd3565b61034d565b005b6101aa6101a5366004610c0d565b610364565b6040516101799190610c52565b6006545f0b61016b565b6101d46101cf366004610c0d565b61040a565b6040516001600160a01b039091168152602001610179565b6101956101fa366004610c6b565b6006805460ff191660ff92909216919091179055565b610218610432565b604051610179929190610ce4565b600154600254600354600454600554604080519586526020860194909452928401919091526060830152608082015260a001610179565b61026561050f565b6040516101799190610cfc565b610195610280366004610bd3565b61056f565b6101aa610293366004610c0d565b610582565b6101956102a6366004610db6565b610591565b61019561060e565b6102bb610654565b6040516101799190610ea1565b6101956102d6366004610bd3565b610728565b6102e35f5481565b604051908152602001610179565b6102bb61073b565b610195610307366004610eb3565b610806565b6102bb610822565b610195610322366004610ef7565b6108ed565b6101aa610335366004610c0d565b610900565b6101aa610348366004610c0d565b61090f565b805161036090600390602084019061091e565b5050565b60058181548110610373575f80fd5b905f5260205f20015f91509050805461038b90610f29565b80601f01602080910402602001604051908101604052809291908181526020018280546103b790610f29565b80156104025780601f106103d957610100808354040283529160200191610402565b820191905f5260205f20905b8154815290600101906020018083116103e557829003601f168201915b505050505081565b60028181548110610419575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f60605f54600180805480602002602001604051908101604052809291908181526020015f905b82821015610501578382905f5260205f2001805461047690610f29565b80601f01602080910402602001604051908101604052809291908181526020018280546104a290610f29565b80156104ed5780601f106104c4576101008083540402835291602001916104ed565b820191905f5260205f20905b8154815290600101906020018083116104d057829003601f168201915b505050505081526020019060010190610459565b505050509050915091509091565b6060600280548060200260200160405190810160405280929190818152602001828054801561056557602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610547575b5050505050905090565b805161036090600490602084019061091e565b60038181548110610373575f80fd5b5f86905584516105a8906002906020880190610972565b5083516105bc90600190602087019061091e565b5082516105d090600390602086019061091e565b5081516105e490600490602085019061091e565b5080516105f890600590602084019061091e565b50506006805460ff191660011790555050505050565b61061960015f6109de565b61062460025f6109fc565b61062f60035f6109de565b61063a60045f6109de565b61064560055f6109de565b6006805460ff191690555f8055565b60606005805480602002602001604051908101604052809291908181526020015f905b8282101561071f578382905f5260205f2001805461069490610f29565b80601f01602080910402602001604051908101604052809291908181526020018280546106c090610f29565b801561070b5780601f106106e25761010080835404028352916020019161070b565b820191905f5260205f20905b8154815290600101906020018083116106ee57829003601f168201915b505050505081526020019060010190610677565b50505050905090565b805161036090600590602084019061091e565b60606004805480602002602001604051908101604052809291908181526020015f905b8282101561071f578382905f5260205f2001805461077b90610f29565b80601f01602080910402602001604051908101604052809291908181526020018280546107a790610f29565b80156107f25780601f106107c9576101008083540402835291602001916107f2565b820191905f5260205f20905b8154815290600101906020018083116107d557829003601f168201915b50505050508152602001906001019061075e565b5f829055805161081d90600190602084019061091e565b505050565b60606003805480602002602001604051908101604052809291908181526020015f905b8282101561071f578382905f5260205f2001805461086290610f29565b80601f016020809104026020016040519081016040528092919081815260200182805461088e90610f29565b80156108d95780601f106108b0576101008083540402835291602001916108d9565b820191905f5260205f20905b8154815290600101906020018083116108bc57829003601f168201915b505050505081526020019060010190610845565b8051610360906002906020840190610972565b60018181548110610373575f80fd5b60048181548110610373575f80fd5b828054828255905f5260205f20908101928215610962579160200282015b8281111561096257825182906109529082610fac565b509160200191906001019061093c565b5061096e929150610a17565b5090565b828054828255905f5260205f209081019282156109d2579160200282015b828111156109d2578251825473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909116178255602090920191600190910190610990565b5061096e929150610a33565b5080545f8255905f5260205f20908101906109f99190610a17565b50565b5080545f8255905f5260205f20908101906109f99190610a33565b8082111561096e575f610a2a8282610a47565b50600101610a17565b5b8082111561096e575f8155600101610a34565b508054610a5390610f29565b5f825580601f10610a62575050565b601f0160209004905f5260205f20908101906109f99190610a33565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610abb57610abb610a7e565b604052919050565b5f67ffffffffffffffff821115610adc57610adc610a7e565b5060051b60200190565b5f82601f830112610af5575f5ffd5b8135610b08610b0382610ac3565b610a92565b8082825260208201915060208360051b860101925085831115610b29575f5ffd5b602085015b83811015610bc957803567ffffffffffffffff811115610b4c575f5ffd5b8601603f81018813610b5c575f5ffd5b602081013567ffffffffffffffff811115610b7957610b79610a7e565b610b8c601f8201601f1916602001610a92565b8181526040838301018a1015610ba0575f5ffd5b816040840160208301375f60208383010152808652505050602083019250602081019050610b2e565b5095945050505050565b5f60208284031215610be3575f5ffd5b813567ffffffffffffffff811115610bf9575f5ffd5b610c0584828501610ae6565b949350505050565b5f60208284031215610c1d575f5ffd5b5035919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610c646020830184610c24565b9392505050565b5f60208284031215610c7b575f5ffd5b8135805f0b8114610c64575f5ffd5b5f82825180855260208501945060208160051b830101602085015f5b83811015610cd857601f19858403018852610cc2838351610c24565b6020988901989093509190910190600101610ca6565b50909695505050505050565b828152604060208201525f610c056040830184610c8a565b602080825282518282018190525f918401906040840190835b81811015610d3c5783516001600160a01b0316835260209384019390920191600101610d15565b509095945050505050565b5f82601f830112610d56575f5ffd5b8135610d64610b0382610ac3565b8082825260208201915060208360051b860101925085831115610d85575f5ffd5b602085015b83811015610bc95780356001600160a01b0381168114610da8575f5ffd5b835260209283019201610d8a565b5f5f5f5f5f5f60c08789031215610dcb575f5ffd5b86359550602087013567ffffffffffffffff811115610de8575f5ffd5b610df489828a01610d47565b955050604087013567ffffffffffffffff811115610e10575f5ffd5b610e1c89828a01610ae6565b945050606087013567ffffffffffffffff811115610e38575f5ffd5b610e4489828a01610ae6565b935050608087013567ffffffffffffffff811115610e60575f5ffd5b610e6c89828a01610ae6565b92505060a087013567ffffffffffffffff811115610e88575f5ffd5b610e9489828a01610ae6565b9150509295509295509295565b602081525f610c646020830184610c8a565b5f5f60408385031215610ec4575f5ffd5b82359150602083013567ffffffffffffffff811115610ee1575f5ffd5b610eed85828601610ae6565b9150509250929050565b5f60208284031215610f07575f5ffd5b813567ffffffffffffffff811115610f1d575f5ffd5b610c0584828501610d47565b600181811c90821680610f3d57607f821691505b602082108103610f5b57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561081d57805f5260205f20601f840160051c81016020851015610f865750805b601f840160051c820191505b81811015610fa5575f8155600101610f92565b5050505050565b815167ffffffffffffffff811115610fc657610fc6610a7e565b610fda81610fd48454610f29565b84610f61565b6020601f82116001811461100c575f8315610ff55750848201515b5f19600385901b1c1916600184901b178455610fa5565b5f84815260208120601f198516915b8281101561103b578785015182556020948501946001909201910161101b565b508482101561105857868401515f19600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220f5d4e2a06c139358152f64837888a161758bc0bf7f2dce8e32715815163235aa64736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f5ffd5b506004361061015b575f3560e01c80639e174653116100c3578063cc5ef00911610088578063e004af5c11610063578063e004af5c14610314578063f24e816e14610327578063fb54cde11461033a575f5ffd5b8063cc5ef009146102f1578063d6b6cf20146102f9578063d73fe0aa1461030c575f5ffd5b80639e17465314610298578063a2012097146102ab578063b0ef8179146102b3578063bfeb1f3f146102c8578063c2704024146102db575f5ffd5b806342ab089e116101235780635aa68ac0116100fe5780635aa68ac01461025d57806361e1d923146102725780636489dc9014610285575f5ffd5b806342ab089e146101ec5780634e3874a01461021057806353c0fefd14610226575f5ffd5b8063055ad42e1461015f5780630d03e7be146101825780631ab78c3e14610197578063221f9511146101b757806335c1d349146101c1575b5f5ffd5b60065461016b905f0b81565b6040515f9190910b81526020015b60405180910390f35b610195610190366004610bd3565b61034d565b005b6101aa6101a5366004610c0d565b610364565b6040516101799190610c52565b6006545f0b61016b565b6101d46101cf366004610c0d565b61040a565b6040516001600160a01b039091168152602001610179565b6101956101fa366004610c6b565b6006805460ff191660ff92909216919091179055565b610218610432565b604051610179929190610ce4565b600154600254600354600454600554604080519586526020860194909452928401919091526060830152608082015260a001610179565b61026561050f565b6040516101799190610cfc565b610195610280366004610bd3565b61056f565b6101aa610293366004610c0d565b610582565b6101956102a6366004610db6565b610591565b61019561060e565b6102bb610654565b6040516101799190610ea1565b6101956102d6366004610bd3565b610728565b6102e35f5481565b604051908152602001610179565b6102bb61073b565b610195610307366004610eb3565b610806565b6102bb610822565b610195610322366004610ef7565b6108ed565b6101aa610335366004610c0d565b610900565b6101aa610348366004610c0d565b61090f565b805161036090600390602084019061091e565b5050565b60058181548110610373575f80fd5b905f5260205f20015f91509050805461038b90610f29565b80601f01602080910402602001604051908101604052809291908181526020018280546103b790610f29565b80156104025780601f106103d957610100808354040283529160200191610402565b820191905f5260205f20905b8154815290600101906020018083116103e557829003601f168201915b505050505081565b60028181548110610419575f80fd5b5f918252602090912001546001600160a01b0316905081565b5f60605f54600180805480602002602001604051908101604052809291908181526020015f905b82821015610501578382905f5260205f2001805461047690610f29565b80601f01602080910402602001604051908101604052809291908181526020018280546104a290610f29565b80156104ed5780601f106104c4576101008083540402835291602001916104ed565b820191905f5260205f20905b8154815290600101906020018083116104d057829003601f168201915b505050505081526020019060010190610459565b505050509050915091509091565b6060600280548060200260200160405190810160405280929190818152602001828054801561056557602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610547575b5050505050905090565b805161036090600490602084019061091e565b60038181548110610373575f80fd5b5f86905584516105a8906002906020880190610972565b5083516105bc90600190602087019061091e565b5082516105d090600390602086019061091e565b5081516105e490600490602085019061091e565b5080516105f890600590602084019061091e565b50506006805460ff191660011790555050505050565b61061960015f6109de565b61062460025f6109fc565b61062f60035f6109de565b61063a60045f6109de565b61064560055f6109de565b6006805460ff191690555f8055565b60606005805480602002602001604051908101604052809291908181526020015f905b8282101561071f578382905f5260205f2001805461069490610f29565b80601f01602080910402602001604051908101604052809291908181526020018280546106c090610f29565b801561070b5780601f106106e25761010080835404028352916020019161070b565b820191905f5260205f20905b8154815290600101906020018083116106ee57829003601f168201915b505050505081526020019060010190610677565b50505050905090565b805161036090600590602084019061091e565b60606004805480602002602001604051908101604052809291908181526020015f905b8282101561071f578382905f5260205f2001805461077b90610f29565b80601f01602080910402602001604051908101604052809291908181526020018280546107a790610f29565b80156107f25780601f106107c9576101008083540402835291602001916107f2565b820191905f5260205f20905b8154815290600101906020018083116107d557829003601f168201915b50505050508152602001906001019061075e565b5f829055805161081d90600190602084019061091e565b505050565b60606003805480602002602001604051908101604052809291908181526020015f905b8282101561071f578382905f5260205f2001805461086290610f29565b80601f016020809104026020016040519081016040528092919081815260200182805461088e90610f29565b80156108d95780601f106108b0576101008083540402835291602001916108d9565b820191905f5260205f20905b8154815290600101906020018083116108bc57829003601f168201915b505050505081526020019060010190610845565b8051610360906002906020840190610972565b60018181548110610373575f80fd5b60048181548110610373575f80fd5b828054828255905f5260205f20908101928215610962579160200282015b8281111561096257825182906109529082610fac565b509160200191906001019061093c565b5061096e929150610a17565b5090565b828054828255905f5260205f209081019282156109d2579160200282015b828111156109d2578251825473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909116178255602090920191600190910190610990565b5061096e929150610a33565b5080545f8255905f5260205f20908101906109f99190610a17565b50565b5080545f8255905f5260205f20908101906109f99190610a33565b8082111561096e575f610a2a8282610a47565b50600101610a17565b5b8082111561096e575f8155600101610a34565b508054610a5390610f29565b5f825580601f10610a62575050565b601f0160209004905f5260205f20908101906109f99190610a33565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610abb57610abb610a7e565b604052919050565b5f67ffffffffffffffff821115610adc57610adc610a7e565b5060051b60200190565b5f82601f830112610af5575f5ffd5b8135610b08610b0382610ac3565b610a92565b8082825260208201915060208360051b860101925085831115610b29575f5ffd5b602085015b83811015610bc957803567ffffffffffffffff811115610b4c575f5ffd5b8601603f81018813610b5c575f5ffd5b602081013567ffffffffffffffff811115610b7957610b79610a7e565b610b8c601f8201601f1916602001610a92565b8181526040838301018a1015610ba0575f5ffd5b816040840160208301375f60208383010152808652505050602083019250602081019050610b2e565b5095945050505050565b5f60208284031215610be3575f5ffd5b813567ffffffffffffffff811115610bf9575f5ffd5b610c0584828501610ae6565b949350505050565b5f60208284031215610c1d575f5ffd5b5035919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610c646020830184610c24565b9392505050565b5f60208284031215610c7b575f5ffd5b8135805f0b8114610c64575f5ffd5b5f82825180855260208501945060208160051b830101602085015f5b83811015610cd857601f19858403018852610cc2838351610c24565b6020988901989093509190910190600101610ca6565b50909695505050505050565b828152604060208201525f610c056040830184610c8a565b602080825282518282018190525f918401906040840190835b81811015610d3c5783516001600160a01b0316835260209384019390920191600101610d15565b509095945050505050565b5f82601f830112610d56575f5ffd5b8135610d64610b0382610ac3565b8082825260208201915060208360051b860101925085831115610d85575f5ffd5b602085015b83811015610bc95780356001600160a01b0381168114610da8575f5ffd5b835260209283019201610d8a565b5f5f5f5f5f5f60c08789031215610dcb575f5ffd5b86359550602087013567ffffffffffffffff811115610de8575f5ffd5b610df489828a01610d47565b955050604087013567ffffffffffffffff811115610e10575f5ffd5b610e1c89828a01610ae6565b945050606087013567ffffffffffffffff811115610e38575f5ffd5b610e4489828a01610ae6565b935050608087013567ffffffffffffffff811115610e60575f5ffd5b610e6c89828a01610ae6565b92505060a087013567ffffffffffffffff811115610e88575f5ffd5b610e9489828a01610ae6565b9150509295509295509295565b602081525f610c646020830184610c8a565b5f5f60408385031215610ec4575f5ffd5b82359150602083013567ffffffffffffffff811115610ee1575f5ffd5b610eed85828601610ae6565b9150509250929050565b5f60208284031215610f07575f5ffd5b813567ffffffffffffffff811115610f1d575f5ffd5b610c0584828501610d47565b600181811c90821680610f3d57607f821691505b602082108103610f5b57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561081d57805f5260205f20601f840160051c81016020851015610f865750805b601f840160051c820191505b81811015610fa5575f8155600101610f92565b5050505050565b815167ffffffffffffffff811115610fc657610fc6610a7e565b610fda81610fd48454610f29565b84610f61565b6020601f82116001811461100c575f8315610ff55750848201515b5f19600385901b1c1916600184901b178455610fa5565b5f84815260208120601f198516915b8281101561103b578785015182556020948501946001909201910161101b565b508482101561105857868401515f19600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220f5d4e2a06c139358152f64837888a161758bc0bf7f2dce8e32715815163235aa64736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "methodIdentifiers": {}, + "metadata": {}, + "id": 1 +} diff --git a/crates/arpa-node/test-contract/MockCoordinator.sol b/crates/arpa-node/test-contract/MockCoordinator.sol new file mode 100644 index 0000000..14e756c --- /dev/null +++ b/crates/arpa-node/test-contract/MockCoordinator.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; + +contract MockCoordinator { + uint256 public dkgThreshold; + bytes[] public dkgKeys; + address[] public participants; + bytes[] public sharesData; + bytes[] public responsesData; + bytes[] public justificationsData; + int8 public currentPhase = 0; + + constructor(uint256 _threshold) { + dkgThreshold = _threshold; + } + + function setDkgKeys(uint256 _threshold, bytes[] memory _keys) external { + dkgThreshold = _threshold; + dkgKeys = _keys; + } + + function setParticipants(address[] memory _participants) external { + participants = _participants; + } + + function setShares(bytes[] memory _shares) external { + sharesData = _shares; + } + + function setResponses(bytes[] memory _responses) external { + responsesData = _responses; + } + + function setJustifications(bytes[] memory _justifications) external { + justificationsData = _justifications; + } + + function setCurrentPhase(int8 _phase) external { + currentPhase = _phase; + } + + function getDkgKeys() external view returns (uint256, bytes[] memory) { + return (dkgThreshold, dkgKeys); + } + + function getParticipants() external view returns (address[] memory) { + return participants; + } + + function getShares() external view returns (bytes[] memory) { + return sharesData; + } + + function getResponses() external view returns (bytes[] memory) { + return responsesData; + } + + function getJustifications() external view returns (bytes[] memory) { + return justificationsData; + } + + function inPhase() external view returns (int8) { + return currentPhase; + } + + function setupTestScenario( + uint256 _threshold, + address[] memory _participants, + bytes[] memory _keys, + bytes[] memory _shares, + bytes[] memory _responses, + bytes[] memory _justifications + ) external { + dkgThreshold = _threshold; + participants = _participants; + dkgKeys = _keys; + sharesData = _shares; + responsesData = _responses; + justificationsData = _justifications; + currentPhase = 1; + } + + function clearAllData() external { + delete dkgKeys; + delete participants; + delete sharesData; + delete responsesData; + delete justificationsData; + currentPhase = 0; + dkgThreshold = 0; + } + + function getDataStats() external view returns ( + uint256 keysCount, + uint256 participantsCount, + uint256 sharesCount, + uint256 responsesCount, + uint256 justificationsCount + ) { + return ( + dkgKeys.length, + participants.length, + sharesData.length, + responsesData.length, + justificationsData.length + ); + } +} \ No newline at end of file diff --git a/crates/arpa-node/test-contract/MockNodeRegistry.json b/crates/arpa-node/test-contract/MockNodeRegistry.json index 822bd2a..c1dc30d 100644 --- a/crates/arpa-node/test-contract/MockNodeRegistry.json +++ b/crates/arpa-node/test-contract/MockNodeRegistry.json @@ -1 +1,317 @@ -{"abi":[{"type":"function","name":"getNode","inputs":[{"name":"nodeAddress","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"tuple","internalType":"struct MockNodeRegistry.Node","components":[{"name":"idAddress","type":"address","internalType":"address"},{"name":"dkgPublicKey","type":"bytes","internalType":"bytes"},{"name":"isEigenlayerNode","type":"bool","internalType":"bool"},{"name":"state","type":"bool","internalType":"bool"},{"name":"pendingUntilBlock","type":"uint256","internalType":"uint256"}]}],"stateMutability":"view"},{"type":"function","name":"nodes","inputs":[{"name":"","type":"address","internalType":"address"}],"outputs":[{"name":"idAddress","type":"address","internalType":"address"},{"name":"dkgPublicKey","type":"bytes","internalType":"bytes"},{"name":"isEigenlayerNode","type":"bool","internalType":"bool"},{"name":"state","type":"bool","internalType":"bool"},{"name":"pendingUntilBlock","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"registerNode","inputs":[{"name":"idAddress","type":"address","internalType":"address"},{"name":"dkgPublicKey","type":"bytes","internalType":"bytes"},{"name":"isEigenlayerNode","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setNodeState","inputs":[{"name":"idAddress","type":"address","internalType":"address"},{"name":"state","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b50610759806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063189a5a1714610051578063933ff7b51461007e5780639d20904814610093578063f56f705f146100b3575b600080fd5b61006461005f3660046103ab565b6100f5565b604051610075959493929190610413565b60405180910390f35b61009161008c366004610478565b6101bd565b005b6100a66100a13660046103ab565b610276565b604051610075919061054a565b6100916100c13660046105a7565b6001600160a01b03909116600090815260208190526040902060020180549115156101000261ff0019909216919091179055565b600060208190529081526040902080546001820180546001600160a01b039092169291610121906105da565b80601f016020809104026020016040519081016040528092919081815260200182805461014d906105da565b801561019a5780601f1061016f5761010080835404028352916020019161019a565b820191906000526020600020905b81548152906001019060200180831161017d57829003601f168201915b505050506002830154600390930154919260ff8082169361010090920416915085565b6040805160a0810182526001600160a01b0385811680835260208084018781528615158587015260006060860181905260808601819052928352908290529390208251815473ffffffffffffffffffffffffffffffffffffffff19169216919091178155915190919060018201906102359082610663565b506040820151600282018054606085015115156101000261ff00199315159390931661ffff1990911617919091179055608090910151600390910155505050565b6040805160a08082018352600080835260606020808501829052848601839052908401829052608084018290526001600160a01b0386811683528282529185902085519384019095528454909116825260018401805493949293918401916102dd906105da565b80601f0160208091040260200160405190810160405280929190818152602001828054610309906105da565b80156103565780601f1061032b57610100808354040283529160200191610356565b820191906000526020600020905b81548152906001019060200180831161033957829003601f168201915b5050509183525050600282015460ff80821615156020840152610100909104161515604082015260039091015460609091015292915050565b80356001600160a01b03811681146103a657600080fd5b919050565b6000602082840312156103bd57600080fd5b6103c68261038f565b9392505050565b6000815180845260005b818110156103f3576020818501810151868301820152016103d7565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038616815260a06020820152600061043560a08301876103cd565b941515604083015250911515606083015260809091015292915050565b634e487b7160e01b600052604160045260246000fd5b803580151581146103a657600080fd5b60008060006060848603121561048d57600080fd5b6104968461038f565b9250602084013567ffffffffffffffff808211156104b357600080fd5b818601915086601f8301126104c757600080fd5b8135818111156104d9576104d9610452565b604051601f8201601f19908116603f0116810190838211818310171561050157610501610452565b8160405282815289602084870101111561051a57600080fd5b82602086016020830137600060208483010152809650505050505061054160408501610468565b90509250925092565b602081526001600160a01b0382511660208201526000602083015160a0604084015261057960c08401826103cd565b9050604084015115156060840152606084015115156080840152608084015160a08401528091505092915050565b600080604083850312156105ba57600080fd5b6105c38361038f565b91506105d160208401610468565b90509250929050565b600181811c908216806105ee57607f821691505b60208210810361060e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561065e57600081815260208120601f850160051c8101602086101561063b5750805b601f850160051c820191505b8181101561065a57828155600101610647565b5050505b505050565b815167ffffffffffffffff81111561067d5761067d610452565b6106918161068b84546105da565b84610614565b602080601f8311600181146106c657600084156106ae5750858301515b600019600386901b1c1916600185901b17855561065a565b600085815260208120601f198616915b828110156106f5578886015182559484019460019091019084016106d6565b50858210156107135787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220942266b53c23c3fad0b806424c63f5baae65c2394bbfc3a3376d10c3ede2f2dc64736f6c63430008120033","sourceMap":"57:813:2:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b506004361061004c5760003560e01c8063189a5a1714610051578063933ff7b51461007e5780639d20904814610093578063f56f705f146100b3575b600080fd5b61006461005f3660046103ab565b6100f5565b604051610075959493929190610413565b60405180910390f35b61009161008c366004610478565b6101bd565b005b6100a66100a13660046103ab565b610276565b604051610075919061054a565b6100916100c13660046105a7565b6001600160a01b03909116600090815260208190526040902060020180549115156101000261ff0019909216919091179055565b600060208190529081526040902080546001820180546001600160a01b039092169291610121906105da565b80601f016020809104026020016040519081016040528092919081815260200182805461014d906105da565b801561019a5780601f1061016f5761010080835404028352916020019161019a565b820191906000526020600020905b81548152906001019060200180831161017d57829003601f168201915b505050506002830154600390930154919260ff8082169361010090920416915085565b6040805160a0810182526001600160a01b0385811680835260208084018781528615158587015260006060860181905260808601819052928352908290529390208251815473ffffffffffffffffffffffffffffffffffffffff19169216919091178155915190919060018201906102359082610663565b506040820151600282018054606085015115156101000261ff00199315159390931661ffff1990911617919091179055608090910151600390910155505050565b6040805160a08082018352600080835260606020808501829052848601839052908401829052608084018290526001600160a01b0386811683528282529185902085519384019095528454909116825260018401805493949293918401916102dd906105da565b80601f0160208091040260200160405190810160405280929190818152602001828054610309906105da565b80156103565780601f1061032b57610100808354040283529160200191610356565b820191906000526020600020905b81548152906001019060200180831161033957829003601f168201915b5050509183525050600282015460ff80821615156020840152610100909104161515604082015260039091015460609091015292915050565b80356001600160a01b03811681146103a657600080fd5b919050565b6000602082840312156103bd57600080fd5b6103c68261038f565b9392505050565b6000815180845260005b818110156103f3576020818501810151868301820152016103d7565b506000602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038616815260a06020820152600061043560a08301876103cd565b941515604083015250911515606083015260809091015292915050565b634e487b7160e01b600052604160045260246000fd5b803580151581146103a657600080fd5b60008060006060848603121561048d57600080fd5b6104968461038f565b9250602084013567ffffffffffffffff808211156104b357600080fd5b818601915086601f8301126104c757600080fd5b8135818111156104d9576104d9610452565b604051601f8201601f19908116603f0116810190838211818310171561050157610501610452565b8160405282815289602084870101111561051a57600080fd5b82602086016020830137600060208483010152809650505050505061054160408501610468565b90509250925092565b602081526001600160a01b0382511660208201526000602083015160a0604084015261057960c08401826103cd565b9050604084015115156060840152606084015115156080840152608084015160a08401528091505092915050565b600080604083850312156105ba57600080fd5b6105c38361038f565b91506105d160208401610468565b90509250929050565b600181811c908216806105ee57607f821691505b60208210810361060e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561065e57600081815260208120601f850160051c8101602086101561063b5750805b601f850160051c820191505b8181101561065a57828155600101610647565b5050505b505050565b815167ffffffffffffffff81111561067d5761067d610452565b6106918161068b84546105da565b84610614565b602080601f8311600181146106c657600084156106ae5750858301515b600019600386901b1c1916600185901b17855561065a565b600085815260208120601f198616915b828110156106f5578886015182559484019460019091019084016106d6565b50858210156107135787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220942266b53c23c3fad0b806424c63f5baae65c2394bbfc3a3376d10c3ede2f2dc64736f6c63430008120033","sourceMap":"57:813:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89:37;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;299:334;;;;;;:::i;:::-;;:::i;:::-;;754:114;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;639:109::-;;;;;;:::i;:::-;-1:-1:-1;;;;;711:16:2;;;:5;:16;;;;;;;;;;:22;;:30;;;;;;;-1:-1:-1;;711:30:2;;;;;;;;;639:109;89:37;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;89:37:2;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;89:37:2;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;89:37:2;:::o;299:334::-;428:198;;;;;;;;-1:-1:-1;;;;;428:198:2;;;;;;;;;;;;;;;;;;;;-1:-1:-1;428:198:2;;;;;;;;;;;;409:16;;;;;;;;;;:217;;;;-1:-1:-1;;409:217:2;;;;;;;;;;;428:198;;409:16;-1:-1:-1;409:217:2;;;;;;;:::i;:::-;-1:-1:-1;409:217:2;;;;;;;;;;;;;;;;;-1:-1:-1;;409:217:2;;;;;;;-1:-1:-1;;409:217:2;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;299:334:2:o;754:114::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;843:18:2;;;;;;;;;;;;836:25;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;836:25:2;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;836:25:2;;;-1:-1:-1;;836:25:2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;754:114;-1:-1:-1;;754:114:2:o;14:196:3:-;82:20;;-1:-1:-1;;;;;131:54:3;;121:65;;111:93;;200:1;197;190:12;111:93;14:196;;;:::o;215:186::-;274:6;327:2;315:9;306:7;302:23;298:32;295:52;;;343:1;340;333:12;295:52;366:29;385:9;366:29;:::i;:::-;356:39;215:186;-1:-1:-1;;;215:186:3:o;406:422::-;447:3;485:5;479:12;512:6;507:3;500:19;537:1;547:162;561:6;558:1;555:13;547:162;;;623:4;679:13;;;675:22;;669:29;651:11;;;647:20;;640:59;576:12;547:162;;;551:3;754:1;747:4;738:6;733:3;729:16;725:27;718:38;817:4;810:2;806:7;801:2;793:6;789:15;785:29;780:3;776:39;772:50;765:57;;;406:422;;;;:::o;833:573::-;-1:-1:-1;;;;;1084:6:3;1080:55;1069:9;1062:74;1172:3;1167:2;1156:9;1152:18;1145:31;1043:4;1193:45;1233:3;1222:9;1218:19;1210:6;1193:45;:::i;:::-;1281:14;;1274:22;1269:2;1254:18;;1247:50;-1:-1:-1;1340:14:3;;1333:22;1328:2;1313:18;;1306:50;1387:3;1372:19;;;1365:35;1185:53;833:573;-1:-1:-1;;833:573:3:o;1411:127::-;1472:10;1467:3;1463:20;1460:1;1453:31;1503:4;1500:1;1493:15;1527:4;1524:1;1517:15;1543:160;1608:20;;1664:13;;1657:21;1647:32;;1637:60;;1693:1;1690;1683:12;1708:1063;1791:6;1799;1807;1860:2;1848:9;1839:7;1835:23;1831:32;1828:52;;;1876:1;1873;1866:12;1828:52;1899:29;1918:9;1899:29;:::i;:::-;1889:39;;1979:2;1968:9;1964:18;1951:32;2002:18;2043:2;2035:6;2032:14;2029:34;;;2059:1;2056;2049:12;2029:34;2097:6;2086:9;2082:22;2072:32;;2142:7;2135:4;2131:2;2127:13;2123:27;2113:55;;2164:1;2161;2154:12;2113:55;2200:2;2187:16;2222:2;2218;2215:10;2212:36;;;2228:18;;:::i;:::-;2303:2;2297:9;2271:2;2357:13;;-1:-1:-1;;2353:22:3;;;2377:2;2349:31;2345:40;2333:53;;;2401:18;;;2421:22;;;2398:46;2395:72;;;2447:18;;:::i;:::-;2487:10;2483:2;2476:22;2522:2;2514:6;2507:18;2562:7;2557:2;2552;2548;2544:11;2540:20;2537:33;2534:53;;;2583:1;2580;2573:12;2534:53;2639:2;2634;2630;2626:11;2621:2;2613:6;2609:15;2596:46;2684:1;2679:2;2674;2666:6;2662:15;2658:24;2651:35;2705:6;2695:16;;;;;;;2730:35;2761:2;2750:9;2746:18;2730:35;:::i;:::-;2720:45;;1708:1063;;;;;:::o;2776:681::-;2947:2;2936:9;2929:21;-1:-1:-1;;;;;2996:6:3;2990:13;2986:62;2981:2;2970:9;2966:18;2959:90;2910:4;3096:2;3088:6;3084:15;3078:22;3136:4;3131:2;3120:9;3116:18;3109:32;3164:51;3210:3;3199:9;3195:19;3181:12;3164:51;:::i;:::-;3150:65;;3283:2;3275:6;3271:15;3265:22;3258:30;3251:38;3246:2;3235:9;3231:18;3224:66;3359:2;3351:6;3347:15;3341:22;3334:30;3327:38;3321:3;3310:9;3306:19;3299:67;3422:3;3414:6;3410:16;3404:23;3397:4;3386:9;3382:20;3375:53;3445:6;3437:14;;;2776:681;;;;:::o;3462:254::-;3527:6;3535;3588:2;3576:9;3567:7;3563:23;3559:32;3556:52;;;3604:1;3601;3594:12;3556:52;3627:29;3646:9;3627:29;:::i;:::-;3617:39;;3675:35;3706:2;3695:9;3691:18;3675:35;:::i;:::-;3665:45;;3462:254;;;;;:::o;3721:380::-;3800:1;3796:12;;;;3843;;;3864:61;;3918:4;3910:6;3906:17;3896:27;;3864:61;3971:2;3963:6;3960:14;3940:18;3937:38;3934:161;;4017:10;4012:3;4008:20;4005:1;3998:31;4052:4;4049:1;4042:15;4080:4;4077:1;4070:15;3934:161;;3721:380;;;:::o;4231:544::-;4332:2;4327:3;4324:11;4321:448;;;4368:1;4393:5;4389:2;4382:17;4438:4;4434:2;4424:19;4508:2;4496:10;4492:19;4489:1;4485:27;4479:4;4475:38;4544:4;4532:10;4529:20;4526:47;;;-1:-1:-1;4567:4:3;4526:47;4622:2;4617:3;4613:12;4610:1;4606:20;4600:4;4596:31;4586:41;;4677:82;4695:2;4688:5;4685:13;4677:82;;;4740:17;;;4721:1;4710:13;4677:82;;;4681:3;;;4321:448;4231:544;;;:::o;4951:1348::-;5075:3;5069:10;5102:18;5094:6;5091:30;5088:56;;;5124:18;;:::i;:::-;5153:96;5242:6;5202:38;5234:4;5228:11;5202:38;:::i;:::-;5196:4;5153:96;:::i;:::-;5304:4;;5368:2;5357:14;;5385:1;5380:662;;;;6086:1;6103:6;6100:89;;;-1:-1:-1;6155:19:3;;;6149:26;6100:89;-1:-1:-1;;4908:1:3;4904:11;;;4900:24;4896:29;4886:40;4932:1;4928:11;;;4883:57;6202:81;;5350:943;;5380:662;4178:1;4171:14;;;4215:4;4202:18;;-1:-1:-1;;5416:20:3;;;5533:236;5547:7;5544:1;5541:14;5533:236;;;5636:19;;;5630:26;5615:42;;5728:27;;;;5696:1;5684:14;;;;5563:19;;5533:236;;;5537:3;5797:6;5788:7;5785:19;5782:201;;;5858:19;;;5852:26;-1:-1:-1;;5941:1:3;5937:14;;;5953:3;5933:24;5929:37;5925:42;5910:58;5895:74;;5782:201;-1:-1:-1;;;;;6029:1:3;6013:14;;;6009:22;5996:36;;-1:-1:-1;4951:1348:3:o","linkReferences":{}},"methodIdentifiers":{"getNode(address)":"9d209048","nodes(address)":"189a5a17","registerNode(address,bytes,bool)":"933ff7b5","setNodeState(address,bool)":"f56f705f"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.18+commit.87f61d96\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"nodeAddress\",\"type\":\"address\"}],\"name\":\"getNode\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"idAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"dkgPublicKey\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isEigenlayerNode\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"state\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"pendingUntilBlock\",\"type\":\"uint256\"}],\"internalType\":\"struct MockNodeRegistry.Node\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nodes\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"idAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"dkgPublicKey\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isEigenlayerNode\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"state\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"pendingUntilBlock\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"dkgPublicKey\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"isEigenlayerNode\",\"type\":\"bool\"}],\"name\":\"registerNode\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"idAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"state\",\"type\":\"bool\"}],\"name\":\"setNodeState\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"test/mock/MockNodeRegistry.sol\":\"MockNodeRegistry\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":300},\"remappings\":[\":Randcast-User-Contract/=lib/Randcast-User-Contract/contracts/\",\":Staking-v0.1/=lib/Staking-v0.1/src/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":fx-portal/=lib/fx-portal/contracts/\",\":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/\"]},\"sources\":{\"test/mock/MockNodeRegistry.sol\":{\"keccak256\":\"0xf3a00a6ae8d2a2483feebf642a046149e01ff99bed84370e45fdc0d6ddd8e09d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://17b217d6acd201674935535a6fe14f7cb9c0e47b7b4a5bbcad52b06a2472704a\",\"dweb:/ipfs/QmSYrFbboZy1N7hL2U2eWL3CZwU1FeB9AdwZNAWeAeKQci\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.18+commit.87f61d96"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"nodeAddress","type":"address"}],"stateMutability":"view","type":"function","name":"getNode","outputs":[{"internalType":"struct MockNodeRegistry.Node","name":"","type":"tuple","components":[{"internalType":"address","name":"idAddress","type":"address"},{"internalType":"bytes","name":"dkgPublicKey","type":"bytes"},{"internalType":"bool","name":"isEigenlayerNode","type":"bool"},{"internalType":"bool","name":"state","type":"bool"},{"internalType":"uint256","name":"pendingUntilBlock","type":"uint256"}]}]},{"inputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function","name":"nodes","outputs":[{"internalType":"address","name":"idAddress","type":"address"},{"internalType":"bytes","name":"dkgPublicKey","type":"bytes"},{"internalType":"bool","name":"isEigenlayerNode","type":"bool"},{"internalType":"bool","name":"state","type":"bool"},{"internalType":"uint256","name":"pendingUntilBlock","type":"uint256"}]},{"inputs":[{"internalType":"address","name":"idAddress","type":"address"},{"internalType":"bytes","name":"dkgPublicKey","type":"bytes"},{"internalType":"bool","name":"isEigenlayerNode","type":"bool"}],"stateMutability":"nonpayable","type":"function","name":"registerNode"},{"inputs":[{"internalType":"address","name":"idAddress","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"stateMutability":"nonpayable","type":"function","name":"setNodeState"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["Randcast-User-Contract/=lib/Randcast-User-Contract/contracts/","Staking-v0.1/=lib/Staking-v0.1/src/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","fx-portal/=lib/fx-portal/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/"],"optimizer":{"enabled":true,"runs":300},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"test/mock/MockNodeRegistry.sol":"MockNodeRegistry"},"evmVersion":"paris","libraries":{}},"sources":{"test/mock/MockNodeRegistry.sol":{"keccak256":"0xf3a00a6ae8d2a2483feebf642a046149e01ff99bed84370e45fdc0d6ddd8e09d","urls":["bzz-raw://17b217d6acd201674935535a6fe14f7cb9c0e47b7b4a5bbcad52b06a2472704a","dweb:/ipfs/QmSYrFbboZy1N7hL2U2eWL3CZwU1FeB9AdwZNAWeAeKQci"],"license":"MIT"}},"version":1},"id":2} \ No newline at end of file +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_controllerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stakingAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_serviceManagerAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "NodeAlreadyActive", + "type": "error" + }, + { + "inputs": [], + "name": "NodeNotRegistered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "pendingUntilBlock", + "type": "uint256" + } + ], + "name": "NodeStillPending", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "nodeAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "groupIndex", + "type": "uint256" + } + ], + "name": "NodeActivated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nodeAddress", + "type": "address" + } + ], + "name": "getNode", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "idAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "dkgPublicKey", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "isEigenlayerNode", + "type": "bool" + }, + { + "internalType": "bool", + "name": "state", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "pendingUntilBlock", + "type": "uint256" + } + ], + "internalType": "struct INodeRegistry.Node", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNodeRegistryConfig", + "outputs": [ + { + "internalType": "address", + "name": "controllerContractAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "stakingContractAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "serviceManagerContractAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nativeNodeStakingAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "eigenlayerNodeStakingAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingBlockAfterQuit", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + } + ], + "internalType": "struct ISignatureUtils.SignatureWithSaltAndExpiry", + "name": "assetAccountSignature", + "type": "tuple" + } + ], + "name": "nodeActivate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "nodes", + "outputs": [ + { + "internalType": "address", + "name": "idAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "dkgPublicKey", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "isEigenlayerNode", + "type": "bool" + }, + { + "internalType": "bool", + "name": "state", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "pendingUntilBlock", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "idAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "dkgPublicKey", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "isEigenlayerNode", + "type": "bool" + } + ], + "name": "registerNode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "idAddress", + "type": "address" + }, + { + "internalType": "bool", + "name": "state", + "type": "bool" + } + ], + "name": "setNodeState", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": { + "object": "0x608060405234801561000f575f5ffd5b50604051610a7f380380610a7f83398101604081905261002e916100e1565b6040805160c0810182526001600160a01b03948516808252938516602082018190529290941690840181905268056bc75e2d6310000060608501819052683635c9adc5dea00000608086018190526103e860a0909601869052600180546001600160a01b0319908116909617905560028054861690941790935560038054909416909117909255600491909155600555600655610121565b80516001600160a01b03811681146100dc575f5ffd5b919050565b5f5f5f606084860312156100f3575f5ffd5b6100fc846100c6565b925061010a602085016100c6565b9150610118604085016100c6565b90509250925092565b6109518061012e5f395ff3fe608060405234801561000f575f5ffd5b506004361061006f575f3560e01c80639d2090481161004d5780639d209048146100c8578063e40e744b146100e8578063f56f705f1461013b575f5ffd5b8063189a5a17146100735780638d2f3e6b146100a0578063933ff7b5146100b5575b5f5ffd5b61008661008136600461051a565b61017c565b604051610097959493929190610568565b60405180910390f35b6100b36100ae366004610645565b610241565b005b6100b36100c33660046106f5565b610331565b6100db6100d636600461051a565b6103e9565b604051610097919061074f565b600154600254600354600454600554600654604080516001600160a01b039788168152958716602087015295909316948401949094526060830152608082019290925260a081019190915260c001610097565b6100b36101493660046107ab565b6001600160a01b039091165f90815260208190526040902060020180549115156101000261ff0019909216919091179055565b5f60208190529081526040902080546001820180546001600160a01b0390921692916101a7906107dc565b80601f01602080910402602001604051908101604052809291908181526020018280546101d3906107dc565b801561021e5780601f106101f55761010080835404028352916020019161021e565b820191905f5260205f20905b81548152906001019060200180831161020157829003601f168201915b505050506002830154600390930154919260ff8082169361010090920416915085565b335f818152602081905260409020805490916001600160a01b039091161461027b576040516229eaad60e31b815260040160405180910390fd5b6002810154610100900460ff16156102a6576040516324a228bb60e21b815260040160405180910390fd5b43816003015411156102dc5780600301546040516363525acb60e11b81526004016102d391815260200190565b60405180910390fd5b60028101805461ff00191661010017905560405160019033907ffc97cd9154b40031874ef09a9436a4b60052e4dcf40f21b1258be265fac4a397906103249084815260200190565b60405180910390a2505050565b6040805160a0810182526001600160a01b038581168083526020808401878152861515858701525f6060860181905260808601819052928352908290529390208251815473ffffffffffffffffffffffffffffffffffffffff19169216919091178155915190919060018201906103a89082610860565b506040820151600282018054606085015115156101000261ff00199315159390931661ffff1990911617919091179055608090910151600390910155505050565b6040805160a080820183525f80835260606020808501829052848601839052908401829052608084018290526001600160a01b03868116835282825291859020855193840190955284549091168252600184018054939492939184019161044f906107dc565b80601f016020809104026020016040519081016040528092919081815260200182805461047b906107dc565b80156104c65780601f1061049d576101008083540402835291602001916104c6565b820191905f5260205f20905b8154815290600101906020018083116104a957829003601f168201915b5050509183525050600282015460ff80821615156020840152610100909104161515604082015260039091015460609091015292915050565b80356001600160a01b0381168114610515575f5ffd5b919050565b5f6020828403121561052a575f5ffd5b610533826104ff565b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038616815260a060208201525f61058960a083018761053a565b941515604083015250911515606083015260809091015292915050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126105c9575f5ffd5b813567ffffffffffffffff8111156105e3576105e36105a6565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610612576106126105a6565b604052818152838201602001851015610629575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60208284031215610655575f5ffd5b813567ffffffffffffffff81111561066b575f5ffd5b82016060818503121561067c575f5ffd5b6040516060810167ffffffffffffffff8111828210171561069f5761069f6105a6565b604052813567ffffffffffffffff8111156106b8575f5ffd5b6106c4868285016105ba565b8252506020820135602082015260408201356040820152809250505092915050565b80358015158114610515575f5ffd5b5f5f5f60608486031215610707575f5ffd5b610710846104ff565b9250602084013567ffffffffffffffff81111561072b575f5ffd5b610737868287016105ba565b925050610746604085016106e6565b90509250925092565b602081526001600160a01b0382511660208201525f602083015160a0604084015261077d60c084018261053a565b9050604084015115156060840152606084015115156080840152608084015160a08401528091505092915050565b5f5f604083850312156107bc575f5ffd5b6107c5836104ff565b91506107d3602084016106e6565b90509250929050565b600181811c908216806107f057607f821691505b60208210810361080e57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561085b57805f5260205f20601f840160051c810160208510156108395750805b601f840160051c820191505b81811015610858575f8155600101610845565b50505b505050565b815167ffffffffffffffff81111561087a5761087a6105a6565b61088e8161088884546107dc565b84610814565b6020601f8211600181146108c0575f83156108a95750848201515b5f19600385901b1c1916600184901b178455610858565b5f84815260208120601f198516915b828110156108ef57878501518255602094850194600190920191016108cf565b508482101561090c57868401515f19600387901b60f8161c191681555b50505050600190811b0190555056fea26469706673582212209ac785113c2664bc891e513dc9d3e6d80b78ceb911f5277bae2f300dfc42ac3c64736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x", + "sourceMap": "", + "linkReferences": {} + }, + "methodIdentifiers": {}, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"MockNodeRegistry.sol\":\"ISignatureUtils\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":300},\"remappings\":[]},\"sources\":{\"MockNodeRegistry.sol\":{\"keccak256\":\"0x4752187fb612cc3c1376603342d2fe8831599834eecf090ac7aea28dbe320cd6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://967d19c4efe9beb90747fc431523fa06c1bce4e7f68cf32d0908a4b4bffbb745\",\"dweb:/ipfs/QmcF2NPreGEoysjgGhVtKAUKfp5rWxBGfo2Rh2xwZUt5qX\"]}},\"version\":1}", + "metadata": { + "compiler": { + "version": "0.8.27+commit.40a35a09" + }, + "language": "Solidity", + "output": { + "abi": [], + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + } + }, + "settings": { + "compilationTarget": { + "MockNodeRegistry.sol": "ISignatureUtils" + }, + "evmVersion": "cancun", + "libraries": {}, + "metadata": { + "bytecodeHash": "ipfs" + }, + "optimizer": { + "enabled": true, + "runs": 300 + }, + "remappings": [] + }, + "sources": { + "MockNodeRegistry.sol": { + "keccak256": "0x4752187fb612cc3c1376603342d2fe8831599834eecf090ac7aea28dbe320cd6", + "license": "MIT", + "urls": [ + "bzz-raw://967d19c4efe9beb90747fc431523fa06c1bce4e7f68cf32d0908a4b4bffbb745", + "dweb:/ipfs/QmcF2NPreGEoysjgGhVtKAUKfp5rWxBGfo2Rh2xwZUt5qX" + ] + } + }, + "version": 1 + }, + "id": 1 +} diff --git a/crates/arpa-node/test-contract/MockNodeRegistry.sol b/crates/arpa-node/test-contract/MockNodeRegistry.sol index 2a8bf54..32ee249 100644 --- a/crates/arpa-node/test-contract/MockNodeRegistry.sol +++ b/crates/arpa-node/test-contract/MockNodeRegistry.sol @@ -1,9 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -contract MockNodeRegistry { - mapping(address => Node) public nodes; +interface ISignatureUtils { + struct SignatureWithSaltAndExpiry { + bytes signature; + bytes32 salt; + uint256 expiry; + } +} +interface INodeRegistry { struct Node { address idAddress; bytes dkgPublicKey; @@ -11,6 +17,52 @@ contract MockNodeRegistry { bool state; uint256 pendingUntilBlock; } + + function getNode(address nodeAddress) external view returns (Node memory); + function nodeActivate(ISignatureUtils.SignatureWithSaltAndExpiry memory assetAccountSignature) external; + function getNodeRegistryConfig() external view returns ( + address controllerContractAddress, + address stakingContractAddress, + address serviceManagerContractAddress, + uint256 nativeNodeStakingAmount, + uint256 eigenlayerNodeStakingAmount, + uint256 pendingBlockAfterQuit + ); +} + +contract MockNodeRegistry is INodeRegistry { + struct Config { + address controllerContractAddress; + address stakingContractAddress; + address serviceManagerContractAddress; + uint256 nativeNodeStakingAmount; + uint256 eigenlayerNodeStakingAmount; + uint256 pendingBlockAfterQuit; + } + + mapping(address => Node) public nodes; + Config private _config; + + event NodeActivated(address indexed nodeAddress, uint256 groupIndex); + + error NodeNotRegistered(); + error NodeAlreadyActive(); + error NodeStillPending(uint256 pendingUntilBlock); + + constructor( + address _controllerAddress, + address _stakingAddress, + address _serviceManagerAddress + ) { + _config = Config({ + controllerContractAddress: _controllerAddress, + stakingContractAddress: _stakingAddress, + serviceManagerContractAddress: _serviceManagerAddress, + nativeNodeStakingAmount: 100 ether, + eigenlayerNodeStakingAmount: 1000 ether, + pendingBlockAfterQuit: 1000 + }); + } function registerNode(address idAddress, bytes memory dkgPublicKey, bool isEigenlayerNode) external { nodes[idAddress] = Node({ @@ -26,7 +78,55 @@ contract MockNodeRegistry { nodes[idAddress].state = state; } - function getNode(address nodeAddress) public view returns (Node memory) { + function getNode(address nodeAddress) public view override(INodeRegistry) returns (Node memory) { return nodes[nodeAddress]; } -} + + function nodeActivate(ISignatureUtils.SignatureWithSaltAndExpiry memory assetAccountSignature) + external + override(INodeRegistry) + { + Node storage node = nodes[msg.sender]; + + if (node.idAddress != msg.sender) { + revert NodeNotRegistered(); + } + + if (node.state) { + revert NodeAlreadyActive(); + } + + if (node.pendingUntilBlock > block.number) { + revert NodeStillPending(node.pendingUntilBlock); + } + + node.state = true; + + uint256 groupIndex = 1; + + emit NodeActivated(msg.sender, groupIndex); + } + + function getNodeRegistryConfig() + public + view + override(INodeRegistry) + returns ( + address controllerContractAddress, + address stakingContractAddress, + address serviceManagerContractAddress, + uint256 nativeNodeStakingAmount, + uint256 eigenlayerNodeStakingAmount, + uint256 pendingBlockAfterQuit + ) + { + return ( + _config.controllerContractAddress, + _config.stakingContractAddress, + _config.serviceManagerContractAddress, + _config.nativeNodeStakingAmount, + _config.eigenlayerNodeStakingAmount, + _config.pendingBlockAfterQuit + ); + } +} \ No newline at end of file diff --git a/crates/arpa-node/test-contract/MockServiceManager.json b/crates/arpa-node/test-contract/MockServiceManager.json new file mode 100644 index 0000000..f8f4a6f --- /dev/null +++ b/crates/arpa-node/test-contract/MockServiceManager.json @@ -0,0 +1,111 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_avsDirectory", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "avsDirectory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": { + "object": "0x6080604052348015600e575f5ffd5b50604051610112380380610112833981016040819052602b91604e565b5f80546001600160a01b0319166001600160a01b03929092169190911790556079565b5f60208284031215605d575f5ffd5b81516001600160a01b03811681146072575f5ffd5b9392505050565b608d806100855f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c80636b3aa72e14602a575b5f5ffd5b5f54603b906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f3fea2646970667358221220436ef968b576911c4bbc003b5bd55757c61730b754b3d3c757b4fdd7ab7d1d0564736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c80636b3aa72e14602a575b5f5ffd5b5f54603b906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f3fea2646970667358221220436ef968b576911c4bbc003b5bd55757c61730b754b3d3c757b4fdd7ab7d1d0564736f6c634300081b0033", + "sourceMap": "", + "linkReferences": {} + }, + "methodIdentifiers": {}, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_avsDirectory\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"avsDirectory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"MockServiceManager.sol\":\"MockServiceManager\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":300},\"remappings\":[]},\"sources\":{\"MockServiceManager.sol\":{\"keccak256\":\"0x9c9807bf9a19b4d1d86094ea0be6b2a0829d5b0cf6840f953449788286523b3e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://62bc8ee5fa7fd899db2a87e650a41f0b3aa65d8326e2d44663909acf8344a521\",\"dweb:/ipfs/QmaXevm89unDQVfhfKCMHyVuZt6yhiPRNvs14hW2dndYYb\"]}},\"version\":1}", + "metadata": { + "compiler": { + "version": "0.8.27+commit.40a35a09" + }, + "language": "Solidity", + "output": { + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_avsDirectory", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "avsDirectory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + } + }, + "settings": { + "compilationTarget": { + "MockServiceManager.sol": "MockServiceManager" + }, + "evmVersion": "cancun", + "libraries": {}, + "metadata": { + "bytecodeHash": "ipfs" + }, + "optimizer": { + "enabled": true, + "runs": 300 + }, + "remappings": [] + }, + "sources": { + "MockServiceManager.sol": { + "keccak256": "0x9c9807bf9a19b4d1d86094ea0be6b2a0829d5b0cf6840f953449788286523b3e", + "license": "MIT", + "urls": [ + "bzz-raw://62bc8ee5fa7fd899db2a87e650a41f0b3aa65d8326e2d44663909acf8344a521", + "dweb:/ipfs/QmaXevm89unDQVfhfKCMHyVuZt6yhiPRNvs14hW2dndYYb" + ] + } + }, + "version": 1 + }, + "id": 1 +} diff --git a/crates/arpa-node/test-contract/MockServiceManager.sol b/crates/arpa-node/test-contract/MockServiceManager.sol new file mode 100644 index 0000000..1d68adb --- /dev/null +++ b/crates/arpa-node/test-contract/MockServiceManager.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract MockServiceManager { + address public avsDirectory; + + constructor(address _avsDirectory) { + avsDirectory = _avsDirectory; + } +} \ No newline at end of file