eigen_services_blsaggregation/lib.rs
1//! BLS Agreggation Service crate.
2//! # BLS Aggregation Service
3//!
4//! ## Introduction
5//!
6//! The BLS Aggregation Service provides functionality to aggregate BLS signatures from multiple operators into a single aggregated signature. This is used by the Aggregator to verify the signatures of the operators and send the aggregated response once the quorum is reached or time expires. AVS developers can use it to define and manage tasks, set quorum requirements and integrate aggregated results into their smart contracts.
7//!
8//! ## Key Features
9//!
10//! - **BLS Signature Aggregation**: Combines multiple individual signatures into a single verifiable aggregated signature.
11//! - **Quorum Verification**: Ensures that the required participation threshold is reached for each quorum.
12//! - **Task Management**: Allows initializing tasks and processing signatures for those tasks.
13//! - **Configurable Time Window**: Allows defining waiting periods for signature collection.
14//!
15//! ## Main Components
16//!
17//! - [`TaskMetadata`]: Defines task parameters, including quorums and thresholds.
18//! - [`TaskSignature`]: Contains an individual BLS signature for a specific task.
19//! - [`ServiceHandle`]: Interface for sending tasks and signatures to the service.
20//! - [`AggregateReceiver`]: Channel for receiving aggregated responses.
21//! - [`BlsAggregatorService`]: The main service that manages tasks and aggregates signatures.
22//!
23//! ## Usage
24//!
25//! When you initialize the BLS Aggregation Service, it returns a tuple of [`ServiceHandle`] and [`AggregateReceiver`]. The `ServiceHandle` is used to interact with the service. The available messages to send to the service are:
26//!
27//! - [`initialize_task(metadata: TaskMetadata)`]: Initializes a new task. If you want to set a time to expiry for the task, you can use the [`with_window_duration()`] method in a builder pattern.
28//! - [`process_signature(task_signature: TaskSignature)`]: Processes a signature for a task
29//!
30//! The `AggregateReceiver` is used to receive aggregated responses from the service. To get the aggregated response, you can use the [`receive_aggregated_response()`] method.
31//!
32//! Once a task is initialized, the service will start processing the task in a loop in the background. The service will wait for the quorum to be reached or the time to expire. Once the quorum is reached or the time expires, the service will aggregate the signatures and send the aggregated response to the `AggregateReceiver`.
33//!
34//! ### Initialize the Service
35//!
36//! ```rust,no_run
37//! # use eigen_services_blsaggregation::bls_agg::{
38//! # AggregateReceiver, BlsAggregatorService, TaskMetadata, TaskSignature
39//! # };
40//! # use eigen_client_avsregistry::{
41//! # reader::AvsRegistryChainReader, writer::AvsRegistryChainWriter,
42//! # };
43//! # use eigen_services_avsregistry::chaincaller::AvsRegistryServiceChainCaller;
44//! # use eigen_services_avsregistry::AvsRegistryService;
45//! # use eigen_logging::get_test_logger;
46//! # use eigen_testing_utils::{
47//! # anvil_constants::{
48//! # get_operator_state_retriever_address, get_registry_coordinator_address,
49//! # },
50//! # };
51//! # use eigen_services_operatorsinfo::operatorsinfo_inmemory::OperatorInfoServiceInMemory;
52//! # #[tokio::main]
53//! # async fn main() {
54//! # let http_endpoint = "http://localhost:8545";
55//! # let ws_endpoint = "ws://localhost:8546";
56//! # let logger = get_test_logger();
57//! # let registry_coordinator_address =
58//! # get_registry_coordinator_address(http_endpoint.to_string()).await;
59//! # let operator_state_retriever_address =
60//! # get_operator_state_retriever_address(http_endpoint.to_string()).await;
61//! #
62//! # // Create avs clients to interact with contracts deployed on anvil
63//! # let avs_registry_reader = AvsRegistryChainReader::new(
64//! # get_test_logger(),
65//! # registry_coordinator_address,
66//! # operator_state_retriever_address,
67//! # http_endpoint.to_string(),
68//! # )
69//! # .await
70//! # .unwrap();
71//! #
72//! # // Create operators info service
73//! # let operators_info = OperatorInfoServiceInMemory::new(
74//! # get_test_logger(),
75//! # avs_registry_reader.clone(),
76//! # ws_endpoint.to_string(),
77//! # )
78//! # .await
79//! # .unwrap()
80//! # .0;
81//! #
82//! # // Create avs registry service chain caller
83//! # let avs_registry_service =
84//! # AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info);
85//! let (service_handle, mut aggregate_receiver) =
86//! BlsAggregatorService::new(avs_registry_service, logger).start();
87//! # }
88//! ```
89//!
90//! ### Initialize a Task
91//!
92//! ```rust,no_run
93//! # use eigen_services_blsaggregation::bls_agg::{
94//! # AggregateReceiver, BlsAggregatorService, TaskMetadata, TaskSignature
95//! # };
96//! # use eigen_client_avsregistry::{
97//! # reader::AvsRegistryChainReader, writer::AvsRegistryChainWriter,
98//! # };
99//! # use eigen_services_avsregistry::chaincaller::AvsRegistryServiceChainCaller;
100//! # use eigen_services_avsregistry::AvsRegistryService;
101//! # use eigen_logging::get_test_logger;
102//! # use eigen_testing_utils::{
103//! # anvil_constants::{
104//! # get_operator_state_retriever_address, get_registry_coordinator_address,
105//! # },
106//! # };
107//! # use eigen_services_operatorsinfo::operatorsinfo_inmemory::OperatorInfoServiceInMemory;
108//! # use std::time::Duration;
109//! # use eigen_testing_utils::anvil_constants::{ANVIL_HTTP_URL, ANVIL_WS_URL};
110//! # #[tokio::main]
111//! # async fn main() {
112//! # let http_endpoint = ANVIL_HTTP_URL;
113//! # let ws_endpoint = ANVIL_WS_URL;
114//! # let logger = get_test_logger();
115//! # let registry_coordinator_address =
116//! # get_registry_coordinator_address(http_endpoint.to_string()).await;
117//! # let operator_state_retriever_address =
118//! # get_operator_state_retriever_address(http_endpoint.to_string()).await;
119//! #
120//! # // Create avs clients to interact with contracts deployed on anvil
121//! # let avs_registry_reader = AvsRegistryChainReader::new(
122//! # get_test_logger(),
123//! # registry_coordinator_address,
124//! # operator_state_retriever_address,
125//! # http_endpoint.to_string(),
126//! # )
127//! # .await
128//! # .unwrap();
129//! #
130//! # // Create operators info service
131//! # let operators_info = OperatorInfoServiceInMemory::new(
132//! # get_test_logger(),
133//! # avs_registry_reader.clone(),
134//! # ws_endpoint.to_string(),
135//! # )
136//! # .await
137//! # .unwrap()
138//! # .0;
139//! #
140//! # // Create avs registry service chain caller
141//! # let avs_registry_service =
142//! # AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info);
143//! # let (service_handle, mut aggregate_receiver) =
144//! # BlsAggregatorService::new(avs_registry_service, logger).start();
145//! #
146//! # let task_index = 0;
147//! # let block_number = 1;
148//! # let quorum_numbers = vec![0];
149//! # let quorum_threshold_percentages = vec![100];
150//! # let time_to_expiry = Duration::from_secs(60);
151//! #
152//! let metadata = TaskMetadata::new(
153//! task_index,
154//! block_number,
155//! quorum_numbers,
156//! quorum_threshold_percentages,
157//! time_to_expiry,
158//! );
159//! service_handle.initialize_task(metadata).await.unwrap();
160//! # }
161//! ```
162//!
163//! ### Process a Signature
164//!
165//! ```rust,no_run
166//! # use eigen_services_blsaggregation::bls_agg::{
167//! # BlsAggregatorService, TaskSignature
168//! # };
169//! # use eigen_client_avsregistry::{
170//! # reader::AvsRegistryChainReader, writer::AvsRegistryChainWriter,
171//! # };
172//! # use eigen_services_avsregistry::chaincaller::AvsRegistryServiceChainCaller;
173//! # use eigen_services_avsregistry::AvsRegistryService;
174//! # use eigen_logging::get_test_logger;
175//! # use eigen_testing_utils::{
176//! # anvil_constants::{
177//! # get_operator_state_retriever_address, get_registry_coordinator_address,
178//! # },
179//! # };
180//! # use eigen_services_operatorsinfo::operatorsinfo_inmemory::OperatorInfoServiceInMemory;
181//! # use sha2::{Digest, Sha256};
182//! # use alloy::primitives::{B256, FixedBytes};
183//! # use eigen_crypto_bls::BlsKeyPair;
184//! # use eigen_testing_utils::anvil_constants::{ANVIL_HTTP_URL, ANVIL_WS_URL, OPERATOR_BLS_KEY};
185//! # #[tokio::main]
186//! # async fn main() {
187//! # let http_endpoint = ANVIL_HTTP_URL;
188//! # let ws_endpoint = ANVIL_WS_URL;
189//! # let logger = get_test_logger();
190//! # let registry_coordinator_address =
191//! # get_registry_coordinator_address(http_endpoint.to_string()).await;
192//! # let operator_state_retriever_address =
193//! # get_operator_state_retriever_address(http_endpoint.to_string()).await;
194//! #
195//! # // Create avs clients to interact with contracts deployed on anvil
196//! # let avs_registry_reader = AvsRegistryChainReader::new(
197//! # get_test_logger(),
198//! # registry_coordinator_address,
199//! # operator_state_retriever_address,
200//! # http_endpoint.to_string(),
201//! # )
202//! # .await
203//! # .unwrap();
204//! #
205//! # // Create operators info service
206//! # let operators_info = OperatorInfoServiceInMemory::new(
207//! # get_test_logger(),
208//! # avs_registry_reader.clone(),
209//! # ws_endpoint.to_string(),
210//! # )
211//! # .await
212//! # .unwrap()
213//! # .0;
214//! #
215//! # // Create avs registry service chain caller
216//! # let avs_registry_service =
217//! # AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info);
218//! # let (service_handle, mut aggregate_receiver) =
219//! # BlsAggregatorService::new(avs_registry_service, logger).start();
220//! #
221//! # let task_index = 0;
222//! # let task_response: u64 = 123;
223//! # let mut hasher = Sha256::new();
224//! # hasher.update(task_response.to_be_bytes());
225//! # let task_response_digest = B256::from_slice(hasher.finalize().as_ref());
226//! # let bls_key_pair = BlsKeyPair::new(OPERATOR_BLS_KEY.to_string()).unwrap();
227//! # let bls_signature = bls_key_pair.sign_message(task_response_digest.as_ref());
228//! # let operator_id = FixedBytes::from_slice(&[1]);
229//! #
230//! let task_signature = TaskSignature::new(
231//! task_index,
232//! task_response_digest,
233//! bls_signature,
234//! operator_id,
235//! );
236//! service_handle.process_signature(task_signature).await.unwrap();
237//! # }
238//! ```
239//!
240//! ### Receive an Aggregated Response
241//!
242//! ```rust,no_run
243//! # use eigen_services_blsaggregation::bls_agg::BlsAggregatorService;
244//! # use eigen_client_avsregistry::{
245//! # reader::AvsRegistryChainReader, writer::AvsRegistryChainWriter,
246//! # };
247//! # use eigen_services_avsregistry::chaincaller::AvsRegistryServiceChainCaller;
248//! # use eigen_services_avsregistry::AvsRegistryService;
249//! # use eigen_logging::get_test_logger;
250//! # use eigen_testing_utils::{
251//! # anvil_constants::{
252//! # get_operator_state_retriever_address, get_registry_coordinator_address,
253//! # },
254//! # };
255//! # use eigen_services_operatorsinfo::operatorsinfo_inmemory::OperatorInfoServiceInMemory;
256//! # use eigen_testing_utils::anvil_constants::{ANVIL_HTTP_URL, ANVIL_WS_URL};
257//! # #[tokio::main]
258//! # async fn main() {
259//! # let http_endpoint = ANVIL_HTTP_URL;
260//! # let ws_endpoint = ANVIL_WS_URL;
261//! # let logger = get_test_logger();
262//! # let registry_coordinator_address =
263//! # get_registry_coordinator_address(http_endpoint.to_string()).await;
264//! # let operator_state_retriever_address =
265//! # get_operator_state_retriever_address(http_endpoint.to_string()).await;
266//! #
267//! # // Create avs clients to interact with contracts deployed on anvil
268//! # let avs_registry_reader = AvsRegistryChainReader::new(
269//! # get_test_logger(),
270//! # registry_coordinator_address,
271//! # operator_state_retriever_address,
272//! # http_endpoint.to_string(),
273//! # )
274//! # .await
275//! # .unwrap();
276//! #
277//! # // Create operators info service
278//! # let operators_info = OperatorInfoServiceInMemory::new(
279//! # get_test_logger(),
280//! # avs_registry_reader.clone(),
281//! # ws_endpoint.to_string(),
282//! # )
283//! # .await
284//! # .unwrap()
285//! # .0;
286//! #
287//! # // Create avs registry service chain caller
288//! # let avs_registry_service =
289//! # AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info);
290//! # let (service_handle, mut aggregate_receiver) =
291//! # BlsAggregatorService::new(avs_registry_service, logger).start();
292//! #
293//! match aggregate_receiver.receive_aggregated_response().await {
294//! Ok(aggregated_response) => {
295//! // Handle the aggregated response
296//! }
297//! Err(e) => {
298//! // Handle the error
299//! }
300//! }
301//! # }
302//! ```
303//!
304//! ## Example Diagram
305//!
306//! The following diagram shows the sequence of events when a user creates the BLS Aggregator Service, starts the service, and then initializes a task. The service processes two signatures from the operators and then aggregates them into a single aggregated signature.
307//!
308//! <pre>
309#![cfg_attr(doc, doc = simple_mermaid::mermaid!("../diagram/sequence-bls.mmd"))]
310//! </pre>
311//!
312//! ## Testing
313//!
314//! To run the [integration tests](https://github.com/Layr-Labs/eigensdk-rs/blob/dev/crates/services/bls_aggregation/src/bls_agg_test.rs), you can use the following command:
315//!
316//! ```sh
317//! cargo test --package eigen-services-blsaggregation --lib -- bls_agg_test::integration_test --show-output
318//! ```
319//! [`new()`]: bls_agg::BlsAggregatorService::new()
320//! [`start()`]: bls_agg::BlsAggregatorService::start()
321//! [`initialize_task(metadata: TaskMetadata)`]: bls_agg::ServiceHandle::initialize_task()
322//! [`process_signature(task_signature: TaskSignature)`]: bls_agg::ServiceHandle::process_signature()
323//! [`receive_aggregated_response()`]: bls_agg::AggregateReceiver::receive_aggregated_response()
324//! [`with_window_duration()`]: bls_agg::TaskMetadata::with_window_duration()
325//! [`ServiceHandle`]: bls_agg::ServiceHandle
326//! [`AggregateReceiver`]: bls_agg::AggregateReceiver
327//! [`TaskMetadata`]: bls_agg::TaskMetadata
328//! [`TaskSignature`]: bls_agg::TaskSignature
329//! [`BlsAggregatorService`]: bls_agg::BlsAggregatorService
330#![doc(
331 html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5",
332 issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/"
333)]
334
335pub mod bls_agg;
336mod bls_agg_test;
337pub mod bls_aggregation_service_error;
338pub mod bls_aggregation_service_response;