Skip to content

Commit c99d3a3

Browse files
JuArceklaus993
andauthored
ci: deploy operator with ansible (#1382)
Co-authored-by: Klaus Lungwitz <[email protected]>
1 parent 3345d4a commit c99d3a3

File tree

10 files changed

+492
-23
lines changed

10 files changed

+492
-23
lines changed

Makefile

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,15 @@ operator_deposit_into_mock_strategy:
247247
--strategy-address $(STRATEGY_ADDRESS) \
248248
--amount 100000000000000000
249249

250+
251+
AMOUNT ?= 1000
252+
250253
operator_deposit_into_strategy:
251254
@echo "Depositing into strategy"
252255
@go run operator/cmd/main.go deposit-into-strategy \
253256
--config $(CONFIG_FILE) \
254-
--amount 1000
257+
--strategy-address $(STRATEGY_ADDRESS) \
258+
--amount $(AMOUNT)
255259

256260
operator_register_with_aligned_layer:
257261
@echo "Registering operator with AlignedLayer"
@@ -1087,3 +1091,20 @@ ansible_batcher_deploy: ## Deploy the Batcher. Parameters: INVENTORY, KEYSTORE
10871091
@ansible-playbook infra/ansible/playbooks/batcher.yaml \
10881092
-i $(INVENTORY) \
10891093
-e "keystore_path=$(KEYSTORE)"
1094+
1095+
1096+
ansible_operator_create_env: ## Create empty variables files for the Operator deploy
1097+
@cp -n infra/ansible/playbooks/ini/config-operator.ini.example infra/ansible/playbooks/ini/config-operator.ini
1098+
@cp -n infra/ansible/playbooks/ini/config-register-operator.ini.example infra/ansible/playbooks/ini/config-register-operator.ini
1099+
@echo "Config files for the Operator created in infra/ansible/playbooks/ini"
1100+
@echo "Please complete the values and run make ansible_operator_deploy"
1101+
1102+
ansible_operator_deploy: ## Deploy the Operator. Parameters: INVENTORY
1103+
@if [ -z "$(INVENTORY)" ] || [ -z "$(ECDSA_KEYSTORE)" ] || [ -z "$(BLS_KEYSTORE)" ]; then \
1104+
echo "Error: INVENTORY, ECDSA_KEYSTORE, BLS_KEYSTORE must be set."; \
1105+
exit 1; \
1106+
fi
1107+
@ansible-playbook infra/ansible/playbooks/operator.yaml \
1108+
-i $(INVENTORY) \
1109+
-e "ecdsa_keystore_path=$(ECDSA_KEYSTORE)" \
1110+
-e "bls_keystore_path=$(BLS_KEYSTORE)"

infra/ansible/README.md

Lines changed: 180 additions & 1 deletion
Large diffs are not rendered by default.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
- name: Foundry Setup
2+
hosts: "{{ host }}"
3+
4+
tasks:
5+
6+
- name: Download Foundry
7+
shell:
8+
cmd: curl -L https://foundry.paradigm.xyz | bash
9+
10+
- name: Run Foundryup
11+
shell:
12+
cmd: /home/{{ ansible_user }}/.foundry/bin/foundryup
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[global]
2+
aligned_layer_deployment_config_file_path=
3+
eigen_layer_deployment_config_file_path=
4+
eth_rpc_url=
5+
eth_rpc_url_fallback=
6+
eth_ws_url=
7+
eth_ws_url_fallback=
8+
9+
ecdsa_private_key_store_path=
10+
ecdsa_private_key_store_password=
11+
12+
bls_private_key_store_path=
13+
bls_private_key_store_password=
14+
15+
aggregator_rpc_server_ip_port_address=
16+
operator_tracker_ip_port_address=
17+
address=
18+
metadata_url=
19+
enable_metrics=
20+
metrics_ip_port_address=
21+
last_processed_batch_filepath=
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[global]
2+
address=
3+
metadata_url=
4+
el_delegation_manager_address=
5+
eth_rpc_url=
6+
private_key_store_path=
7+
private_key_store_password=
8+
chain_id=
9+
weth_address=
10+
weth_strategy_address=
Lines changed: 155 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,181 @@
1-
- import_playbook: setup.yaml
2-
- import_playbook: go.yaml
3-
- import_playbook: rust.yaml
4-
- import_playbook: eigenlayer-cli.yaml
1+
- name: Run setup playbook
2+
ansible.builtin.import_playbook: setup.yaml
3+
vars:
4+
host: operator
5+
6+
- name: Run go playbook
7+
ansible.builtin.import_playbook: go.yaml
8+
vars:
9+
host: operator
10+
11+
- name: Run rust playbook
12+
ansible.builtin.import_playbook: rust.yaml
13+
vars:
14+
host: operator
15+
16+
- name: Run eigenlayer-cli playbook
17+
ansible.builtin.import_playbook: eigenlayer-cli.yaml
18+
vars:
19+
host: operator
520

6-
- hosts: aligned-holesky-operator-1
7-
become: true
21+
- name: Run foundry playbook
22+
ansible.builtin.import_playbook: foundry.yaml
823
vars:
9-
user: "{{ user }}"
24+
host: operator
25+
26+
27+
- hosts: operator
1028

1129
tasks:
12-
# Install required packages
30+
1331
- name: Update apt and install required system packages
32+
become: true
1433
apt:
1534
pkg:
1635
- pkg-config
1736
- libssl-dev
18-
- gcc
1937
state: latest
2038
update_cache: true
39+
vars:
40+
ansible_ssh_user: "{{ admin_user }}"
2141

22-
# Create directories for each service
23-
- name: Create directories for each service if do not exist
42+
- name: Create directory for the repository
2443
ansible.builtin.file:
25-
path: /home/{{ user }}/repos/{{ item }}
44+
path: /home/{{ ansible_user }}/repos/operator
2645
state: directory
2746
mode: '0755'
28-
become_user: "{{ user }}"
29-
loop:
30-
- operator
47+
owner: '{{ ansible_user }}'
48+
group: '{{ ansible_user }}'
3149

32-
# Clone Aligned repository for each service
3350
- name: Clone Aligned repository
3451
ansible.builtin.git:
3552
repo: https://github.com/yetanotherco/aligned_layer.git
36-
dest: /home/{{ user }}/repos/{{ item }}/aligned_layer
53+
dest: /home/{{ ansible_user }}/repos/operator/aligned_layer
3754
version: v0.10.2
38-
become_user: "{{ user }}"
39-
loop:
40-
- operator
55+
recursive: false
56+
57+
- name: Build the Operator
58+
make:
59+
chdir: /home/{{ ansible_user }}/repos/operator/aligned_layer
60+
target: build_operator
61+
environment:
62+
PATH: "{{ ansible_env.PATH }}:/usr/bin:/usr/local/go/bin:/home/{{ ansible_user }}/.cargo/bin"
63+
64+
- name: Copy ECDSA keystore to server
65+
ansible.builtin.copy:
66+
src: '{{ ecdsa_keystore_path }}'
67+
dest: /home/{{ ansible_user }}/.keystores/operator.ecdsa
68+
owner: '{{ ansible_user }}'
69+
group: '{{ ansible_user }}'
70+
71+
- name: Copy BLS keystore to server
72+
ansible.builtin.copy:
73+
src: '{{ bls_keystore_path }}'
74+
dest: /home/{{ ansible_user }}/.keystores/operator.bls
75+
owner: '{{ ansible_user }}'
76+
group: '{{ ansible_user }}'
77+
78+
- name: Create variables
79+
set_fact:
80+
weth_strategy_address: "{{ lookup('ini', 'weth_strategy_address', file='ini/config-register-operator.ini') }}"
81+
address: "{{ lookup('ini', 'address', file='ini/config-register-operator.ini') }}"
82+
eth_rpc_url: "{{ lookup('ini', 'eth_rpc_url', file='ini/config-register-operator.ini') }}"
83+
84+
- name: Check if Operator already staked wETH
85+
ansible.builtin.command: "cast call {{ weth_strategy_address }} shares(address)(uint256) {{ address }} --rpc-url {{ eth_rpc_url }}"
86+
register: operator_stake
87+
environment:
88+
PATH: "{{ ansible_env.PATH }}:/home/{{ ansible_user }}/.foundry/bin"
89+
90+
- name: Upload config file for register Operator
91+
when: operator_stake.stdout == "0"
92+
template:
93+
src: operator/config-register-operator.yaml.j2
94+
dest: "/home/{{ ansible_user }}/config/config-register-operator.yaml"
95+
vars:
96+
address: "{{ lookup('ini', 'address', file='ini/config-register-operator.ini') }}"
97+
metadata_url: "{{ lookup('ini', 'metadata_url', file='ini/config-register-operator.ini') }}"
98+
el_delegation_manager_address: "{{ lookup('ini', 'el_delegation_manager_address', file='ini/config-register-operator.ini') }}"
99+
eth_rpc_url: "{{ lookup('ini', 'eth_rpc_url', file='ini/config-register-operator.ini') }}"
100+
private_key_store_path: "{{ lookup('ini', 'private_key_store_path', file='ini/config-register-operator.ini') }}"
101+
chain_id: "{{ lookup('ini', 'chain_id', file='ini/config-register-operator.ini') }}"
102+
103+
- name: Register Operator in EigenLayer
104+
when: operator_stake.stdout == "0"
105+
shell:
106+
cmd: echo "{{ lookup('ini', 'private_key_store_password', file='ini/config-register-operator.ini') }}" | eigenlayer operator register /home/{{ ansible_user }}/config/config-register-operator.yaml >> register.log 2>&1
107+
environment:
108+
PATH: "{{ ansible_env.PATH }}:/home/{{ ansible_user }}/bin"
109+
110+
- name: Swap holETH for wETH
111+
when: operator_stake.stdout == "0"
112+
shell:
113+
cmd: cast send --value 0.1ether {{ lookup('ini', 'weth_address', file='ini/config-register-operator.ini') }} --password {{ lookup('ini', 'private_key_store_password', file='ini/config-register-operator.ini') }}
114+
environment:
115+
PATH: "{{ ansible_env.PATH }}:/home/{{ ansible_user }}/.foundry/bin"
116+
ETH_KEYSTORE: "{{ lookup('ini', 'private_key_store_path', file='ini/config-register-operator.ini') }}"
117+
ETH_PASSWORD: "{{ lookup('ini', 'private_key_store_password', file='ini/config-register-operator.ini') }}" # It is not working idk why
118+
ETH_RPC_URL: "{{ lookup('ini', 'eth_rpc_url', file='ini/config-register-operator.ini') }}"
119+
120+
- name: Upload config file for Operator
121+
template:
122+
src: config-files/config-operator.yaml.j2
123+
dest: "/home/{{ ansible_user }}/config/config-operator.yaml"
124+
vars:
125+
aligned_layer_deployment_config_file_path: "{{ lookup('ini', 'aligned_layer_deployment_config_file_path', file='ini/config-operator.ini') }}"
126+
eigen_layer_deployment_config_file_path: "{{ lookup('ini', 'eigen_layer_deployment_config_file_path', file='ini/config-operator.ini') }}"
127+
eth_rpc_url: "{{ lookup('ini', 'eth_rpc_url', file='ini/config-operator.ini') }}"
128+
eth_rpc_url_fallback: "{{ lookup('ini', 'eth_rpc_url_fallback', file='ini/config-operator.ini') }}"
129+
eth_ws_url: "{{ lookup('ini', 'eth_ws_url', file='ini/config-operator.ini') }}"
130+
eth_ws_url_fallback: "{{ lookup('ini', 'eth_ws_url_fallback', file='ini/config-operator.ini') }}"
131+
ecdsa_private_key_store_path: "{{ lookup('ini', 'ecdsa_private_key_store_path', file='ini/config-operator.ini') }}"
132+
ecdsa_private_key_store_password: "{{ lookup('ini', 'ecdsa_private_key_store_password', file='ini/config-operator.ini') }}"
133+
bls_private_key_store_path: "{{ lookup('ini', 'bls_private_key_store_path', file='ini/config-operator.ini') }}"
134+
bls_private_key_store_password: "{{ lookup('ini', 'bls_private_key_store_password', file='ini/config-operator.ini') }}"
135+
aggregator_rpc_server_ip_port_address: "{{ lookup('ini', 'aggregator_rpc_server_ip_port_address', file='ini/config-operator.ini') }}"
136+
operator_tracker_ip_port_address: "{{ lookup('ini', 'operator_tracker_ip_port_address', file='ini/config-operator.ini') }}"
137+
address: "{{ lookup('ini', 'address', file='ini/config-operator.ini') }}"
138+
metadata_url: "{{ lookup('ini', 'metadata_url', file='ini/config-operator.ini') }}"
139+
enable_metrics: "{{ lookup('ini', 'enable_metrics', file='ini/config-operator.ini') }}"
140+
metrics_ip_port_address: "{{ lookup('ini', 'metrics_ip_port_address', file='ini/config-operator.ini') }}"
141+
last_processed_batch_filepath: "{{ lookup('ini', 'last_processed_batch_filepath', file='ini/config-operator.ini') }}"
142+
143+
- name: Deposit into wETH strategy
144+
when: operator_stake.stdout == "0"
145+
make:
146+
chdir: /home/{{ ansible_user }}/repos/operator/aligned_layer
147+
target: operator_deposit_into_strategy
148+
params:
149+
CONFIG_FILE=/home/{{ ansible_user }}/config/config-operator.yaml
150+
STRATEGY_ADDRESS={{ lookup('ini', 'weth_strategy_address', file='ini/config-register-operator.ini') }}
151+
AMOUNT=100000000000000000 # 0.1ether
152+
environment:
153+
PATH: "{{ ansible_env.PATH }}:/usr/bin:/usr/local/go/bin"
41154

42155
- name: Allow access to tcp port 9092 from the VPN
156+
become: true
43157
ufw:
44158
rule: allow
45159
port: 9092
46160
proto: tcp
47-
src: 100.0.0.0/24
161+
src: 100.0.0.0/24
162+
vars:
163+
ansible_ssh_user: "{{ admin_user }}"
164+
165+
- name: Create systemd services directory
166+
file:
167+
path: "/home/{{ ansible_user }}/.config/systemd/user/"
168+
state: directory
169+
170+
- name: Add service to systemd
171+
template:
172+
src: services/operator.service.j2
173+
dest: "/home/{{ ansible_user }}/.config/systemd/user/operator.service"
174+
force: no
175+
176+
- name: Start Operator service
177+
ansible.builtin.systemd_service:
178+
name: operator
179+
state: started
180+
enabled: true
181+
scope: user
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Common variables for all the services
2+
# 'production' only prints info and above. 'development' also prints debug
3+
environment: 'production'
4+
aligned_layer_deployment_config_file_path: "{{ aligned_layer_deployment_config_file_path }}"
5+
eigen_layer_deployment_config_file_path: "{{ eigen_layer_deployment_config_file_path }}"
6+
eth_rpc_url: "{{ eth_rpc_url }}"
7+
eth_rpc_url_fallback: "{{ eth_rpc_url_fallback }}"
8+
eth_ws_url: "{{ eth_ws_url }}"
9+
eth_ws_url_fallback: "{{ eth_ws_url_fallback }}"
10+
eigen_metrics_ip_port_address: 'localhost:9090'
11+
12+
## ECDSA Configurations
13+
ecdsa:
14+
private_key_store_path: "{{ ecdsa_private_key_store_path }}"
15+
private_key_store_password: "{{ ecdsa_private_key_store_password }}"
16+
17+
## BLS Configurations
18+
bls:
19+
private_key_store_path: "{{ bls_private_key_store_path }}"
20+
private_key_store_password: "{{ bls_private_key_store_password }}"
21+
22+
## Operator Configurations
23+
operator:
24+
aggregator_rpc_server_ip_port_address: "{{ aggregator_rpc_server_ip_port_address }}"
25+
operator_tracker_ip_port_address: "{{ operator_tracker_ip_port_address }}"
26+
address: "{{ address }}"
27+
earnings_receiver_address: "{{ address }}" #Can be the same as the operator.
28+
delegation_approver_address: '0x0000000000000000000000000000000000000000'
29+
staker_opt_out_window_blocks: 0
30+
metadata_url: "{{ metadata_url }}"
31+
enable_metrics: {{ enable_metrics }}
32+
metrics_ip_port_address: "{{ metrics_ip_port_address }}"
33+
max_batch_size: 268435456 # 256 MiB
34+
last_processed_batch_filepath: "{{ last_processed_batch_filepath }}"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Reference: https://github.com/Layr-Labs/eigenlayer-cli/blob/master/pkg/operator/config/operator-config-example.yaml
2+
# All the below fields are required for successful operator registration.
3+
4+
# To learn more about operator fields
5+
# https://github.com/Layr-Labs/eigenlayer-contracts/blob/92ccacc868785350973afc15e90a18dcd39fbc0b/src/contracts/interfaces/IDelegationManager.sol#L21:
6+
operator:
7+
# This is the standard Ethereum address format (ex: 0x6a8c0D554a694899041E52a91B4EC3Ff23d8aBD5) of your operator
8+
# which is the ecdsa key you created or imported using EigenLayer CLI
9+
address: {{ address }}
10+
# This is the standard Ethereum address format (0x...)
11+
# This is the address which operator will use to approve delegation requests from stakers.
12+
# if set, this address must sign and approve new delegation from Stakers to this Operator
13+
# For now, you can leave it with the default value for un-gated delegation requests
14+
# Once we enable gated delegation requests, you can update this field with the address of the approver
15+
delegation_approver_address: 0x0000000000000000000000000000000000000000
16+
# Please refer to this link for more details on this field https://github.com/Layr-Labs/eigenlayer-contracts/blob/92ccacc868785350973afc15e90a18dcd39fbc0b/src/contracts/interfaces/IDelegationManager.sol#L33:
17+
# Please keep this field to 0, and it can be updated later using EigenLayer CLI
18+
staker_opt_out_window_blocks: 0
19+
metadata_url: {{ metadata_url }}
20+
21+
# EigenLayer Delegation manager contract address
22+
# For the testnet address, refer to here: https://github.com/layr-labs/eigenlayer-contracts/?tab=readme-ov-file#current-testnet-deployment
23+
# For the mainnet address, refer to here: https://github.com/layr-labs/eigenlayer-contracts/?tab=readme-ov-file#current-mainnet-deployment
24+
el_delegation_manager_address: {{ el_delegation_manager_address }}
25+
26+
# ETH RPC URL to the ethereum node you are using for on-chain operations
27+
eth_rpc_url: {{ eth_rpc_url }}
28+
29+
# Signer Type to use
30+
# Supported values: local_keystore, fireblocks, web3
31+
signer_type: local_keystore
32+
33+
# Full path to local ecdsa private key store file
34+
private_key_store_path: {{ private_key_store_path }}
35+
36+
# Chain ID: 1 for mainnet, 17000 for holesky, 31337 for local
37+
chain_id: {{ chain_id }}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[Unit]
2+
Description=Operator
3+
After=network.target
4+
5+
[Service]
6+
Type=simple
7+
WorkingDirectory=/home/{{ ansible_user }}/repos/operator/aligned_layer
8+
ExecStart=/home/{{ ansible_user }}/repos/operator/aligned_layer/operator/build/aligned-operator start --config /home/{{ ansible_user }}/config/config-operator.yaml
9+
Restart=always
10+
RestartSec=1
11+
StartLimitBurst=100
12+
13+
[Install]
14+
WantedBy=multi-user.target

infra/ansible/stage_inventory.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,10 @@ batcher:
1818
# ansible_host: aligned-holesky-explorer
1919
# ansible_user: admin
2020
# ansible_python_interpreter: /usr/bin/python3
21+
operator:
22+
hosts:
23+
operator-1:
24+
ansible_host: aligned-holesky-stage-1
25+
admin_user: admin
26+
ansible_user: app
27+
ansible_python_interpreter: /usr/bin/python3

0 commit comments

Comments
 (0)