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