From 6673f4c4f8866a5bd4110ce6afe0fbf7ceaa4c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:33:17 -0300 Subject: [PATCH 1/4] fix: extract keystore's password in independent step (#196) Fixes: #195 This PR fixes the `invalid character '\n' in string literal` error that sometimes happened in our CI. The error was caused by `egnkey generate` printing a "Private key Ignore" message whenever a generated key wasn't 32 bytes long. Since we generated the key and printed the password in the same step, the output of the first command got stored along with the second one. --- kurtosis_package/keys.star | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/kurtosis_package/keys.star b/kurtosis_package/keys.star index 241e31d3..e24646f7 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( From e790bbc273da62c572bed1268b7cdee9c69b2724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:35:02 -0300 Subject: [PATCH 2/4] ci: cache docker images (#186) Closes: #29 --- .github/workflows/ci.yml | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc0ce9a0..984aebf6 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/ From 5786a92032e59bc675229bd27e51235eccf76670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:39:03 -0300 Subject: [PATCH 3/4] feat!: unify cmd args (#194) Closes #90 This PR drops the config file flag and positional argument in all but the `init` and `start` subcommands. It also adds a `--name`/`-n` flag for specifying a name for the devnet (which defaults to `devnet`). --- cmd/avs-devnet/main.go | 35 ++++++++++++++++------------------- src/cmds/flags/flags.go | 11 +++++++---- src/cmds/get_address.go | 6 +----- src/cmds/get_ports.go | 6 ++---- src/cmds/init.go | 2 +- src/cmds/start.go | 3 ++- src/cmds/stop.go | 8 +++----- src/cmds/utils.go | 30 +++++++----------------------- 8 files changed, 39 insertions(+), 62 deletions(-) diff --git a/cmd/avs-devnet/main.go b/cmd/avs-devnet/main.go index 89e0cf86..0e9819d8 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/src/cmds/flags/flags.go b/src/cmds/flags/flags.go index aafa5ce1..635cf401 100644 --- a/src/cmds/flags/flags.go +++ b/src/cmds/flags/flags.go @@ -10,10 +10,13 @@ var DefaultKurtosisPackage string = "" //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 cbf20e56..270c0563 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 1731ce6f..3ffe5962 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 89bca704..a490ab9b 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 990efe9b..b4f54b70 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 2710cd1e..03cd8554 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 6eac948e..7fc9364d 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, "-") From aaf434de709dea6cde4d334cdc26c4af3d4a015f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Gr=C3=BCner?= <47506558+MegaRedHand@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:10:21 -0300 Subject: [PATCH 4/4] feat: add Aligned Layer's AVS example (#30) This PR adds an example that deploys Aligned Layer and starts an operator and aggregator. This isn't enabled in the CI due to images taking too long to build. What's left: - add balance on the `ServiceManager` for the `BatcherPaymentService` at startup. This is needed because the `ServiceManager` overcharges the sender by about 2x, but always reimburses any extra. Note that this was already added, but needs testing. --- Makefile | 4 +- examples/aligned_layer.yaml | 533 ++++++++++++++++++++++++++++++++++++ 2 files changed, 535 insertions(+), 2 deletions(-) create mode 100644 examples/aligned_layer.yaml diff --git a/Makefile b/Makefile index b08a4e77..da3846b2 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/examples/aligned_layer.yaml b/examples/aligned_layer.yaml new file mode 100644 index 00000000..8f0e9a15 --- /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