From 3f208d4b8d356a48096b29e98f021ad9779c1e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:44:49 -0300 Subject: [PATCH 1/6] feat: add avs-devnet configuration file --- devnet.yaml | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 devnet.yaml diff --git a/devnet.yaml b/devnet.yaml new file mode 100644 index 00000000..86293f87 --- /dev/null +++ b/devnet.yaml @@ -0,0 +1,131 @@ +# yaml-language-server: $schema=https://github.com/Layr-Labs/avs-devnet/raw/refs/heads/main/schema.json + +# Local devnet config file for the hello-world-avs example +# This file can be used inside the hello-world-avs repo to start +# a devnet with any local changes + +# To run this example: +# 0. Ensure you have the latest version of the devnet (see https://github.com/Layr-Labs/avs-devnet for how to install) +# 1. While inside the Hello World repo, run `avs-devnet start` + +deployments: + - name: EigenLayer + repo: "." + contracts_path: "contracts" + script: script/DeployEigenLayerCore.s.sol + env: + # NOTE: this is used inside the deployer script + PRIVATE_KEY: "{{.deployer_private_key}}" + # NOTE: these are needed because of repo's `foundry.toml` + HOLESKY_PRIVATE_KEY: "" + HOLESKY_RPC_URL: "" + ETHERSCAN_API_KEY: "" + input: + config/core/: core_deployment_config + output: + eigenlayer_addresses: "deployments/core/31337.json" + + - name: hello-world-avs + repo: "." + contracts_path: "contracts" + script: script/HelloWorldDeployer.s.sol + env: + # NOTE: this is used inside the deployer script + PRIVATE_KEY: "{{.deployer_private_key}}" + # NOTE: these are needed because of repo's `foundry.toml` + HOLESKY_PRIVATE_KEY: "" + HOLESKY_RPC_URL: "" + ETHERSCAN_API_KEY: "" + input: + config/hello-world/: avs_deployment_config + deployments/core/: eigenlayer_addresses + output: + avs_addresses: "deployments/hello-world/31337.json" + +services: + - name: operator + image: hello_world + build_context: "." + input: + /app/contracts/deployments/core/: eigenlayer_addresses + /app/contracts/deployments/hello-world/: avs_addresses + env: + # This expands to the RPC node's URL + RPC_URL: "{{.http_rpc_url}}" + PRIVATE_KEY: "{{.keys.operator_ecdsa_keys.private_key}}" + cmd: ["npm", "run", "start:operator"] + + - name: traffic-generator + image: hello_world + build_context: "." + input: + /app/contracts/deployments/core/: eigenlayer_addresses + /app/contracts/deployments/hello-world/: avs_addresses + env: + # This expands to the RPC node's URL + RPC_URL: "{{.http_rpc_url}}" + PRIVATE_KEY: "{{.keys.traffic_generator_ecdsa_keys.private_key}}" + cmd: ["npm", "run", "start:traffic"] + +keys: + - name: operator_ecdsa_keys + type: ecdsa + - name: traffic_generator_ecdsa_keys + type: ecdsa + +artifacts: + core_deployment_config: + files: + 31337.json: + template: | + { + "strategyManager": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 50400 + }, + "delegation": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 50400 + }, + "slasher": { + "init_paused_status": 0 + }, + "eigenPodManager": { + "init_paused_status": 0 + }, + "rewardsCoordinator": { + "init_paused_status": 0, + "MAX_REWARDS_DURATION": 864000, + "MAX_RETROACTIVE_LENGTH": 86400, + "MAX_FUTURE_LENGTH": 86400, + "GENESIS_REWARDS_TIMESTAMP": 1672531200, + "rewards_updater_address": "{{.deployer_address}}", + "rewards_updater_key": "{{.deployer_private_key}}", + "activation_delay": 0, + "calculation_interval_seconds": 86400, + "global_operator_commission_bips": 1000 + } + } + + avs_deployment_config: + files: + 31337.json: + template: | + { + "addresses": { + "rewardsOwner": "{{.deployer_address}}", + "rewardsInitiator": "{{.deployer_address}}" + }, + "keys": { + "rewardsOwner": "{{.deployer_private_key}}", + "rewardsInitiator": "{{.deployer_private_key}}" + } + } + +ethereum_package: + additional_services: + - blockscout + network_params: + # We use the chain ID hardcoded in the hello-world-avs example + network_id: "31337" + seconds_per_slot: 3 From 36e6659eb0b394283b1391bfdf10aa586136e04a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:03:21 -0300 Subject: [PATCH 2/6] feat: dockerize Rust operator and traffic-generator --- Dockerfile | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 63a34d62..db0f6338 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,23 @@ -FROM node:22 +# Rust +FROM rust:1.81 AS rs-builder +WORKDIR /usr/src/hello-world +COPY ./Cargo.toml ./Cargo.lock rust-toolchain.toml ./ +COPY ./operator/rust ./operator/rust +RUN cargo build --release --bin start_operator --bin spam_tasks + +FROM debian:bullseye-slim AS operator-rs +WORKDIR /app +COPY --from=rs-builder /usr/src/hello-world/target/release/start_operator /usr/local/bin/start_operator +CMD ["start_operator"] + +FROM debian:bullseye-slim AS traffic-generator-rs +WORKDIR /app +COPY --from=rs-builder /usr/src/hello-world/target/release/spam_tasks /usr/local/bin/spam_tasks +CMD ["spam_tasks"] + + +# TypeScript +FROM node:22 AS operator-ts WORKDIR /app From 84cb845beeb1204bb696d208f70ebaffd42d6c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:03:45 -0300 Subject: [PATCH 3/6] feat: add Rust operator and spam_tasks to devnet --- devnet.yaml | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/devnet.yaml b/devnet.yaml index 86293f87..0bb8898e 100644 --- a/devnet.yaml +++ b/devnet.yaml @@ -43,34 +43,60 @@ deployments: avs_addresses: "deployments/hello-world/31337.json" services: - - name: operator - image: hello_world - build_context: "." + - name: operator0 + image: hello_world_ts + build_cmd: "docker build . -t hello_world_ts --target operator-ts" input: /app/contracts/deployments/core/: eigenlayer_addresses /app/contracts/deployments/hello-world/: avs_addresses env: # This expands to the RPC node's URL RPC_URL: "{{.http_rpc_url}}" - PRIVATE_KEY: "{{.keys.operator_ecdsa_keys.private_key}}" + PRIVATE_KEY: "{{.keys.operator0_ecdsa_keys.private_key}}" cmd: ["npm", "run", "start:operator"] - - name: traffic-generator - image: hello_world - build_context: "." + - name: operator1 + image: operator_rs + build_cmd: "docker build . -t operator_rs --target operator-rs" input: /app/contracts/deployments/core/: eigenlayer_addresses /app/contracts/deployments/hello-world/: avs_addresses env: # This expands to the RPC node's URL RPC_URL: "{{.http_rpc_url}}" - PRIVATE_KEY: "{{.keys.traffic_generator_ecdsa_keys.private_key}}" + PRIVATE_KEY: "{{.keys.operator1_ecdsa_keys.private_key}}" + + - name: traffic-generator0 + image: hello_world_ts + build_cmd: "docker build . -t hello_world_ts --target operator-ts" + input: + /app/contracts/deployments/core/: eigenlayer_addresses + /app/contracts/deployments/hello-world/: avs_addresses + env: + # This expands to the RPC node's URL + RPC_URL: "{{.http_rpc_url}}" + PRIVATE_KEY: "{{.keys.traffic_generator0_ecdsa_keys.private_key}}" cmd: ["npm", "run", "start:traffic"] + - name: traffic-generator1 + image: traffic_generator_rs + build_cmd: "docker build . -t traffic_generator_rs --target traffic-generator-rs" + input: + /app/contracts/deployments/core/: eigenlayer_addresses + /app/contracts/deployments/hello-world/: avs_addresses + env: + # This expands to the RPC node's URL + RPC_URL: "{{.http_rpc_url}}" + PRIVATE_KEY: "{{.keys.traffic_generator1_ecdsa_keys.private_key}}" + keys: - - name: operator_ecdsa_keys + - name: operator0_ecdsa_keys + type: ecdsa + - name: operator1_ecdsa_keys + type: ecdsa + - name: traffic_generator0_ecdsa_keys type: ecdsa - - name: traffic_generator_ecdsa_keys + - name: traffic_generator1_ecdsa_keys type: ecdsa artifacts: From b854624fd860f15131b3a62770e8645d13980326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:04:02 -0300 Subject: [PATCH 4/6] fix: fetch RPC URL from env --- operator/rust/crates/operator/src/spam_tasks.rs | 5 +++-- .../rust/crates/operator/src/start_operator.rs | 15 ++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/operator/rust/crates/operator/src/spam_tasks.rs b/operator/rust/crates/operator/src/spam_tasks.rs index da3b0834..7b21aa20 100644 --- a/operator/rust/crates/operator/src/spam_tasks.rs +++ b/operator/rust/crates/operator/src/spam_tasks.rs @@ -10,7 +10,8 @@ use rand::Rng; use std::{env, str::FromStr}; use tokio::time::{self, Duration}; -pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; +const RPC_URL: Lazy = + Lazy::new(|| env::var("RPC_URL").expect("failed to retrieve RPC URL")); #[allow(unused)] static KEY: Lazy = @@ -38,7 +39,7 @@ async fn create_new_task(task_name: &str) -> Result<()> { let parsed: HelloWorldData = serde_json::from_str(&data)?; let hello_world_contract_address: Address = parsed.addresses.hello_world_service_manager.parse()?; - let pr = get_signer(&KEY.clone(), ANVIL_RPC_URL); + let pr = get_signer(&KEY.clone(), &RPC_URL.clone()); let signer = PrivateKeySigner::from_str(&KEY.clone())?; let hello_world_contract = HelloWorldServiceManager::new(hello_world_contract_address, pr); diff --git a/operator/rust/crates/operator/src/start_operator.rs b/operator/rust/crates/operator/src/start_operator.rs index 5c0de67b..de155ee8 100644 --- a/operator/rust/crates/operator/src/start_operator.rs +++ b/operator/rust/crates/operator/src/start_operator.rs @@ -28,7 +28,8 @@ use once_cell::sync::Lazy; use rand::TryRngCore; use std::{env, str::FromStr}; -pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; +const RPC_URL: Lazy = + Lazy::new(|| env::var("RPC_URL").expect("failed to retrieve RPC URL")); static KEY: Lazy = Lazy::new(|| env::var("PRIVATE_KEY").expect("failed to retrieve private key")); @@ -38,7 +39,7 @@ async fn sign_and_response_to_task( task_created_block: u32, name: String, ) -> Result<()> { - let pr = get_signer(&KEY.clone(), ANVIL_RPC_URL); + let pr = get_signer(&KEY.clone(), &RPC_URL.clone()); let signer = PrivateKeySigner::from_str(&KEY.clone())?; let message = format!("Hello, {}", name); @@ -46,7 +47,7 @@ async fn sign_and_response_to_task( let operators: Vec = vec![DynSolValue::Address(signer.address())]; let signature: Vec = vec![DynSolValue::Bytes(signer.sign_hash_sync(&m_hash)?.into())]; - let current_block = U256::from(get_provider(ANVIL_RPC_URL).get_block_number().await?); + let current_block = U256::from(get_provider(&RPC_URL.clone()).get_block_number().await?); let signature_data = DynSolValue::Tuple(vec![ DynSolValue::Array(operators.clone()), DynSolValue::Array(signature.clone()), @@ -86,7 +87,7 @@ async fn sign_and_response_to_task( /// Monitor new tasks async fn monitor_new_tasks() -> Result<()> { - let pr = get_signer(&KEY.clone(), ANVIL_RPC_URL); + let pr = get_signer(&KEY.clone(), &RPC_URL.clone()); let hello_world_contract_address: Address = parse_hello_world_service_manager("contracts/deployments/hello-world/31337.json")?; let mut latest_processed_block = pr.get_block_number().await?; @@ -121,7 +122,7 @@ async fn monitor_new_tasks() -> Result<()> { } async fn register_operator() -> Result<()> { - let pr = get_signer(&KEY.clone(), ANVIL_RPC_URL); + let pr = get_signer(&KEY.clone(), &RPC_URL.clone()); let signer = PrivateKeySigner::from_str(&KEY.clone())?; let data = std::fs::read_to_string("contracts/deployments/core/31337.json")?; @@ -136,7 +137,7 @@ async fn register_operator() -> Result<()> { Address::ZERO, avs_directory_address, None, - ANVIL_RPC_URL.to_string(), + RPC_URL.to_string(), ); let elcontracts_writer_instance = ELChainWriter::new( Address::ZERO, @@ -145,7 +146,7 @@ async fn register_operator() -> Result<()> { None, Address::ZERO, elcontracts_reader_instance.clone(), - ANVIL_RPC_URL.to_string(), + RPC_URL.to_string(), KEY.clone(), ); From 6321b746fe40291cd5342cd12530671e90fc3dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:26:26 -0300 Subject: [PATCH 5/6] fix: use ubuntu as base image --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index db0f6338..60096af8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,12 +5,12 @@ COPY ./Cargo.toml ./Cargo.lock rust-toolchain.toml ./ COPY ./operator/rust ./operator/rust RUN cargo build --release --bin start_operator --bin spam_tasks -FROM debian:bullseye-slim AS operator-rs +FROM ubuntu:24.04 AS operator-rs WORKDIR /app COPY --from=rs-builder /usr/src/hello-world/target/release/start_operator /usr/local/bin/start_operator CMD ["start_operator"] -FROM debian:bullseye-slim AS traffic-generator-rs +FROM ubuntu:24.04 AS traffic-generator-rs WORKDIR /app COPY --from=rs-builder /usr/src/hello-world/target/release/spam_tasks /usr/local/bin/spam_tasks CMD ["spam_tasks"] From 8edbd31db38dbbed6b0f01e165aef2a8295ba7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:39:39 -0300 Subject: [PATCH 6/6] chore: fix clippy errors --- operator/rust/crates/operator/src/spam_tasks.rs | 2 +- operator/rust/crates/operator/src/start_operator.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator/rust/crates/operator/src/spam_tasks.rs b/operator/rust/crates/operator/src/spam_tasks.rs index 7b21aa20..6e64605b 100644 --- a/operator/rust/crates/operator/src/spam_tasks.rs +++ b/operator/rust/crates/operator/src/spam_tasks.rs @@ -10,7 +10,7 @@ use rand::Rng; use std::{env, str::FromStr}; use tokio::time::{self, Duration}; -const RPC_URL: Lazy = +static RPC_URL: Lazy = Lazy::new(|| env::var("RPC_URL").expect("failed to retrieve RPC URL")); #[allow(unused)] diff --git a/operator/rust/crates/operator/src/start_operator.rs b/operator/rust/crates/operator/src/start_operator.rs index de155ee8..567a8c64 100644 --- a/operator/rust/crates/operator/src/start_operator.rs +++ b/operator/rust/crates/operator/src/start_operator.rs @@ -28,7 +28,7 @@ use once_cell::sync::Lazy; use rand::TryRngCore; use std::{env, str::FromStr}; -const RPC_URL: Lazy = +static RPC_URL: Lazy = Lazy::new(|| env::var("RPC_URL").expect("failed to retrieve RPC URL")); static KEY: Lazy =