diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc0ce9a..984aebf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,11 @@ jobs: with: version: ${{ env.KURTOSIS_VERSION }} + - name: Cache Docker images + uses: ScribeMD/docker-cache@0.5.0 + with: + key: docker-${{ runner.os }}-${{ hashFiles('Makefile', 'examples', 'src/config/default_config.yaml') }} + - name: Run Package with default args run: | kurtosis run ./kurtosis_package @@ -50,6 +55,11 @@ jobs: with: version: ${{ env.KURTOSIS_VERSION }} + - name: Cache Docker images + uses: ScribeMD/docker-cache@0.5.0 + with: + key: docker-${{ runner.os }}-${{ hashFiles('Makefile', 'examples', 'src/config/default_config.yaml') }} + - name: Run example '${{ matrix.example }}' run: make ${{ matrix.example }} @@ -66,6 +76,11 @@ jobs: with: version: ${{ env.KURTOSIS_VERSION }} + - name: Cache Docker images + uses: ScribeMD/docker-cache@0.5.0 + with: + key: docker-${{ runner.os }}-${{ env.KURTOSIS_VERSION }} + - name: Kurtosis Lint run: make kurtosis_lint @@ -120,6 +135,11 @@ jobs: with: go-version: ${{ env.GO_VERSION }} + - name: Cache Docker images + uses: ScribeMD/docker-cache@0.5.0 + with: + key: docker-${{ runner.os }}-${{ hashFiles('Makefile', 'examples', 'src/config/default_config.yaml') }} + - name: Run go test run: make test @@ -144,14 +164,19 @@ jobs: - name: Install devnet run: make install - + + - name: Cache Docker images + uses: ScribeMD/docker-cache@0.5.0 + with: + key: docker-${{ runner.os }}-a294978-${{ hashFiles('examples/eigenda.yaml') }} + - name: Checkout EigenDA repo uses: actions/checkout@v4 with: repository: Layr-Labs/eigenda path: eigenda/ ref: a294978e346fe9d7ede0f1a57012c36f64f1212a - + - name: Download SRS points run: | cd eigenda/ diff --git a/Makefile b/Makefile index b08a4e7..da3846b 100644 --- a/Makefile +++ b/Makefile @@ -103,8 +103,8 @@ HELLO_WORLD_REF:=4626e206fd119b26ebe98935b256daa7256e863b examples/hello-world-avs: @echo "Cloning hello-world-avs repo..." - @mkdir -p examples/hello-world-avs - @cd examples/hello-world-avs && \ + @mkdir -p $@ + @cd $@ && \ git init . && \ git remote add origin https://github.com/Layr-Labs/hello-world-avs.git && \ git fetch --depth 1 origin $(HELLO_WORLD_REF) && \ diff --git a/cmd/avs-devnet/main.go b/cmd/avs-devnet/main.go index 89e0cf8..0e9819d 100644 --- a/cmd/avs-devnet/main.go +++ b/cmd/avs-devnet/main.go @@ -16,14 +16,12 @@ func main() { app.Name = "avs-devnet" app.Usage = "start an AVS devnet" app.Version = version - app.Flags = append(app.Flags, &flags.KurtosisPackageFlag) app.Commands = append(app.Commands, &cli.Command{ Name: "init", Usage: "Initialize a devnet configuration file", Args: true, - ArgsUsage: "[]", - Flags: []cli.Flag{}, + ArgsUsage: "[]", Action: cmds.InitCmd, }) @@ -31,18 +29,19 @@ func main() { Name: "start", Usage: "Start devnet from configuration file", Args: true, - ArgsUsage: "[]", - Flags: []cli.Flag{}, - Action: cmds.StartCmd, + ArgsUsage: "[]", + Flags: []cli.Flag{ + &flags.DevnetNameFlag, + &flags.KurtosisPackageFlag, + }, + Action: cmds.StartCmd, }) app.Commands = append(app.Commands, &cli.Command{ - Name: "stop", - Usage: "Stop devnet from configuration file", - Args: true, - ArgsUsage: "[]", - Flags: []cli.Flag{}, - Action: cmds.StopCmd, + Name: "stop", + Usage: "Stop devnet from configuration file", + Flags: []cli.Flag{&flags.DevnetNameFlag}, + Action: cmds.StopCmd, }) app.Commands = append(app.Commands, &cli.Command{ @@ -50,17 +49,15 @@ func main() { Usage: "Get a devnet contract or EOA address", Args: true, ArgsUsage: "...", - Flags: []cli.Flag{&flags.ConfigFilePathFlag}, + Flags: []cli.Flag{&flags.DevnetNameFlag}, Action: cmds.GetAddress, }) app.Commands = append(app.Commands, &cli.Command{ - Name: "get-ports", - Usage: "Get the published ports on the devnet", - Args: true, - ArgsUsage: "[]", - Flags: []cli.Flag{}, - Action: cmds.GetPorts, + Name: "get-ports", + Usage: "Get the published ports on the devnet", + Flags: []cli.Flag{&flags.DevnetNameFlag}, + Action: cmds.GetPorts, }) if err := app.Run(os.Args); err != nil { diff --git a/examples/aligned_layer.yaml b/examples/aligned_layer.yaml new file mode 100644 index 0000000..8f0e9a1 --- /dev/null +++ b/examples/aligned_layer.yaml @@ -0,0 +1,533 @@ +# yaml-language-server: $schema=../schema.json + +# Example devnet config file for Aligned Layer (https://github.com/yetanotherco/aligned_layer) + +# Things to note: +# - images need to be built manually, by running `make docker_build` in the Aigned Layer repo +# - the branch required is: https://github.com/yetanotherco/aligned_layer/pull/1708 +# - proof sending doesn't work yet +# - to try sending proofs, you need to: +# - replace 0x7bc06c482DEAd17c0e297aFbC32f6e63d3846650 with the correct contract address in sdk +# - specify the correct RPC URL when sending proofs (look at the makefile for that) +# - pass batcher URL and proof sender PK with the `--batcher_url` and `--private_key` flags +deployments: + # TODO: use devnet EigenLayer deployer + - name: EigenLayer + repo: "https://github.com/yetanotherco/aligned_layer.git" + ref: "output-batcher-addresses-as-json" + contracts_path: "contracts" + script: script/deploy/EigenLayerDeployer.s.sol + extra_args: --sig 'run(string memory configFileName)' -- eigen.devnet.config.json + input: + script/deploy/config/devnet/: eigenlayer_deployment_config + output: + eigenlayer_addresses: "script/output/devnet/eigenlayer_deployment_output.json" + addresses: + delegationManager: "eigenlayer_addresses:.addresses.delegationManager" + mockStrategy: "eigenlayer_addresses:.addresses.strategies.MOCK" + + - name: Aligned + repo: "https://github.com/yetanotherco/aligned_layer.git" + ref: "output-batcher-addresses-as-json" + contracts_path: "contracts" + script: script/deploy/AlignedLayerDeployer.s.sol + extra_args: >- + --sig "run(string memory existingDeploymentInfoPath, string memory deployConfigPath, string memory outputPath)" + ./script/output/devnet/eigenlayer_deployment_output.json + ./script/deploy/config/devnet/aligned.devnet.config.json + ./script/output/devnet/alignedlayer_deployment_output.json + input: + script/deploy/config/devnet/: aligned_deployment_config + script/output/devnet/: eigenlayer_addresses + output: + avs_addresses: script/output/devnet/alignedlayer_deployment_output.json + addresses: + alignedLayerServiceManager: "avs_addresses:.addresses.alignedLayerServiceManager" + registryCoordinator: "avs_addresses:.addresses.registryCoordinator" + + - name: BatcherPaymentService + repo: "https://github.com/yetanotherco/aligned_layer.git" + ref: "output-batcher-addresses-as-json" + contracts_path: "contracts" + script: script/deploy/BatcherPaymentServiceDeployer.s.sol + extra_args: >- + --sig "run(string batcherConfigPath, string outputPath)" + ./script/deploy/config/devnet/batcher.devnet.config.json + ./script/output/devnet/batcher_deployment_output.json + input: + script/deploy/config/devnet/: batcher_deployment_config + output: + batcher_addresses: script/output/devnet/batcher_deployment_output.json + addresses: + batcherPaymentService: "batcher_addresses:.addresses.batcherPaymentService" + +services: + - name: localstack + image: localstack/localstack + ports: + gateway: + number: 4566 + transport_protocol: TCP + application_protocol: "http" + wait: 1m + env: + DEBUG: 1 + DEFAULT_REGION: us-east-2 + AWS_ACCESS_KEY_ID: test + AWS_SECRET_ACCESS_KEY: test + input: + /etc/localstack/init/ready.d: localstack_init_script + + - name: "aggregator" + image: "ghcr.io/yetanotherco/aligned_layer/aggregator:latest" + ports: + rpc: + number: 8090 + transport_protocol: "TCP" + application_protocol: "http" + metrics: + number: 9091 + transport_protocol: "TCP" + application_protocol: "http" + input: + /aggregator/config-files/: aggregator_config + /aggregator/contracts/script/output/devnet/: + - eigenlayer_addresses + - avs_addresses + /aggregator/keystores/: + - aggregator_bls + - aggregator_ecdsa + cmd: + - "aligned-layer-aggregator" + - "--config" + - "./config-files/config-aggregator.yaml" + + # One-shot services to perform tasks + - name: "operator1-register-operator-eigenlayer" + image: ghcr.io/yetanotherco/aligned_layer/eigenlayer-cli:latest + input: + /go/config-files/: operator_config + /go/keystores/: operator1_ecdsa + env: + PASSWORD: "{{.keys.operator1_ecdsa.password}}" + cmd: + - "sh" + - "-c" + - 'echo "$PASSWORD" | eigenlayer operator register ./config-files/config-docker.yaml' + + - name: "operator1-mint-mock-tokens" + image: ghcr.io/yetanotherco/aligned_layer/foundry:latest + input: + /config-files/: operator_config + /keystores/: operator1_ecdsa + env: + DEPLOYER_PRIVATE_KEY: "{{.deployer_private_key}}" + RPC_URL: "{{.http_rpc_url}}" + OPERATOR_ADDRESS: "{{.keys.operator1_ecdsa.address}}" + cmd: + - "sh" + - "-c" + - >- + sleep 6 && + TOKEN_ADDR=$(cast call --rpc-url $RPC_URL {{.addresses.EigenLayer.mockStrategy}} 'underlyingToken()(address)') && + cast send $TOKEN_ADDR 'mint(address, uint256)' $OPERATOR_ADDRESS 100000000000000000 + --private-key $DEPLOYER_PRIVATE_KEY --rpc-url $RPC_URL + + - name: "batcher-payment-service-deposit-initial-funds" + image: ghcr.io/yetanotherco/aligned_layer/foundry:latest + env: + PRIVATE_KEY: "{{.keys.batcher_ecdsa.private_key}}" + RPC_URL: "{{.http_rpc_url}}" + BATCHER_PAYMENT_SERVICE_ADDRESS: "{{.addresses.BatcherPaymentService.batcherPaymentService}}" + ALIGNED_SERVICE_MANAGER_ADDRESS: "{{.addresses.Aligned.alignedLayerServiceManager}}" + cmd: + - "sh" + - "-c" + - >- + cast send --value "1ether" + --private-key $PRIVATE_KEY --rpc-url $RPC_URL + $ALIGNED_SERVICE_MANAGER_ADDRESS 'depositToBatcher(address)' $BATCHER_PAYMENT_SERVICE_ADDRESS + + - name: "operator1-deposit-into-mock-strategy" + image: ghcr.io/yetanotherco/aligned_layer/operator:latest + input: + /aligned_layer/config-files/: operator_config + /aligned_layer/contracts/script/output/devnet/: + - eigenlayer_addresses + - avs_addresses + /aligned_layer/keystores/: + - operator1_bls + - operator1_ecdsa + env: + OPERATOR_ADDRESS: "{{.keys.operator1_ecdsa.address}}" + cmd: + - "sh" + - "-c" + - >- + sleep 12 && + aligned-layer-operator deposit-into-strategy --config ./config-files/config-docker.yaml + --strategy-address {{.addresses.EigenLayer.mockStrategy}} --amount 100000000000000000 + + - name: "operator1-whitelist-devnet" + image: ghcr.io/yetanotherco/aligned_layer/foundry:latest + input: + /config-files/: operator_config + /addresses/: avs_addresses + /keystores/: operator1_ecdsa + env: + DEPLOYER_PRIVATE_KEY: "{{.deployer_private_key}}" + RPC_URL: "{{.http_rpc_url}}" + OPERATOR_ADDRESS: "{{.keys.operator1_ecdsa.address}}" + REGISTRY_ADDR: "{{.addresses.Aligned.registryCoordinator}}" + cmd: + - "sh" + - "-c" + - >- + echo "Registry address: $REGISTRY_ADDR" && + sleep 18 && + cast send $REGISTRY_ADDR 'add(address)' $OPERATOR_ADDRESS --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY + + - name: operator-register-with-aligned-layer + image: ghcr.io/yetanotherco/aligned_layer/operator:latest + input: + /aligned_layer/config-files/: operator_config + /aligned_layer/contracts/script/output/devnet/: + - eigenlayer_addresses + - avs_addresses + /aligned_layer/keystores/: + - operator1_bls + - operator1_ecdsa + cmd: + - "sh" + - "-c" + - "sleep 24 && aligned-layer-operator register --config ./config-files/config-docker.yaml" + + - name: "operator1" + image: "ghcr.io/yetanotherco/aligned_layer/operator:latest" + input: + /aligned_layer/config-files/: operator_config + /aligned_layer/contracts/script/output/devnet/: + - eigenlayer_addresses + - avs_addresses + /aligned_layer/keystores/: + - operator1_bls + - operator1_ecdsa + cmd: + - "sh" + - "-c" + - "sleep 30 && aligned-layer-operator start --config ./config-files/config-docker.yaml" + + - name: batcher + image: ghcr.io/yetanotherco/aligned_layer/batcher:latest + ports: + metrics: + number: 9093 + transport_protocol: "TCP" + application_protocol: "http" + rpc: + number: 8080 + transport_protocol: "TCP" + application_protocol: "http" + input: + /config-files/: + - batcher_config + - batcher_ecdsa + /deployment_output/: + - eigenlayer_addresses + - avs_addresses_merged + env: + AWS_SECRET_ACCESS_KEY: test + AWS_REGION: us-east-2 + AWS_ACCESS_KEY_ID: test + AWS_BUCKET_NAME: aligned.storage + UPLOAD_ENDPOINT: http://{{.services.localstack.ip_address}}:4566 + DOWNLOAD_ENDPOINT: http://{{.services.localstack.ip_address}}:4566/aligned.storage + RUST_LOG: info + RUST_BACKTRACE: 1 + cmd: + [ + "aligned-batcher", + "--config", + "./config-files/config-batcher-docker.yaml", + "--addr", + "0.0.0.0", + "--port", + "8080", + ] + +keys: + - name: "aggregator_bls" + type: "bls" + - name: "aggregator_ecdsa" + type: "ecdsa" + - name: "operator1_bls" + type: "bls" + - name: "operator1_ecdsa" + type: "ecdsa" + - name: "batcher_ecdsa" + type: "ecdsa" + # Account to be used when sending proofs + - name: "proof_sender" + type: "ecdsa" + +artifacts: + localstack_init_script: + files: + init-s3.py: + static_file: https://raw.githubusercontent.com/yetanotherco/aligned_layer/refs/heads/testnet/scripts/init-s3.py + + eigenlayer_deployment_config: + files: + eigen.devnet.config.json: + template: | + { + "chainInfo": { + "chainId": 31337 + }, + "multisig_addresses": { + "pauserMultisig": "{{.deployer_address}}", + "communityMultisig": "{{.deployer_address}}", + "operationsMultisig": "{{.deployer_address}}", + "executorMultisig": "{{.deployer_address}}", + "timelock": "{{.deployer_address}}" + }, + "strategies": { + "numStrategies": 0, + "MAX_PER_DEPOSIT": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "MAX_TOTAL_DEPOSITS": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "strategiesToDeploy": [] + }, + "strategyManager": { + "init_strategy_whitelister": "{{.deployer_address}}", + "init_paused_status": 0 + }, + "delegationManager": { + "init_paused_status": 0, + "init_minWithdrawalDelayBlocks": 10 + }, + "rewardsCoordinator": { + "init_paused_status": 0, + "CALCULATION_INTERVAL_SECONDS": 604800, + "MAX_REWARDS_DURATION": 6048000, + "MAX_RETROACTIVE_LENGTH": 7776000, + "MAX_FUTURE_LENGTH": 2592000, + "GENESIS_REWARDS_TIMESTAMP": 1710979200, + "rewards_updater_address": "{{.deployer_address}}", + "activation_delay": 7200, + "calculation_interval_seconds": 604800, + "global_operator_commission_bips": 1000 + }, + "avsDirectory": { + "init_paused_status": 0 + }, + "slasher": { + "init_paused_status": 0 + }, + "eigenPod": { + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": 32000000000, + "GENESIS_TIME": 1695902400 + }, + "eigenPodManager": { + "init_paused_status": 0, + "deneb_fork_timestamp": "1707305664" + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawalDelayBlocks": 10 + }, + "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", + "beaconOracleAddress": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" + } + + aligned_deployment_config: + files: + aligned.devnet.config.json: + template: | + { + "chainInfo": { + "chainId": 31337 + }, + "permissions": { + "owner": "{{.deployer_address}}", + "pauser": "{{.deployer_address}}", + "aggregator": "{{.keys.aggregator_ecdsa.address}}", + "upgrader": "{{.deployer_address}}", + "churner": "{{.deployer_address}}", + "ejector": "{{.deployer_address}}", + "deployer": "{{.deployer_address}}", + "initalPausedStatus": 0 + }, + "minimumStakes": [ + 1 + ], + "strategyWeights": [ + [ + { + "0_strategy": "{{.addresses.EigenLayer.mockStrategy}}", + "1_multiplier": 1e+18 + } + ] + ], + "operatorSetParams": [ + { + "0_maxOperatorCount": 200, + "1_kickBIPsOfOperatorStake": 11000, + "2_kickBIPsOfTotalStake": 50 + } + ], + "uri": "" + } + + batcher_deployment_config: + files: + batcher.devnet.config.json: + template: | + { + "address": { + "batcherWallet": "{{.keys.batcher_ecdsa.address}}", + "batcherPrivateKey": "{{.keys.batcher_ecdsa.private_key}}", + "alignedLayerServiceManager": "{{.addresses.Aligned.alignedLayerServiceManager}}" + }, + "amounts": { + "gasForAggregator": "300000", + "gasPerProof": "21000" + }, + "permissions": { + "owner": "{{.deployer_address}}" + } + } + + aggregator_config: + files: + config-aggregator.yaml: + template: | + # Common variables for all the services + # 'production' only prints info and above. 'development' also prints debug + environment: "production" + aligned_layer_deployment_config_file_path: "./contracts/script/output/devnet/alignedlayer_deployment_output.json" + eigen_layer_deployment_config_file_path: "./contracts/script/output/devnet/eigenlayer_deployment_output.json" + eth_rpc_url: "{{.http_rpc_url}}" + eth_rpc_url_fallback: "{{.http_rpc_url}}" + eth_ws_url: "{{.ws_rpc_url}}" + eth_ws_url_fallback: "{{.ws_rpc_url}}" + eigen_metrics_ip_port_address: "localhost:9090" + + ## ECDSA Configurations + ecdsa: + private_key_store_path: "keystores/keys/1.ecdsa.key.json" + private_key_store_password: "{{.keys.aggregator_ecdsa.password}}" + + ## BLS Configurations + bls: + private_key_store_path: "keystores/keys/1.bls.key.json" + private_key_store_password: "{{.keys.aggregator_bls.password}}" + + ## Aggregator Configurations + aggregator: + server_ip_port_address: 0.0.0.0:8090 + bls_public_key_compendium_address: "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44" + avs_service_manager_address: "{{.addresses.Aligned.alignedLayerServiceManager}}" + enable_metrics: true + metrics_ip_port_address: 0.0.0.0:9091 + telemetry_ip_port_address: localhost:4001 + 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) + + operator_config: + files: + config-docker.yaml: + template: | + # Common variables for all the services + # 'production' only prints info and above. 'development' also prints debug + environment: "production" + aligned_layer_deployment_config_file_path: "./contracts/script/output/devnet/alignedlayer_deployment_output.json" + eigen_layer_deployment_config_file_path: "./contracts/script/output/devnet/eigenlayer_deployment_output.json" + eth_rpc_url: "{{.http_rpc_url}}" + eth_rpc_url_fallback: "{{.http_rpc_url}}" + eth_ws_url: "{{.ws_rpc_url}}" + eth_ws_url_fallback: "{{.ws_rpc_url}}" + eigen_metrics_ip_port_address: "localhost:9090" + + ## ECDSA Configurations + ecdsa: + private_key_store_path: "keystores/keys/1.ecdsa.key.json" + private_key_store_password: "{{.keys.operator1_ecdsa.password}}" + + ## BLS Configurations + bls: + private_key_store_path: "keystores/keys/1.bls.key.json" + private_key_store_password: "{{.keys.operator1_bls.password}}" + + ## Operator Configurations + operator: + aggregator_rpc_server_ip_port_address: {{.services.aggregator.ip_address}}:8090 + operator_tracker_ip_port_address: http://localhost:3030 + address: {{.keys.operator1_ecdsa.address}} + earnings_receiver_address: {{.keys.operator1_ecdsa.address}} + delegation_approver_address: "0x0000000000000000000000000000000000000000" + staker_opt_out_window_blocks: 0 + metadata_url: "https://yetanotherco.github.io/operator_metadata/metadata.json" + enable_metrics: true + metrics_ip_port_address: localhost:9092 + max_batch_size: 268435456 # 256 MiB + last_processed_batch_filepath: config-files/operator.last_processed_batch.json + + # Operators variables needed for register it in EigenLayer + el_delegation_manager_address: "{{.addresses.EigenLayer.delegationManager}}" + private_key_store_path: keystores/keys/1.ecdsa.key.json + bls_private_key_store_path: keystores/keys/1.bls.key.json + signer_type: local_keystore + chain_id: 31337 + + avs_addresses_merged: + files: + alignedlayer_deployment_output.json: + template: | + { + "addresses": { + "alignedLayerServiceManager": "{{.addresses.Aligned.alignedLayerServiceManager}}", + "batcherPaymentService": "{{.addresses.BatcherPaymentService.batcherPaymentService}}" + } + } + + batcher_config: + files: + config-batcher-docker.yaml: + template: | + # Common variables for all the services + # 'production' only prints info and above. 'development' also prints debug + environment: "production" + aligned_layer_deployment_config_file_path: "/deployment_output/alignedlayer_deployment_output.json" + eigen_layer_deployment_config_file_path: "/deployment_output/eigenlayer_deployment_output.json" + eth_rpc_url: "{{.http_rpc_url}}" + eth_rpc_url_fallback: "{{.http_rpc_url}}" + eth_ws_url: "{{.ws_rpc_url}}" + eth_ws_url_fallback: "{{.ws_rpc_url}}" + eigen_metrics_ip_port_address: "localhost:9090" + + ## ECDSA Configurations + ecdsa: + private_key_store_path: "config-files/keys/1.ecdsa.key.json" + private_key_store_password: "{{.keys.batcher_ecdsa.password}}" + + ## Batcher configurations + batcher: + block_interval: 3 + batch_size_interval: 10 + transaction_wait_timeout: 96000 # 8 blocks + max_proof_size: 67108864 # 64 MiB + max_batch_byte_size: 268435456 # 256 MiB + max_batch_proof_qty: 3000 # 3000 proofs in a batch + eth_ws_reconnects: 99999999999999 + pre_verification_is_enabled: true + metrics_port: 9093 + telemetry_ip_port_address: localhost:4001 + +ethereum_package: + additional_services: + - blockscout + network_params: + # We use anvil's chain ID because 3151908 is not supported by eigenlayer-cli + network_id: "31337" + seconds_per_slot: 3 diff --git a/kurtosis_package/keys.star b/kurtosis_package/keys.star index 241e31d..e24646f 100644 --- a/kurtosis_package/keys.star +++ b/kurtosis_package/keys.star @@ -63,8 +63,7 @@ def generate_keys(plan, egnkey_service_name, key_type, artifact_name): output_dir = "/_output" cmd = "set -e ; rm -rf {output} && \ - egnkey generate --key-type {type} --num-keys 1 --output-dir {output} ; \ - cat {output}/password.txt | tr -d '\n'".format( + egnkey generate --key-type {type} --num-keys 1 --output-dir {output}".format( output=output_dir, type=key_type ) @@ -73,7 +72,6 @@ def generate_keys(plan, egnkey_service_name, key_type, artifact_name): recipe=ExecRecipe(command=["sh", "-c", cmd]), description="Generating " + key_type + " key", ) - password = result["output"] artifact_name = plan.store_service_files( service_name=egnkey_service_name, @@ -82,6 +80,16 @@ def generate_keys(plan, egnkey_service_name, key_type, artifact_name): description="Storing " + key_type + " key", ) + # NOTE: we do this in another step to avoid egnkey's output from being stored + cmd = "set -e ; cat {}/password.txt | tr -d '\n'".format(output_dir) + + result = plan.exec( + service_name=egnkey_service_name, + recipe=ExecRecipe(command=["sh", "-c", cmd]), + description="Extracting keystore password", + ) + password = result["output"] + cmd = "set -e ; cat {}/private_key_hex.txt | tr -d '\n'".format(output_dir) result = plan.exec( diff --git a/src/cmds/flags/flags.go b/src/cmds/flags/flags.go index a2d11d9..12d5928 100644 --- a/src/cmds/flags/flags.go +++ b/src/cmds/flags/flags.go @@ -10,10 +10,13 @@ var DefaultKurtosisPackage string = "github.com/Layr-Labs/avs-devnet/kurtosis_pa //nolint:gochecknoglobals // these are constants var ( - ConfigFilePathFlag = cli.StringFlag{ - Name: "config-file", - Usage: "Path to the devnet configuration file", - Value: "devnet.yaml", + DevnetNameFlag = cli.StringFlag{ + Name: "name", + TakesFile: true, + Aliases: []string{"n"}, + Usage: "Assign a name to the devnet", + Value: "devnet", + DefaultText: "devnet", } // NOTE: this flag is for internal use. diff --git a/src/cmds/get_address.go b/src/cmds/get_address.go index cbf20e5..270c056 100644 --- a/src/cmds/get_address.go +++ b/src/cmds/get_address.go @@ -14,11 +14,7 @@ import ( func GetAddress(ctx *cli.Context) error { args := ctx.Args() - configFileName := ctx.String(flags.ConfigFilePathFlag.Name) - devnetName, err := EnclaveNameFromFileName(configFileName) - if err != nil { - return cli.Exit(err, 1) - } + devnetName := flags.DevnetNameFlag.Get(ctx) kurtosisCtx, err := kurtosis.InitKurtosisContext() if err != nil { diff --git a/src/cmds/get_ports.go b/src/cmds/get_ports.go index 1731ce6..3ffe596 100644 --- a/src/cmds/get_ports.go +++ b/src/cmds/get_ports.go @@ -3,16 +3,14 @@ package cmds import ( "fmt" + "github.com/Layr-Labs/avs-devnet/src/cmds/flags" "github.com/Layr-Labs/avs-devnet/src/kurtosis" "github.com/urfave/cli/v2" "gopkg.in/yaml.v3" ) func GetPorts(ctx *cli.Context) error { - devnetName, _, err := parseArgs(ctx) - if err != nil { - return cli.Exit(err, 1) - } + devnetName := flags.DevnetNameFlag.Get(ctx) kurtosisCtx, err := kurtosis.InitKurtosisContext() if err != nil { diff --git a/src/cmds/init.go b/src/cmds/init.go index 89bca70..a490ab9 100644 --- a/src/cmds/init.go +++ b/src/cmds/init.go @@ -11,7 +11,7 @@ import ( // Creates a new devnet configuration with the given context. func InitCmd(ctx *cli.Context) error { - _, configFileName, err := parseArgs(ctx) + configFileName, err := parseConfigFileName(ctx) if err != nil { return cli.Exit(err, 1) } diff --git a/src/cmds/start.go b/src/cmds/start.go index 990efe9..b4f54b7 100644 --- a/src/cmds/start.go +++ b/src/cmds/start.go @@ -24,7 +24,8 @@ import ( // Starts the devnet with the given context. func StartCmd(ctx *cli.Context) error { pkgName := flags.KurtosisPackageFlag.Get(ctx) - devnetName, configPath, err := parseArgs(ctx) + devnetName := flags.DevnetNameFlag.Get(ctx) + configPath, err := parseConfigFileName(ctx) if err != nil { return cli.Exit(err, 1) } diff --git a/src/cmds/stop.go b/src/cmds/stop.go index 2710cd1..03cd855 100644 --- a/src/cmds/stop.go +++ b/src/cmds/stop.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/Layr-Labs/avs-devnet/src/cmds/flags" "github.com/Layr-Labs/avs-devnet/src/kurtosis" "github.com/urfave/cli/v2" ) @@ -13,12 +14,9 @@ var ErrEnclaveNotExists = errors.New("enclave doesn't exist") // Stops the devnet with the given context. func StopCmd(ctx *cli.Context) error { - devnetName, _, err := parseArgs(ctx) - if err != nil { - return cli.Exit(err, 1) - } + devnetName := flags.DevnetNameFlag.Get(ctx) fmt.Println("Stopping devnet...") - err = Stop(ctx.Context, devnetName) + err := Stop(ctx.Context, devnetName) if errors.Is(err, ErrEnclaveNotExists) { return cli.Exit("Failed to find '"+devnetName+"'. Maybe it's not running?", 1) } else if err != nil { diff --git a/src/cmds/utils.go b/src/cmds/utils.go index 6eac948..7fc9364 100644 --- a/src/cmds/utils.go +++ b/src/cmds/utils.go @@ -3,34 +3,25 @@ package cmds import ( "errors" "os" - "path/filepath" "regexp" "strings" "github.com/urfave/cli/v2" ) -// Parses the main arguments from the given context. -// Returns the devnet name and the configuration file name. -func parseArgs(ctx *cli.Context) (string, string, error) { +// Parses the configuration file path from the positional args. +// Fails if more than one positional arg is provided. +func parseConfigFileName(ctx *cli.Context) (string, error) { args := ctx.Args() if args.Len() > 1 { - return "", "", errors.New("expected exactly 1 argument: ") + return "", errors.New("expected none or 1 argument: []") } fileName := args.First() - var devnetName string - + // TODO: check file exists and support yml extension if fileName == "" { - fileName = "devnet.yaml" - devnetName = "devnet" - } else { - name, err := EnclaveNameFromFileName(fileName) - if err != nil { - return "", "", err - } - devnetName = name + return "devnet.yaml", nil } - return devnetName, fileName, nil + return fileName, nil } // Checks if a file exists at the given path. @@ -39,13 +30,6 @@ func fileExists(filePath string) bool { return !errors.Is(err, os.ErrNotExist) } -// Extracts the devnet name from the given configuration file name. -func EnclaveNameFromFileName(fileName string) (string, error) { - name := filepath.Base(fileName) - name = strings.Split(name, ".")[0] - return ToValidEnclaveName(name) -} - func ToValidEnclaveName(name string) (string, error) { for _, r := range []string{"_", "/", "."} { name = strings.ReplaceAll(name, r, "-")