diff --git a/Operator_Onboarding/.env.example b/Operator_Onboarding/.env.example new file mode 100644 index 0000000..c9c65f8 --- /dev/null +++ b/Operator_Onboarding/.env.example @@ -0,0 +1,20 @@ +PRIVATE_KEY_PERFORMER= +PRIVATE_KEY_AGGREGATOR= + +L2_RPC= +L1_RPC= + +IPFS_HOST= +PINATA_API_KEY= +PINATA_SECRET_API_KEY= + + +ATTESTATION_CENTER_ADDRESS= +OTHENTIC_REGISTRY_ADDRESS= +AVS_GOVERNANCE_ADDRESS= + +AVS_WEBAPI=10.8.0.42 +# NOTICE: Bootstrap is also aggregator +OTHENTIC_BOOTSTRAP_IP=10.8.0.69 +OTHENTIC_BOOTSTRAP_ID=12D3KooWBNFG1QjuF3UKAKvqhdXcxh9iBmj88cM5eU2EK5Pa91KB +OTHENTIC_BOOTSTRAP_SEED=97a64de0fb18532d4ce56fb35b730aedec993032b533f783b04c9175d465d9bf diff --git a/Operator_Onboarding/Dockerfile.aggregator b/Operator_Onboarding/Dockerfile.aggregator new file mode 100644 index 0000000..34d9c86 --- /dev/null +++ b/Operator_Onboarding/Dockerfile.aggregator @@ -0,0 +1,13 @@ +FROM node:18 + +RUN npm install -g npm@10.5.0 + +ARG NPM_TOKEN=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 + +WORKDIR /app + +RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > $HOME/.npmrc + +RUN npm i -g @othentic/othentic-cli + +ENTRYPOINT [ "othentic-cli" ] diff --git a/Operator_Onboarding/Dockerfile.operator b/Operator_Onboarding/Dockerfile.operator new file mode 100644 index 0000000..8c0cfdd --- /dev/null +++ b/Operator_Onboarding/Dockerfile.operator @@ -0,0 +1,29 @@ +FROM node:18 + +# NOTICE!!! +# Run from root directory of the project, not from Operator_Onboarding directory + +RUN npm install -g npm@10.5.0 + +ARG NPM_TOKEN=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 + +# Install CLI +RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > $HOME/.npmrc + +RUN npm i -g @othentic/othentic-cli + +# Copy AVS WebAPI +COPY Price_Oracle_AVS_JS/AVS_WebAPI /app/AVS_WebAPI + +WORKDIR /app/AVS_WebAPI + +RUN npm install + +WORKDIR /app + +# Copy entrypoint script +COPY Operator_Onboarding/entrypoint-operator.sh /usr/local/bin/ + +RUN chmod +x /usr/local/bin/entrypoint-operator.sh + +ENTRYPOINT [ "entrypoint-operator.sh" ] diff --git a/Operator_Onboarding/README.md b/Operator_Onboarding/README.md new file mode 100644 index 0000000..d9b91e7 --- /dev/null +++ b/Operator_Onboarding/README.md @@ -0,0 +1,53 @@ +# Operator Onboarding Resources +This folder contains many helpful resources for developing a good operator on-boarding process to AVSs. + +## Operator Onboarding Docker Image +In order to simplify the onboarding process of operators joining an AVS, an AVS can publish an all-in-one docker image for operators to use for various operator activities (registration and running a node). In this folder there is a demo setup for a docker image of that likeness: `Dockerfile.operator`. + +The example uses the `Price_Oracle_AVS_JS` sample present in the samples directory, but this image can be adjusted for other AVSs. + +### Prerequesites +- Foundry +In order to run the example operator onboarding docker image, you need to have already deployed a set of AVS smart contracts. + +### Setup +All the steps are preformed from the root folder `avs-samples`. +This is crucial for the building process of the docker images. + +Copy `.env.example` and fill in environment variables: +``` +cp .env.example .env +``` + +Run the setup script: +``` +chmod +x setup.sh +./setup.sh +``` + +Build the operator docker image: +``` +docker build -f Operator_Onboarding/Dockerfile.operator -t avs-operator . +``` + +To register an operator: +``` +docker run --rm --env-file .env -it avs-operator register +``` + +**You need to register the PRIVATE_KEY you've put in your .env file** + +### Running +To run the AVS operator network, first you need to start the docker compose: +``` +docker-compose -f Operator_Onboarding/docker-compose.aggregator.yml up +``` +This will run the task performer service and the aggregator node. +To add operators to the network, run the command: + +``` +chmod +x ./Operator_Onboarding/run-operator.sh +./Operator_Onboarding/run-operator.sh +``` + +You can view operator node logs through Docker Desktop \ No newline at end of file diff --git a/Operator_Onboarding/docker-compose.aggregator.yml b/Operator_Onboarding/docker-compose.aggregator.yml new file mode 100644 index 0000000..5797eae --- /dev/null +++ b/Operator_Onboarding/docker-compose.aggregator.yml @@ -0,0 +1,43 @@ +# Needs to be ran from root directory of the project + +version: '3.7' +services: + aggregator: + env_file: + - .env + environment: + - PRIVATE_KEY=${PRIVATE_KEY_AGGREGATOR:-${PRIVATE_KEY:-}} + - TASK_PERFORMER=0x0000000000000000000000000000000000000000 + build: + context: . + dockerfile: ./Dockerfile.aggregator + command: ["node", "aggregator", "--json-rpc"] + ports: + - "8545:8545" + - "9876:9876" + networks: + p2p: + ipv4_address: ${OTHENTIC_BOOTSTRAP_IP} + task-performer: + env_file: + - .env + build: + context: ../Price_Oracle_AVS_JS/Task_Performer + dockerfile: ./Dockerfile + environment: + - OTHENTIC_CLIENT_RPC_ADDRESS=http://${OTHENTIC_BOOTSTRAP_IP}:8545 + - PRIVATE_KEY=${PRIVATE_KEY_PERFORMER:-${PRIVATE_KEY:-}} + - TASK_PERFORMER=0x0000000000000000000000000000000000000000 + ports: + - "4003:4003" + networks: + - p2p + +networks: + p2p: + external: true + driver: bridge + ipam: + config: + - subnet: 10.8.0.0/16 + - gateway: 10.8.0.1 \ No newline at end of file diff --git a/Operator_Onboarding/entrypoint-operator.sh b/Operator_Onboarding/entrypoint-operator.sh new file mode 100755 index 0000000..4af3e6d --- /dev/null +++ b/Operator_Onboarding/entrypoint-operator.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# NOTICE: docker needs to be ran with env file + +# node +if [ "$1" = "node" ]; then + othentic-cli node attester "/ip4/${OTHENTIC_BOOTSTRAP_IP}/tcp/9876/p2p/${OTHENTIC_BOOTSTRAP_ID}" --avs-webapi "http://${AVS_WEBAPI}" --json-rpc +fi + +# avs-webapi +if [ "$1" = "avs-webapi" ]; then + cd AVS_WebAPI + node index.js +fi + +# needs to be ran interactively and deleted immediately +if [ "$1" = "register" ]; then + othentic-cli operator register +fi diff --git a/Operator_Onboarding/run-operator.sh b/Operator_Onboarding/run-operator.sh new file mode 100755 index 0000000..e43d3c5 --- /dev/null +++ b/Operator_Onboarding/run-operator.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Validate private key +cast wallet address $1 || exit 1 + +SCRIPT_PATH="$(realpath "$0")" +SCRIPT_DIR="$(dirname "$SCRIPT_PATH")" + +# Work from the script directory +cd $SCRIPT_DIR + +source .env + +NETWORK_NAME="p2p" +IMAGE_NAME="avs-operator" +AVS_WEBAPI_CONTAINER_NAME="AVS_WebAPI" + +# the name of the operator container is deterministic with respect to the private key. +# we hash the private key, and take the first 8 bytes of the hash in base64 +IDENTIFIER=$(echo -n $1 | openssl dgst -sha256 -binary | xxd -l 4 -p) +OPERATOR_CONTAINER_NAME="AVS_Operator_${IDENTIFIER}" + +# docker start $AVS_WEBAPI_CONTAINER_NAME || docker run --name $AVS_WEBAPI_CONTAINER_NAME -d $IMAGE_NAME --network p2p +# When running multiple AVS operators on the same machine, boot only one instance of AVS WebAPI +docker start $AVS_WEBAPI_CONTAINER_NAME 2>/dev/null || docker run --name $AVS_WEBAPI_CONTAINER_NAME --env-file .env --network p2p --ip $AVS_WEBAPI -d $IMAGE_NAME avs-webapi || exit 1 +docker start $OPERATOR_CONTAINER_NAME 2>/dev/null || docker run --name $OPERATOR_CONTAINER_NAME --env-file .env -e PRIVATE_KEY=$1 --network p2p -d $IMAGE_NAME node $1 || exit 1 + +echo "Operator container is running with name $OPERATOR_CONTAINER_NAME" diff --git a/Operator_Onboarding/setup.sh b/Operator_Onboarding/setup.sh new file mode 100755 index 0000000..b7844b5 --- /dev/null +++ b/Operator_Onboarding/setup.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Name of the Docker network +NETWORK_NAME="p2p" + +# Check if the network already exists +if docker network inspect "$NETWORK_NAME" >/dev/null 2>&1; then + echo "Docker network '$NETWORK_NAME' already exists." +else + # Create the Docker network + docker network create "$NETWORK_NAME" --subnet 10.8.0.0/16 --gateway 10.8.0.1 + echo "Docker network '$NETWORK_NAME' created." +fi \ No newline at end of file