diff --git a/Makefile b/Makefile
index 58b79e17f..8165fa73f 100644
--- a/Makefile
+++ b/Makefile
@@ -1092,6 +1092,20 @@ ansible_batcher_deploy: ## Deploy the Batcher. Parameters: INVENTORY, KEYSTORE
-i $(INVENTORY) \
-e "keystore_path=$(KEYSTORE)"
+ansible_aggregator_create_env: ## Create empty variables files for the Aggregator deploy
+ @cp -n infra/ansible/playbooks/ini/config-aggregator.ini.example infra/ansible/playbooks/ini/config-aggregator.ini
+ @echo "Config files for the Aggregator created in infra/ansible/playbooks/ini"
+ @echo "Please complete the values and run make ansible_aggregator_deploy"
+
+ansible_aggregator_deploy: ## Deploy the Operator. Parameters: INVENTORY
+ @if [ -z "$(INVENTORY)" ] || [ -z "$(ECDSA_KEYSTORE)" ] || [ -z "$(BLS_KEYSTORE)" ]; then \
+ echo "Error: INVENTORY, ECDSA_KEYSTORE, BLS_KEYSTORE must be set."; \
+ exit 1; \
+ fi
+ @ansible-playbook infra/ansible/playbooks/aggregator.yaml \
+ -i $(INVENTORY) \
+ -e "ecdsa_keystore_path=$(ECDSA_KEYSTORE)" \
+ -e "bls_keystore_path=$(BLS_KEYSTORE)"
ansible_operator_create_env: ## Create empty variables files for the Operator deploy
@cp -n infra/ansible/playbooks/ini/config-operator.ini.example infra/ansible/playbooks/ini/config-operator.ini
diff --git a/infra/ansible/README.md b/infra/ansible/README.md
index b3e59ac01..806b3fe90 100644
--- a/infra/ansible/README.md
+++ b/infra/ansible/README.md
@@ -70,7 +70,6 @@ make ansible_batcher_deploy INVENTORY= KEYSTORE= [!CAUTION]
> To register the Operator in Aligned successfully, you need to have been whitelisted by the Aligned team previously.
-
To deploy the Operator you need to set some variables and then run the Operator playbook.
Create the variables files:
@@ -86,18 +85,17 @@ This will create the following files in `infra/ansible/playbooks/ini`:
The `config-register-operator.ini` contains the variables to register the Operator in EigenLayer:
-| Variable | Description | Stage | Testnet | Mainnet |
-|-------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|
-| address | ECDSA address of the Operator | | | |
-| metadata_url | Operator Metadata. You can create one following this [guide](https://docs.eigenlayer.xyz/eigenlayer/operator-guides/operator-installation#operator-configuration-and-registration) | | | |
-| el_delegation_manager_address | Delegation Manager Address | `0xA44151489861Fe9e3055d95adC98FbD462B948e7` | `0xA44151489861Fe9e3055d95adC98FbD462B948e7` | TBD |
-| eth_rpc_url | HTTP RPC url | `https://ethereum-holesky-rpc.publicnode.com` | `https://ethereum-holesky-rpc.publicnode.com` | `https://ethereum-rpc.publicnode.com` |
-| private_key_store_path | Path to the ECDSA keystore in the Operator host | `/home/app/.keystores/operator.ecdsa` | `/home/app/.keystores/operator.ecdsa` | `/home/app/.keystores/operator.ecdsa` |
-| private_key_store_password | Password of the ECDSA keystore | | | |
-| chain_id | Chain ID | 17000 | 17000 | 1 |
-| weth_address | Address of wETH token | [0x94373a4919B3240D86eA41593D5eBa789FEF3848](https://holesky.etherscan.io/address/0x94373a4919B3240D86eA41593D5eBa789FEF3848) | [0x94373a4919B3240D86eA41593D5eBa789FEF3848](https://holesky.etherscan.io/address/0x94373a4919B3240D86eA41593D5eBa789FEF3848) | TBD |
-| weth_strategy_address | Address of wETH token strategy | [0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9](https://holesky.eigenlayer.xyz/restake/WETH) | [0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9](https://holesky.eigenlayer.xyz/restake/WETH) | TBD |
-
+| Variable | Description | Stage | Testnet | Mainnet |
+|-------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------|
+| address | ECDSA address of the Operator | | | |
+| metadata_url | Operator Metadata. You can create one following this [guide](https://docs.eigenlayer.xyz/eigenlayer/operator-guides/operator-installation#operator-configuration-and-registration) | | | |
+| el_delegation_manager_address | Delegation Manager Address | `0xA44151489861Fe9e3055d95adC98FbD462B948e7` | `0xA44151489861Fe9e3055d95adC98FbD462B948e7` | TBD |
+| eth_rpc_url | HTTP RPC url | `https://ethereum-holesky-rpc.publicnode.com` | `https://ethereum-holesky-rpc.publicnode.com` | `https://ethereum-rpc.publicnode.com` |
+| private_key_store_path | Path to the ECDSA keystore in the Operator host | `/home/app/.keystores/operator.ecdsa` | `/home/app/.keystores/operator.ecdsa` | `/home/app/.keystores/operator.ecdsa` |
+| private_key_store_password | Password of the ECDSA keystore | | | |
+| chain_id | Chain ID | 17000 | 17000 | 1 |
+| weth_address | Address of wETH token | [0x94373a4919B3240D86eA41593D5eBa789FEF3848](https://holesky.etherscan.io/address/0x94373a4919B3240D86eA41593D5eBa789FEF3848) | [0x94373a4919B3240D86eA41593D5eBa789FEF3848](https://holesky.etherscan.io/address/0x94373a4919B3240D86eA41593D5eBa789FEF3848) | TBD |
+| weth_strategy_address | Address of wETH token strategy | [0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9](https://holesky.eigenlayer.xyz/restake/WETH) | [0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9](https://holesky.eigenlayer.xyz/restake/WETH) | TBD |
The `config-operator.ini` contains the variables to run the Operator in Aligned:
@@ -121,17 +119,53 @@ The `config-operator.ini` contains the variables to run the Operator in Aligned:
| metrics_ip_port_address | Where to expose prometheus metrics if enabled | `localhost:9092` | `localhost:9092` | `localhost:9092` |
| last_processed_batch_filepath | Where to store the last processed batch for system recovery | `/home/app/operator.last_processed_batch.json` | `/home/app/operator.last_processed_batch.json` | `/home/app/operator.last_processed_batch.json` |
-
Deploy the Operator:
```shell
make ansible_operator_deploy INVENTORY= ECDSA_KEYSTORE= BLS_KEYSTORE=
```
+## Aggregator
+
+> [!IMPORTANT]
+> You need to have previously created an ECDSA keystore with at least 1ETH and a BLS keystore.
+> You can create keystore following this [guide](#How-to-Create-Keystores)
+
+To deploy the Aggregator you need to set some variables and then run the Aggregator playbook
+
+This will create the following file in `infra/ansible/playbooks/ini`:
+
+```shell
+make ansible_aggregator_create_env
+```
+- `config-aggregator.ini`
+
+The `config-aggregator.ini` contains the variables to run the Operator in Aligned:
+
+| Variable | Description | Stage | Testnet | Mainnet |
+|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
+| aligned_layer_deployment_config_file_path | JSON with Aligned contracts addresses | `/home/app/repos/aggregator/aligned_layer/contracts/script/output/holesky/alignedlayer_deployment_output.stage.json` | `/home/app/repos/aggregator/aligned_layer/contracts/script/output/holesky/alignedlayer_deployment_output.json` | TBD |
+| eigen_layer_deployment_config_file_path | JSON with EigenLayer contracts addresses | `/home/app/repos/aggregator/aligned_layer/contracts/script/output/holesky/eigenlayer_deployment_output.json` | `/home/app/repos/aggregator/aligned_layer/contracts/script/output/holesky/eigenlayer_deployment_output.json` | TBD |
+| eth_rpc_url | HTTP RPC url | | | |
+| eth_rpc_url_fallback | HTTP RPC fallback url. Must be different than `eth_rpc_url` | `https://ethereum-holesky-rpc.publicnode.com` | `https://ethereum-holesky-rpc.publicnode.com` | `https://ethereum-rpc.publicnode.com` |
+| eth_ws_url | WS RPC url | | your_rpc_ws_provider> | |
+| eth_ws_url_fallback | WS RPC fallback url. Must be different than `eth_ws_rpc_url` | `wss://ethereum-holesky-rpc.publicnode.com` | `wss://ethereum-holesky-rpc.publicnode.com` | `wss://ethereum-rpc.publicnode.com` |
+| ecdsa_private_key_store_path | Path to the ECDSA keystore in the Operator host | `/home/app/.keystores/aggregator.ecdsa` | `/home/app/.keystores/aggregator.ecdsa` | `/home/app/.keystores/operator.ecdsa` |
+| ecdsa_private_key_store_password | Password of the ECDSA keystore | | | |
+| bls_private_key_store_path | Path to the BLS keystore in the Operator host | `/home/app/.keystores/aggregator.bls` | `/home/app/.keystores/aggregator.bls` | `/home/app/.keystores/operator.bls` |
+| bls_private_key_store_password | Password of the BLS keystore | | | |
+| enable_metrics | Expose or not prometheus metrics | `true` | `true` | `true` |
+| metrics_ip_port_address | Where to expose prometheus metrics if enabled | `localhost:9092` | `localhost:9092` | `localhost:9092` |
+| telemetry_ip_port_address | Where to send telemetry traces | `100.73.98.8:4001` | `100.91.67.33:4001` | TBD |
+
+Deploy the Aggregator:
+
+```shell
+make ansible_aggregator_deploy INVENTORY= ECDSA_KEYSTORE= BLS_KEYSTORE=
+```
> [!Note]
> ECDSA_KEYSTORE and BLS_KEYSTORE are the paths of the keystores in your machine.
-
# How to Create Keystores
## Create ECDSA Keystore
@@ -196,7 +230,6 @@ Ethereum Address: 0x...
Refer to this link for more details about keystore creation https://docs.eigenlayer.xyz/eigenlayer/operator-guides/operator-installation#create-keys
-
## Create BLS Keystore
Make sure you have installed:
@@ -227,10 +260,9 @@ BLS Private Key (Hex):
And then,
```
-
Key location: $HOME/.eigenlayer/operator_keys/.bls.key.json
Public Key: E([...,...])
-
```
Refer to this link for more details about keystore creation https://docs.eigenlayer.xyz/eigenlayer/operator-guides/operator-installation#create-keys
+
diff --git a/infra/ansible/playbooks/aggregator.yaml b/infra/ansible/playbooks/aggregator.yaml
new file mode 100644
index 000000000..599f6e76e
--- /dev/null
+++ b/infra/ansible/playbooks/aggregator.yaml
@@ -0,0 +1,116 @@
+- name: Run setup playbook
+ ansible.builtin.import_playbook: setup.yaml
+ vars:
+ host: aggregator
+
+- name: Run go playbook
+ ansible.builtin.import_playbook: go.yaml
+ vars:
+ host: aggregator
+
+- hosts: aggregator
+ vars:
+ service: "aggregator"
+
+ tasks:
+ - name: Update apt and install required system packages
+ become: true
+ apt:
+ pkg:
+ - pkg-config
+ - libssl-dev
+ state: latest
+ update_cache: true
+ vars:
+ ansible_ssh_user: "{{ admin_user }}"
+
+ - name: Create directories for each service if do not exist
+ file:
+ path: /home/{{ ansible_user }}/repos/{{ service }}
+ state: directory
+ mode: '0755'
+ owner: '{{ ansible_user }}'
+ group: '{{ ansible_user }}'
+ loop:
+ - aggregator
+
+ - name: Clone Aligned repository
+ git:
+ repo: https://github.com/yetanotherco/aligned_layer.git
+ dest: /home/{{ ansible_user }}/repos/{{ service }}/aligned_layer
+ version: v0.10.2
+ loop:
+ - aggregator
+
+ - name: Set permissions for cloned repository
+ file:
+ path: /home/{{ ansible_user }}/repos/{{ service }}/aligned_layer
+ mode: '0755'
+ owner: '{{ ansible_user }}'
+ group: '{{ ansible_user }}'
+ recurse: yes
+
+ - name: Copy ECDSA keystore to server
+ copy:
+ src: '{{ ecdsa_keystore_path }}'
+ dest: /home/{{ ansible_user }}/.keystores/aggregator.ecdsa
+ owner: '{{ ansible_user }}'
+ group: '{{ ansible_user }}'
+
+ - name: Copy BLS keystore to server
+ copy:
+ src: '{{ bls_keystore_path }}'
+ dest: /home/{{ ansible_user }}/.keystores/aggregator.bls
+ owner: '{{ ansible_user }}'
+ group: '{{ ansible_user }}'
+
+ - name: Build aggregator
+ shell:
+ chdir: /home/{{ ansible_user }}/repos/aggregator/aligned_layer/
+ cmd: /usr/local/go/bin/go build -o /home/{{ ansible_user }}/repos/aggregator/aligned_layer/build/aligned-aggregator /home/{{ ansible_user }}/repos/aggregator/aligned_layer/aggregator/cmd/main.go
+
+ - name: Upload config file for aggregator
+ template:
+ src: config-files/config-aggregator.yaml.j2
+ dest: "/home/{{ ansible_user }}/config/config-aggregator.yaml"
+ vars:
+ aligned_layer_deployment_config_file_path: "{{ lookup('ini', 'aligned_layer_deployment_config_file_path', file='ini/config-aggregator.ini') }}"
+ eigen_layer_deployment_config_file_path: "{{ lookup('ini', 'eigen_layer_deployment_config_file_path', file='ini/config-aggregator.ini') }}"
+ eth_rpc_url: "{{ lookup('ini', 'eth_rpc_url', file='ini/config-aggregator.ini') }}"
+ eth_rpc_url_fallback: "{{ lookup('ini', 'eth_rpc_url_fallback', file='ini/config-aggregator.ini') }}"
+ eth_ws_url: "{{ lookup('ini', 'eth_ws_url', file='ini/config-aggregator.ini') }}"
+ eth_ws_url_fallback: "{{ lookup('ini', 'eth_ws_url_fallback', file='ini/config-aggregator.ini') }}"
+ ecdsa_private_key_store_path: "{{ lookup('ini', 'ecdsa_private_key_store_path', file='ini/config-aggregator.ini') }}"
+ ecdsa_private_key_store_password: "{{ lookup('ini', 'ecdsa_private_key_store_password', file='ini/config-aggregator.ini') }}"
+ bls_private_key_store_path: "{{ lookup('ini', 'bls_private_key_store_path', file='ini/config-aggregator.ini') }}"
+ bls_private_key_store_password: "{{ lookup('ini', 'bls_private_key_store_password', file='ini/config-aggregator.ini') }}"
+ enable_metrics: "{{ lookup('ini', 'enable_metrics', file='ini/config-aggregator.ini') }}"
+ metrics_ip_port_address: "{{ lookup('ini', 'metrics_ip_port_address', file='ini/config-aggregator.ini') }}"
+ telemetry_ip_port_address: "{{ lookup('ini', 'telemetry_ip_port_address', file='ini/config-aggregator.ini') }}"
+
+ - name: Allow access to tcp port 8090
+ become: true
+ ufw:
+ rule: allow
+ port: 8090
+ proto: tcp
+ vars:
+ ansible_ssh_user: "{{ admin_user }}"
+
+ - name: Create systemd services directory
+ file:
+ path: "/home/{{ ansible_user }}/.config/systemd/user/"
+ state: directory
+
+ - name: Add service to systemd
+ template:
+ src: services/aggregator.service.j2
+ dest: "/home/{{ ansible_user }}/.config/systemd/user/aggregator.service"
+ force: no
+
+ - name: Start aggregator service
+ systemd_service:
+ name: aggregator
+ state: started
+ enabled: true
+ scope: user
diff --git a/infra/ansible/playbooks/batcher.yaml b/infra/ansible/playbooks/batcher.yaml
index 238a6bf2c..2a1c1cb71 100644
--- a/infra/ansible/playbooks/batcher.yaml
+++ b/infra/ansible/playbooks/batcher.yaml
@@ -97,7 +97,6 @@
telemetry_ip_port_address: "{{ lookup('ini', 'telemetry_ip_port_address', file='ini/config-batcher.ini') }}"
batcher_replacement_private_key: "{{ lookup('ini', 'batcher_replacement_private_key', file='ini/config-batcher.ini') }}"
-
- name: Upload env file for batcher
template:
src: config-files/env-batcher.j2
diff --git a/infra/ansible/playbooks/ini/config-aggregator.ini.example b/infra/ansible/playbooks/ini/config-aggregator.ini.example
new file mode 100644
index 000000000..6c01c1c1b
--- /dev/null
+++ b/infra/ansible/playbooks/ini/config-aggregator.ini.example
@@ -0,0 +1,14 @@
+[global]
+aligned_layer_deployment_config_file_path=
+eigen_layer_deployment_config_file_path=
+eth_rpc_url=
+eth_rpc_url_fallback=
+eth_ws_url=
+eth_ws_url_fallback=
+ecdsa_private_key_store_path=
+ecdsa_private_key_store_password=
+bls_private_key_store_path=
+bls_private_key_store_password=
+enable_metrics=
+metrics_ip_port_address=
+telemetry_ip_port_address=
diff --git a/infra/ansible/playbooks/templates/config-files/config-aggregator.yaml.j2 b/infra/ansible/playbooks/templates/config-files/config-aggregator.yaml.j2
new file mode 100644
index 000000000..49bb8a3c4
--- /dev/null
+++ b/infra/ansible/playbooks/templates/config-files/config-aggregator.yaml.j2
@@ -0,0 +1,32 @@
+# Common variables for all the services
+# 'production' only prints info and above. 'development' also prints debug
+environment: "production"
+aligned_layer_deployment_config_file_path: "{{ aligned_layer_deployment_config_file_path }}"
+eigen_layer_deployment_config_file_path: "{{ eigen_layer_deployment_config_file_path }}"
+eth_rpc_url: "{{ eth_rpc_url }}"
+eth_rpc_url_fallback: "{{ eth_rpc_url_fallback }}"
+eth_ws_url: "{{ eth_ws_url }}"
+eth_ws_url_fallback: "{{ eth_ws_url_fallback }}"
+eigen_metrics_ip_port_address: "localhost:9090"
+
+## ECDSA Configurations
+ecdsa:
+ private_key_store_path: "{{ ecdsa_private_key_store_path }}"
+ private_key_store_password: "{{ ecdsa_private_key_store_password }}"
+
+## BLS Configurations
+bls:
+ private_key_store_path: "{{ bls_private_key_store_path }}"
+ private_key_store_password: "{{ bls_private_key_store_password }}"
+
+## Aggregator Configurations
+aggregator:
+ server_ip_port_address: localhost:8090
+ bls_public_key_compendium_address:
+ avs_service_manager_address:
+ enable_metrics: {{ enable_metrics }}
+ metrics_ip_port_address: "{{ metrics_ip_port_address }}"
+ telemetry_ip_port_address: "{{ telemetry_ip_port_address }}"
+ garbage_collector_period: 2m #The period of the GC process. Suggested value for Prod: '168h' (7 days)
+ garbage_collector_tasks_age: 20 #The age of tasks that will be removed by the GC, in blocks. Suggested value for prod: '216000' (30 days)
+ garbage_collector_tasks_interval: 10 #The interval of queried blocks to get an old batch. Suggested value for prod: '900' (3 hours)
diff --git a/infra/ansible/playbooks/templates/services/aggregator.service.j2 b/infra/ansible/playbooks/templates/services/aggregator.service.j2
new file mode 100644
index 000000000..eacf82989
--- /dev/null
+++ b/infra/ansible/playbooks/templates/services/aggregator.service.j2
@@ -0,0 +1,15 @@
+[Unit]
+Description=Aggregator
+After=network.target
+
+[Service]
+Type=simple
+WorkingDirectory=/home/{{ ansible_user }}/repos/aggregator/aligned_layer/aggregator
+ExecStart=/home/{{ ansible_user }}/repos/aggregator/aligned_layer/build/aligned-aggregator --config /home/{{ ansible_user }}/config/config-aggregator.yaml
+Restart=always
+RestartSec=1
+StartLimitBurst=100
+LimitNOFILE=100000
+
+[Install]
+WantedBy=multi-user.target
diff --git a/infra/ansible/stage_inventory.yaml b/infra/ansible/stage_inventory.yaml
index fb8085653..2a4cc8d38 100644
--- a/infra/ansible/stage_inventory.yaml
+++ b/infra/ansible/stage_inventory.yaml
@@ -1,9 +1,9 @@
aggregator:
hosts:
aligned-holesky-aggregator-1:
- ansible_host: aligned-ansible
- ansible_user: admin
- app_user: app
+ ansible_host: aligned-holesky-stage-1-aggregator
+ admin_user: admin
+ ansible_user: app
ansible_python_interpreter: /usr/bin/python3
batcher:
hosts: