├── .dockerignore ├── .editorconfig ├── .env.example ├── .gitattributes ├── .gitignore ├── .gitmodules ├── Dockerfile ├── Dockerfile.celestia ├── Dockerfile.services ├── LICENSE ├── README.md ├── backup ├── blockscout ├── README.md ├── docker-compose.yml ├── envs │ ├── common-blockscout.env │ ├── common-frontend.env │ ├── common-smart-contract-verifier.env │ ├── common-stats.env │ └── common-visualizer.env ├── erigon.yml ├── external-backend.yml ├── external-db.yml ├── external-frontend.yml ├── ganache.yml ├── geth-clique-consensus.yml ├── geth.yml ├── hardhat-network.yml ├── microservices.yml ├── proxy │ ├── default.conf.template │ └── microservices.conf.template └── services │ ├── backend.yml │ ├── db.yml │ ├── frontend.yml │ ├── nginx.yml │ ├── redis.yml │ ├── sig-provider.yml │ ├── smart-contract-verifier.yml │ ├── stats.yml │ └── visualizer.yml ├── celestia.env ├── clean ├── deploy ├── deploy-config.example.json ├── deploy-config.modulargames.json ├── docker-compose-celestia.yml ├── docker-compose.yml ├── entrypoints ├── celestia-da.sh ├── op-batcher.sh ├── op-geth.sh ├── op-node.sh └── op-proposer.sh ├── faucet └── docker-compose.yml ├── funding.json ├── grafana.env ├── monitoring ├── grafana │ ├── dashboards │ │ └── op_stack_compose_dashboard.json │ └── provisioning │ │ ├── dashboards │ │ └── all.yml │ │ └── datasources │ │ └── all.yml └── prometheus │ └── prometheus.yml ├── opbatcher.env ├── opgeth.env ├── opnode.env ├── opproposer.env ├── paths.env ├── restore ├── run ├── scripts ├── clone-repos.sh ├── prepare.sh └── utils.sh └── serve ├── .dockerignore ├── .gitignore ├── Dockerfile ├── index.js ├── package-lock.json └── package.json /.dockerignore: -------------------------------------------------------------------------------- 1 | data 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | # end_of_line = lf/crlf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | 8 | [*.{js,ts,json,yml}] 9 | charset = utf-8 10 | indent_style = space 11 | indent_size = 2 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # Global Configuration # 3 | ################################################## 4 | 5 | # SKIP_DEPLOYMENT_CHECK: 'true' skips checking all deployment components, only checks genesis.json and rollup.json; 'false' checks all components. Default: false. 6 | SKIP_DEPLOYMENT_CHECK=false 7 | 8 | # SEQUENCER_MODE: 'true' enables sequencer, runs op-batcher/op-proposer; 'false' disables them. Default: true. 9 | SEQUENCER_MODE=true 10 | 11 | # CELESTIA_MODE: 'true' runs celestia-da service; 'false' disables it. Default: true. 12 | CELESTIA_MODE=false 13 | 14 | ################################################## 15 | # Cloning Configuration # 16 | ################################################## 17 | 18 | # Repository configuration for optimism and op-geth 19 | # If not set, default to the official optimism implementation 20 | 21 | OPTIMISM_REPO_URL=https://github.com/ethereum-optimism/optimism.git 22 | OPTIMISM_BRANCH_OR_COMMIT=v1.9.0 23 | 24 | OP_GETH_REPO_URL=https://github.com/ethereum-optimism/op-geth.git 25 | OP_GETH_BRANCH_OR_COMMIT=v1.101315.3 26 | 27 | ################################################## 28 | # Accounts Info # 29 | ################################################## 30 | 31 | # Admin account 32 | ADMIN_PRIVATE_KEY= 33 | 34 | # Batcher account 35 | BATCHER_PRIVATE_KEY= 36 | 37 | # Proposer account 38 | PROPOSER_PRIVATE_KEY= 39 | 40 | # Sequencer account 41 | SEQUENCER_PRIVATE_KEY= 42 | 43 | # Contract deployer account 44 | DEPLOYER_PRIVATE_KEY=$ADMIN_PRIVATE_KEY 45 | 46 | ################################################## 47 | # L1 RPC Info # 48 | ################################################## 49 | 50 | # The kind of RPC provider, used to inform optimal transactions receipts 51 | # fetching. Valid options: alchemy, quicknode, infura, parity, nethermind, 52 | # debug_geth, erigon, basic, any. 53 | L1_RPC_KIND= 54 | 55 | # RPC URL for the L1 network to interact with 56 | L1_RPC_URL= 57 | 58 | L1_BLOCK_TIME=12 59 | 60 | ################################################## 61 | # Deployment Info # 62 | ################################################## 63 | 64 | # The chain identifier for the L2 network 65 | L2_CHAIN_ID=42069 66 | 67 | L2_BLOCK_TIME=2 68 | 69 | ################################################## 70 | # celestia-da Configuration # 71 | ################################################## 72 | 73 | # These variables are required if the celestia profile is applied 74 | 75 | # Skip celestia da light node sync check 76 | SKIP_HEALTHCHECK=false 77 | 78 | # Necessary because it's used in the build of the celestia-da service and in celestia.env/paths.env 79 | TARGET_FOLDER_NAME=.celestia-light-mocha-4 80 | # Necessary because it's used in the build of the celestia-da service and in celestia.env 81 | P2P_NETWORK=mocha 82 | 83 | # Used in celestia.env/paths.env 84 | CELESTIA_RPC=rpc-mocha.pops.one 85 | CELESTIA_RPC_PORT=26657 86 | CELESTIA_GRPC_PORT=9090 87 | CELESTIA_NAMESPACE= 88 | CELESTIA_KEYRING_MNEMONIC= 89 | CELESTIA_ACCNAME=acc 90 | CELESTIA_NODE_TYPE=light 91 | 92 | ################################################## 93 | # op-node Configuration # 94 | ################################################## 95 | 96 | # Used in opnode.env 97 | P2P_AGENT= 98 | P2P_ADVERTISE_IP= 99 | 100 | ################################################## 101 | # op-geth Configuration # 102 | ################################################## 103 | 104 | # Used in opgeth.env 105 | MINER_ETHERBASE_ADDRESS= 106 | UNLOCK_ADDRESS= 107 | 108 | # If GETH_PASSWORD is set in opgeth.env 109 | PASSWORD=pwd 110 | 111 | ################################################## 112 | # op-proposer Configuration # 113 | ################################################## 114 | 115 | # Used in opproposer.env 116 | L2OO_ADDRESS= 117 | 118 | ################################################## 119 | # Contract Deployment # 120 | ################################################## 121 | 122 | # Optional Tenderly details for simulation link during deployment 123 | TENDERLY_PROJECT= 124 | TENDERLY_USERNAME= 125 | 126 | # Optional Etherscan API key for contract verification 127 | ETHERSCAN_API_KEY= 128 | 129 | ################################################## 130 | # AWS Credentials # 131 | ################################################## 132 | 133 | # AWS Secrets Manager ARN 134 | AWS_SECRET_ARN= 135 | 136 | # AWS Credentials 137 | AWS_ACCESS_KEY_ID= 138 | AWS_SECRET_ACCESS_KEY= 139 | AWS_DEFAULT_REGION= 140 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | data 2 | .env 3 | .env.backup 4 | temp 5 | indexer.env 6 | ui.env 7 | .DS_Store 8 | 9 | blockscout/services/blockscout-db-data 10 | blockscout/services/logs 11 | blockscout/services/redis-data 12 | blockscout/services/stats-db-data 13 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "bridge/indexer"] 2 | path = bridge/indexer 3 | url = https://github.com/upnodedev/opstack-bridge-indexer-v2.git 4 | [submodule "bridge/ui"] 5 | path = bridge/ui 6 | url = https://github.com/upnodedev/opstack-bridge-ui-v2.git 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use Ubuntu as the base image 2 | FROM ubuntu:22.04 3 | 4 | # Set environment variables to non-interactive (this prevents some prompts) 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | ENV NODE_VERSION 20 8 | ENV GO_VERSION 1.21.8 9 | ENV FOUNDRY_VERSION nightly-ef62fdbab638a275fc19a2ff8fe8951c3bd1d9aa 10 | 11 | # Update and install basic dependencies 12 | RUN apt-get update && \ 13 | apt-get install -y git make jq curl wget gettext-base build-essential pkg-config libssl-dev openssl ca-certificates unzip gnupg && \ 14 | apt-get clean && \ 15 | rm -rf /var/lib/apt/lists/* 16 | 17 | # Install Node.js 18 | RUN mkdir -p /etc/apt/keyrings && \ 19 | curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ 20 | echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_VERSION.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ 21 | apt-get update && \ 22 | apt-get install nodejs -y 23 | 24 | # Install PNPM 25 | RUN npm install -g pnpm 26 | 27 | # Install Go 28 | RUN ARCH=$(dpkg --print-architecture) && echo "Architecture: ${ARCH}" && \ 29 | wget https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz -O go.tar.gz && \ 30 | tar -C /usr/local -xzf go.tar.gz && \ 31 | rm go.tar.gz 32 | ENV PATH=$PATH:/usr/local/go/bin 33 | 34 | # Install Rust 35 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 36 | ENV PATH="/root/.cargo/bin:${PATH}" 37 | 38 | # Install Foundry 39 | RUN curl -L https://foundry.paradigm.xyz | bash 40 | ENV PATH="/root/.foundry/bin:${PATH}" 41 | RUN foundryup -v ${FOUNDRY_VERSION} 42 | 43 | # Install AWS CLI version 2 44 | RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \ 45 | unzip awscliv2.zip && \ 46 | ./aws/install && \ 47 | rm -rf awscliv2.zip ./aws 48 | 49 | # Define work directory 50 | WORKDIR /app 51 | 52 | # Copy the scripts 53 | COPY scripts/clone-repos.sh /app/clone-repos.sh 54 | COPY scripts/utils.sh /app/utils.sh 55 | COPY scripts/prepare.sh /app/prepare.sh 56 | 57 | # Set permissions 58 | RUN chmod +x /app/clone-repos.sh 59 | RUN chmod +x /app/prepare.sh 60 | 61 | # MacOS pnpm fix 62 | RUN mkdir -p /app/pnpm/store 63 | RUN pnpm config set store-dir /app/pnpm/store 64 | 65 | # Set the clone-repos.sh script as the entry point 66 | ENTRYPOINT ["/app/prepare.sh"] 67 | -------------------------------------------------------------------------------- /Dockerfile.celestia: -------------------------------------------------------------------------------- 1 | # Use the existing image as a base 2 | FROM ghcr.io/rollkit/celestia-da:v0.13.2 3 | 4 | ENV GO_VERSION 1.21.7 5 | 6 | # Set environment variables to non-interactive 7 | ENV DEBIAN_FRONTEND=noninteractive 8 | 9 | # Ensure we are running as root 10 | USER root 11 | 12 | # Update and install basic dependencies 13 | RUN apk update && \ 14 | apk add --no-cache curl tar wget clang-dev pkgconf openssl-dev jq build-base git ncdu && \ 15 | rm -rf /var/cache/apk/* 16 | 17 | # Install Go 18 | RUN wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz -O go.tar.gz && \ 19 | tar -C /usr/local -xzf go.tar.gz && \ 20 | rm go.tar.gz 21 | ENV PATH=$PATH:/usr/local/go/bin 22 | 23 | # Clone celestia-node and build cel-key 24 | RUN git clone https://github.com/celestiaorg/celestia-node.git && \ 25 | cd celestia-node && \ 26 | go build -o cel-key ./cmd/cel-key && \ 27 | mv cel-key /usr/local/bin/ 28 | 29 | # Define work directory 30 | WORKDIR /app 31 | 32 | COPY ./entrypoints/celestia-da.sh /app/celestia-da.sh 33 | RUN chmod +x /app/celestia-da.sh 34 | -------------------------------------------------------------------------------- /Dockerfile.services: -------------------------------------------------------------------------------- 1 | # Use Ubuntu as the base image 2 | FROM ubuntu:22.04 3 | 4 | # Set environment variables to non-interactive 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | ARG ENTRYPOINT_SCRIPT 8 | 9 | # Update and install basic dependencies 10 | RUN apt-get update && \ 11 | apt-get install -y curl jq ca-certificates unzip && \ 12 | apt-get clean && \ 13 | rm -rf /var/lib/apt/lists/* 14 | 15 | # Install AWS CLI version 2 16 | RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \ 17 | unzip awscliv2.zip && \ 18 | ./aws/install && \ 19 | rm -rf awscliv2.zip ./aws 20 | 21 | # Define work directory 22 | WORKDIR /app 23 | 24 | COPY ./entrypoints/${ENTRYPOINT_SCRIPT} /app/entrypoint.sh 25 | RUN chmod +x /app/entrypoint.sh 26 | 27 | ENTRYPOINT ["/app/entrypoint.sh"] 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Upnode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Upnode Deploy 2 | 3 | Upnode Deploy is an open-source Docker Compose and UI tool for deploying an OP Stack chain. 4 | 5 | Unlike Conduit, which is a paid, closed-source RaaS, Upnode Deploy is an open-source public good that helps developers customize and deploy their OP Stack chain. 6 | 7 | ## Getting Started 8 | 9 | Clone the repository: https://github.com/upnodedev/opstack-compose 10 | 11 | Copy the .env.example file to .env. 12 | 13 | Edit the following sections in the .env file: 14 | 15 | ``` 16 | ################################################## 17 | # Accounts Info # 18 | ################################################## 19 | 20 | # Admin account 21 | ADMIN_PRIVATE_KEY= 22 | 23 | # Batcher account 24 | BATCHER_PRIVATE_KEY= 25 | 26 | # Proposer account 27 | PROPOSER_PRIVATE_KEY= 28 | 29 | # Sequencer account 30 | SEQUENCER_PRIVATE_KEY= 31 | 32 | # Contract deployer account 33 | DEPLOYER_PRIVATE_KEY=$ADMIN_PRIVATE_KEY 34 | 35 | ################################################## 36 | # L1 RPC Info # 37 | ################################################## 38 | 39 | # The kind of RPC provider, used to inform optimal transaction receipts 40 | # fetching. Valid options: alchemy, quicknode, infura, parity, nethermind, 41 | # debug_geth, erigon, basic, any. 42 | L1_RPC_KIND=basic 43 | 44 | # RPC URL for the L1 network to interact with 45 | L1_RPC_URL= 46 | 47 | ################################################## 48 | # Deployment Info # 49 | ################################################## 50 | 51 | # The chain identifier for the L2 network 52 | L2_CHAIN_ID= 53 | ``` 54 | 55 | You can use the same private key for Admin, Batcher, Proposer, and Sequencer for ease of testing. However, this practice is not recommended on the mainnet. 56 | 57 | After editing the .env file, deploy the chain using Docker Compose by running the following command: 58 | 59 | ``` 60 | docker compose --profile sequencer up -d --build 61 | ``` 62 | 63 | Wait for it to deploy the OP Stack chain as a Fraxtal L3. 64 | 65 | Once the deployment is complete, your Fraxtal L3 will be accessible at: 66 | 67 | * **RPC:** http://YOURIPADDRESS:8545 68 | * **WS:** ws://YOURIPADDRESS:8545 69 | 70 | To deploy the Blockscout explorer for your Fraxtal L3 chain, navigate to the blockscout folder and run: 71 | 72 | ``` 73 | docker compose -f geth.yml up -d --build 74 | ``` 75 | 76 | If you want to point a domain name to these endpoints or introduce a rate limit, you can use a reverse proxy such as Nginx or Traefik to handle this job. 77 | 78 | Span batch activated by default! 79 | -------------------------------------------------------------------------------- /backup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if argument is provided 4 | if [ $# -ne 1 ]; then 5 | echo "Usage: ./backup .tar.gz" 6 | exit 1 7 | fi 8 | 9 | # Create backup 10 | echo "Creating backup..." 11 | tar -czvf "$1" --exclude='optimism' --exclude='op-geth' --exclude='bin' --exclude='datadir' --exclude='celestia' -C ./data . 12 | echo "Backup created: $1" 13 | -------------------------------------------------------------------------------- /blockscout/README.md: -------------------------------------------------------------------------------- 1 | # Docker-compose configuration 2 | 3 | Runs Blockscout locally in Docker containers with [docker-compose](https://github.com/docker/compose). 4 | 5 | ## Prerequisites 6 | 7 | - Docker v20.10+ 8 | - Docker-compose 2.x.x+ 9 | - Running Ethereum JSON RPC client 10 | 11 | ## Building Docker containers from source 12 | 13 | ```bash 14 | cd ./docker-compose 15 | docker-compose up --build 16 | ``` 17 | 18 | **Note**: if you don't need to make backend customizations, you can run `docker-compose up` in order to launch from pre-build backend Docker image. This will be much faster. 19 | 20 | This command uses `docker-compose.yml` by-default, which builds the backend of the explorer into the Docker image and runs 9 Docker containers: 21 | 22 | - Postgres 14.x database, which will be available at port 7432 on the host machine. 23 | - Redis database of the latest version. 24 | - Blockscout backend with api at /api path. 25 | - Nginx proxy to bind backend, frontend and microservices. 26 | - Blockscout explorer at http://localhost. 27 | 28 | and 4 containers for microservices (written in Rust): 29 | 30 | - [Stats](https://github.com/blockscout/blockscout-rs/tree/main/stats) service with a separate Postgres 14 DB. 31 | - [Sol2UML visualizer](https://github.com/blockscout/blockscout-rs/tree/main/visualizer) service. 32 | - [Sig-provider](https://github.com/blockscout/blockscout-rs/tree/main/sig-provider) service. 33 | 34 | **Note for Linux users**: Linux users need to run the local node on http://0.0.0.0/ rather than http://127.0.0.1/ 35 | 36 | ## Configs for different Ethereum clients 37 | 38 | The repo contains built-in configs for different JSON RPC clients without need to build the image. 39 | 40 | **Note**: in all below examples, you can use `docker compose` instead of `docker-compose`, if compose v2 plugin is installed in Docker. 41 | 42 | | __JSON RPC Client__ | __Docker compose launch command__ | 43 | | -------- | ------- | 44 | | Erigon | `docker-compose -f erigon.yml up -d` | 45 | | Geth (suitable for Reth as well) | `docker-compose -f geth.yml up -d` | 46 | | Geth Clique | `docker-compose -f geth-clique-consensus.yml up -d` | 47 | | Nethermind, OpenEthereum | `docker-compose -f nethermind up -d` | 48 | | Ganache | `docker-compose -f ganache.yml up -d` | 49 | | HardHat network | `docker-compose -f hardhat-network.yml up -d` | 50 | 51 | - Running only explorer without DB: `docker-compose -f external-db.yml up -d`. In this case, no db container is created. And it assumes that the DB credentials are provided through `DATABASE_URL` environment variable on the backend container. 52 | - Running explorer with external backend: `docker-compose -f external-backend.yml up -d` 53 | - Running explorer with external frontend: `docker-compose -f external-frontend.yml up -d` 54 | - Running all microservices: `docker-compose -f microservices.yml up -d` 55 | 56 | All of the configs assume the Ethereum JSON RPC is running at http://localhost:8545. 57 | 58 | In order to stop launched containers, run `docker-compose -d -f config_file.yml down`, replacing `config_file.yml` with the file name of the config which was previously launched. 59 | 60 | You can adjust BlockScout environment variables: 61 | 62 | - for backend in `./envs/common-blockscout.env` 63 | - for frontend in `./envs/common-frontend.env` 64 | - for stats service in `./envs/common-stats.env` 65 | - for visualizer in `./envs/common-visualizer.env` 66 | 67 | Descriptions of the ENVs are available 68 | 69 | - for [backend](https://docs.blockscout.com/for-developers/information-and-settings/env-variables) 70 | - for [frontend](https://github.com/blockscout/frontend/blob/main/docs/ENVS.md). 71 | 72 | ## Running Docker containers via Makefile 73 | 74 | Prerequisites are the same, as for docker-compose setup. 75 | 76 | Start all containers: 77 | 78 | ```bash 79 | cd ./docker 80 | make start 81 | ``` 82 | 83 | Stop all containers: 84 | 85 | ```bash 86 | cd ./docker 87 | make stop 88 | ``` 89 | 90 | ***Note***: Makefile uses the same .env files since it is running docker-compose services inside. 91 | -------------------------------------------------------------------------------- /blockscout/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | db-init: 10 | extends: 11 | file: ./services/db.yml 12 | service: db-init 13 | 14 | db: 15 | depends_on: 16 | db-init: 17 | condition: service_completed_successfully 18 | extends: 19 | file: ./services/db.yml 20 | service: db 21 | 22 | backend: 23 | depends_on: 24 | - db 25 | - redis-db 26 | extends: 27 | file: ./services/backend.yml 28 | service: backend 29 | # build: 30 | # context: .. 31 | # dockerfile: ./docker/Dockerfile 32 | # args: 33 | # CACHE_EXCHANGE_RATES_PERIOD: "" 34 | # API_V1_READ_METHODS_DISABLED: "false" 35 | # DISABLE_WEBAPP: "false" 36 | # API_V1_WRITE_METHODS_DISABLED: "false" 37 | # CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED: "" 38 | # CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL: "" 39 | # ADMIN_PANEL_ENABLED: "" 40 | # RELEASE_VERSION: 6.3.0 41 | links: 42 | - db:database 43 | environment: 44 | ETHEREUM_JSONRPC_HTTP_URL: http://host.docker.internal:8545/ 45 | ETHEREUM_JSONRPC_TRACE_URL: http://host.docker.internal:8545/ 46 | ETHEREUM_JSONRPC_WS_URL: ws://host.docker.internal:8545/ 47 | CHAIN_ID: '1337' 48 | 49 | visualizer: 50 | extends: 51 | file: ./services/visualizer.yml 52 | service: visualizer 53 | 54 | sig-provider: 55 | extends: 56 | file: ./services/sig-provider.yml 57 | service: sig-provider 58 | 59 | frontend: 60 | depends_on: 61 | - backend 62 | extends: 63 | file: ./services/frontend.yml 64 | service: frontend 65 | 66 | stats-db-init: 67 | extends: 68 | file: ./services/stats.yml 69 | service: stats-db-init 70 | 71 | stats-db: 72 | depends_on: 73 | stats-db-init: 74 | condition: service_completed_successfully 75 | extends: 76 | file: ./services/stats.yml 77 | service: stats-db 78 | 79 | stats: 80 | depends_on: 81 | - stats-db 82 | - backend 83 | extends: 84 | file: ./services/stats.yml 85 | service: stats 86 | 87 | proxy: 88 | depends_on: 89 | - backend 90 | - frontend 91 | - stats 92 | extends: 93 | file: ./services/nginx.yml 94 | service: proxy 95 | -------------------------------------------------------------------------------- /blockscout/envs/common-blockscout.env: -------------------------------------------------------------------------------- 1 | ETHEREUM_JSONRPC_VARIANT=geth 2 | ETHEREUM_JSONRPC_HTTP_URL=http://host.docker.internal:8545/ 3 | # ETHEREUM_JSONRPC_FALLBACK_HTTP_URL= 4 | DATABASE_URL=postgresql://blockscout:ceWb1MeLBEeOIfk65gU8EjF8@db:5432/blockscout 5 | # DATABASE_QUEUE_TARGET 6 | ETHEREUM_JSONRPC_TRACE_URL=http://host.docker.internal:8545/ 7 | # ETHEREUM_JSONRPC_FALLBACK_TRACE_URL= 8 | # ETHEREUM_JSONRPC_FALLBACK_ETH_CALL_URL= 9 | # ETHEREUM_JSONRPC_ETH_CALL_URL= 10 | # ETHEREUM_JSONRPC_HTTP_TIMEOUT= 11 | # CHAIN_TYPE= 12 | NETWORK= 13 | SUBNETWORK=Awesome chain 14 | LOGO=/images/blockscout_logo.svg 15 | # ETHEREUM_JSONRPC_WS_URL= 16 | ETHEREUM_JSONRPC_TRANSPORT=http 17 | ETHEREUM_JSONRPC_DISABLE_ARCHIVE_BALANCES=false 18 | # ETHEREUM_JSONRPC_ARCHIVE_BALANCES_WINDOW=200 19 | # ETHEREUM_JSONRPC_HTTP_HEADERS= 20 | # ETHEREUM_JSONRPC_WAIT_PER_TIMEOUT= 21 | # ETHEREUM_JSONRPC_GETH_TRACE_BY_BLOCK= 22 | IPC_PATH= 23 | NETWORK_PATH=/ 24 | BLOCKSCOUT_HOST= 25 | BLOCKSCOUT_PROTOCOL= 26 | SECRET_KEY_BASE=56NtB48ear7+wMSf0IQuWDAAazhpb31qyc7GiyspBP2vh7t5zlCsF5QDv76chXeN 27 | # CHECK_ORIGIN= 28 | PORT=4000 29 | COIN_NAME= 30 | # METADATA_CONTRACT= 31 | # VALIDATORS_CONTRACT= 32 | # KEYS_MANAGER_CONTRACT= 33 | # REWARDS_CONTRACT= 34 | # TOKEN_BRIDGE_CONTRACT= 35 | EMISSION_FORMAT=DEFAULT 36 | # CHAIN_SPEC_PATH= 37 | # SUPPLY_MODULE= 38 | COIN= 39 | EXCHANGE_RATES_COIN= 40 | # EXCHANGE_RATES_MARKET_CAP_SOURCE= 41 | # EXCHANGE_RATES_TVL_SOURCE= 42 | # EXCHANGE_RATES_PRICE_SOURCE= 43 | # EXCHANGE_RATES_COINGECKO_COIN_ID= 44 | # EXCHANGE_RATES_COINGECKO_SECONDARY_COIN_ID= 45 | # EXCHANGE_RATES_COINGECKO_API_KEY= 46 | # EXCHANGE_RATES_COINMARKETCAP_API_KEY= 47 | # EXCHANGE_RATES_COINMARKETCAP_COIN_ID= 48 | # EXCHANGE_RATES_COINMARKETCAP_SECONDARY_COIN_ID= 49 | # EXCHANGE_RATES_CRYPTOCOMPARE_SECONDARY_COIN_SYMBOL= 50 | POOL_SIZE=80 51 | # EXCHANGE_RATES_COINGECKO_PLATFORM_ID= 52 | # TOKEN_EXCHANGE_RATE_INTERVAL= 53 | # TOKEN_EXCHANGE_RATE_REFETCH_INTERVAL= 54 | # TOKEN_EXCHANGE_RATE_MAX_BATCH_SIZE= 55 | # DISABLE_TOKEN_EXCHANGE_RATE= 56 | POOL_SIZE_API=10 57 | ECTO_USE_SSL=false 58 | # DATADOG_HOST= 59 | # DATADOG_PORT= 60 | # SPANDEX_BATCH_SIZE= 61 | # SPANDEX_SYNC_THRESHOLD= 62 | HEART_BEAT_TIMEOUT=30 63 | # HEART_COMMAND= 64 | # BLOCKSCOUT_VERSION= 65 | RELEASE_LINK= 66 | BLOCK_TRANSFORMER=base 67 | # GRAPHIQL_TRANSACTION= 68 | # BLOCK_RANGES= 69 | # FIRST_BLOCK= 70 | # LAST_BLOCK= 71 | # TRACE_BLOCK_RANGES= 72 | # TRACE_FIRST_BLOCK= 73 | # TRACE_LAST_BLOCK= 74 | # FOOTER_CHAT_LINK= 75 | # FOOTER_FORUM_LINK_ENABLED= 76 | # FOOTER_FORUM_LINK= 77 | # FOOTER_TELEGRAM_LINK_ENABLED= 78 | # FOOTER_TELEGRAM_LINK= 79 | # FOOTER_GITHUB_LINK= 80 | FOOTER_LOGO=/images/blockscout_logo.svg 81 | FOOTER_LINK_TO_OTHER_EXPLORERS=false 82 | FOOTER_OTHER_EXPLORERS={} 83 | SUPPORTED_CHAINS={} 84 | CACHE_BLOCK_COUNT_PERIOD=7200 85 | CACHE_TXS_COUNT_PERIOD=7200 86 | CACHE_ADDRESS_SUM_PERIOD=3600 87 | CACHE_TOTAL_GAS_USAGE_PERIOD=3600 88 | CACHE_ADDRESS_TRANSACTIONS_GAS_USAGE_COUNTER_PERIOD=1800 89 | CACHE_TOKEN_HOLDERS_COUNTER_PERIOD=3600 90 | CACHE_TOKEN_TRANSFERS_COUNTER_PERIOD=3600 91 | CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=1800 92 | CACHE_AVERAGE_BLOCK_PERIOD=1800 93 | CACHE_MARKET_HISTORY_PERIOD=21600 94 | CACHE_ADDRESS_TRANSACTIONS_COUNTER_PERIOD=1800 95 | CACHE_ADDRESS_TOKENS_USD_SUM_PERIOD=3600 96 | CACHE_ADDRESS_TOKEN_TRANSFERS_COUNTER_PERIOD=1800 97 | # CACHE_TRANSACTIONS_24H_STATS_PERIOD= 98 | # CACHE_FRESH_PENDING_TRANSACTIONS_COUNTER_PERIOD= 99 | TOKEN_METADATA_UPDATE_INTERVAL=172800 100 | CONTRACT_VERIFICATION_ALLOWED_SOLIDITY_EVM_VERSIONS=homestead,tangerineWhistle,spuriousDragon,byzantium,constantinople,petersburg,istanbul,berlin,london,paris,shanghai,cancun,default 101 | CONTRACT_VERIFICATION_ALLOWED_VYPER_EVM_VERSIONS=byzantium,constantinople,petersburg,istanbul,berlin,paris,shanghai,cancun,default 102 | # CONTRACT_VERIFICATION_MAX_LIBRARIES=10 103 | CONTRACT_MAX_STRING_LENGTH_WITHOUT_TRIMMING=2040 104 | # CONTRACT_DISABLE_INTERACTION= 105 | # CONTRACT_AUDIT_REPORTS_AIRTABLE_URL= 106 | # CONTRACT_AUDIT_REPORTS_AIRTABLE_API_KEY= 107 | UNCLES_IN_AVERAGE_BLOCK_TIME=false 108 | DISABLE_WEBAPP=false 109 | API_V2_ENABLED=true 110 | API_V1_READ_METHODS_DISABLED=false 111 | API_V1_WRITE_METHODS_DISABLED=false 112 | # API_RATE_LIMIT_DISABLED=true 113 | # API_SENSITIVE_ENDPOINTS_KEY= 114 | API_RATE_LIMIT_TIME_INTERVAL=1s 115 | API_RATE_LIMIT_BY_IP_TIME_INTERVAL=5m 116 | API_RATE_LIMIT=50 117 | API_RATE_LIMIT_BY_KEY=50 118 | API_RATE_LIMIT_BY_WHITELISTED_IP=50 119 | API_RATE_LIMIT_WHITELISTED_IPS= 120 | API_RATE_LIMIT_STATIC_API_KEY= 121 | API_RATE_LIMIT_UI_V2_WITH_TOKEN=5 122 | API_RATE_LIMIT_BY_IP=3000 123 | DISABLE_INDEXER=false 124 | DISABLE_REALTIME_INDEXER=false 125 | DISABLE_CATCHUP_INDEXER=false 126 | INDEXER_DISABLE_ADDRESS_COIN_BALANCE_FETCHER=false 127 | INDEXER_DISABLE_TOKEN_INSTANCE_REALTIME_FETCHER=false 128 | INDEXER_DISABLE_TOKEN_INSTANCE_RETRY_FETCHER=false 129 | INDEXER_DISABLE_TOKEN_INSTANCE_SANITIZE_FETCHER=false 130 | INDEXER_DISABLE_TOKEN_INSTANCE_LEGACY_SANITIZE_FETCHER=false 131 | INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER=false 132 | INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER=false 133 | # INDEXER_DISABLE_CATALOGED_TOKEN_UPDATER_FETCHER= 134 | # INDEXER_DISABLE_BLOCK_REWARD_FETCHER= 135 | # INDEXER_DISABLE_EMPTY_BLOCKS_SANITIZER= 136 | # INDEXER_DISABLE_WITHDRAWALS_FETCHER= 137 | # INDEXER_CATCHUP_BLOCKS_BATCH_SIZE= 138 | # INDEXER_CATCHUP_BLOCKS_CONCURRENCY= 139 | # INDEXER_CATCHUP_BLOCK_INTERVAL= 140 | # INDEXER_EMPTY_BLOCKS_SANITIZER_INTERVAL= 141 | # INDEXER_INTERNAL_TRANSACTIONS_BATCH_SIZE= 142 | # INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY= 143 | # ETHEREUM_JSONRPC_DEBUG_TRACE_TRANSACTION_TIMEOUT= 144 | # INDEXER_BLOCK_REWARD_BATCH_SIZE= 145 | # INDEXER_BLOCK_REWARD_CONCURRENCY= 146 | # INDEXER_TOKEN_INSTANCE_USE_BASE_URI_RETRY= 147 | # INDEXER_TOKEN_INSTANCE_RETRY_REFETCH_INTERVAL= 148 | # INDEXER_TOKEN_INSTANCE_RETRY_BATCH_SIZE=10 149 | # INDEXER_TOKEN_INSTANCE_RETRY_CONCURRENCY= 150 | # INDEXER_TOKEN_INSTANCE_REALTIME_BATCH_SIZE=1 151 | # INDEXER_TOKEN_INSTANCE_REALTIME_CONCURRENCY= 152 | # INDEXER_TOKEN_INSTANCE_SANITIZE_BATCH_SIZE=10 153 | # INDEXER_TOKEN_INSTANCE_SANITIZE_CONCURRENCY= 154 | # INDEXER_TOKEN_INSTANCE_LEGACY_SANITIZE_BATCH_SIZE=10 155 | # INDEXER_TOKEN_INSTANCE_LEGACY_SANITIZE_CONCURRENCY=10 156 | # INDEXER_DISABLE_TOKEN_INSTANCE_ERC_1155_SANITIZE_FETCHER=false 157 | # INDEXER_DISABLE_TOKEN_INSTANCE_ERC_721_SANITIZE_FETCHER=false 158 | # INDEXER_TOKEN_INSTANCE_ERC_1155_SANITIZE_CONCURRENCY=2 159 | # INDEXER_TOKEN_INSTANCE_ERC_1155_SANITIZE_BATCH_SIZE=10 160 | # INDEXER_TOKEN_INSTANCE_ERC_721_SANITIZE_CONCURRENCY=2 161 | # INDEXER_TOKEN_INSTANCE_ERC_721_SANITIZE_BATCH_SIZE=10 162 | # INDEXER_TOKEN_INSTANCE_ERC_721_SANITIZE_TOKENS_BATCH_SIZE=100 163 | # TOKEN_INSTANCE_OWNER_MIGRATION_CONCURRENCY=5 164 | # TOKEN_INSTANCE_OWNER_MIGRATION_BATCH_SIZE=50 165 | # INDEXER_COIN_BALANCES_BATCH_SIZE= 166 | # INDEXER_COIN_BALANCES_CONCURRENCY= 167 | # INDEXER_RECEIPTS_BATCH_SIZE= 168 | # INDEXER_RECEIPTS_CONCURRENCY= 169 | # INDEXER_TOKEN_CONCURRENCY= 170 | # INDEXER_TOKEN_BALANCES_BATCH_SIZE= 171 | # INDEXER_TOKEN_BALANCES_CONCURRENCY= 172 | # INDEXER_TX_ACTIONS_ENABLE= 173 | # INDEXER_TX_ACTIONS_MAX_TOKEN_CACHE_SIZE= 174 | # INDEXER_TX_ACTIONS_REINDEX_FIRST_BLOCK= 175 | # INDEXER_TX_ACTIONS_REINDEX_LAST_BLOCK= 176 | # INDEXER_TX_ACTIONS_REINDEX_PROTOCOLS= 177 | # INDEXER_TX_ACTIONS_AAVE_V3_POOL_CONTRACT= 178 | # INDEXER_POLYGON_EDGE_L1_RPC= 179 | # INDEXER_POLYGON_EDGE_L1_EXIT_HELPER_CONTRACT= 180 | # INDEXER_POLYGON_EDGE_L1_WITHDRAWALS_START_BLOCK= 181 | # INDEXER_POLYGON_EDGE_L1_STATE_SENDER_CONTRACT= 182 | # INDEXER_POLYGON_EDGE_L1_DEPOSITS_START_BLOCK= 183 | # INDEXER_POLYGON_EDGE_L2_STATE_SENDER_CONTRACT= 184 | # INDEXER_POLYGON_EDGE_L2_WITHDRAWALS_START_BLOCK= 185 | # INDEXER_POLYGON_EDGE_L2_STATE_RECEIVER_CONTRACT= 186 | # INDEXER_POLYGON_EDGE_L2_DEPOSITS_START_BLOCK= 187 | # INDEXER_POLYGON_EDGE_ETH_GET_LOGS_RANGE_SIZE= 188 | # INDEXER_POLYGON_ZKEVM_BATCHES_ENABLED= 189 | # INDEXER_POLYGON_ZKEVM_BATCHES_CHUNK_SIZE= 190 | # INDEXER_POLYGON_ZKEVM_BATCHES_RECHECK_INTERVAL= 191 | # INDEXER_POLYGON_ZKEVM_L1_RPC= 192 | # INDEXER_POLYGON_ZKEVM_L1_BRIDGE_START_BLOCK= 193 | # INDEXER_POLYGON_ZKEVM_L1_BRIDGE_CONTRACT= 194 | # INDEXER_POLYGON_ZKEVM_L1_BRIDGE_NATIVE_SYMBOL= 195 | # INDEXER_POLYGON_ZKEVM_L1_BRIDGE_NATIVE_DECIMALS= 196 | # INDEXER_POLYGON_ZKEVM_L2_BRIDGE_START_BLOCK= 197 | # INDEXER_POLYGON_ZKEVM_L2_BRIDGE_CONTRACT= 198 | # INDEXER_ZKSYNC_BATCHES_ENABLED= 199 | # INDEXER_ZKSYNC_BATCHES_CHUNK_SIZE= 200 | # INDEXER_ZKSYNC_NEW_BATCHES_MAX_RANGE= 201 | # INDEXER_ZKSYNC_NEW_BATCHES_RECHECK_INTERVAL= 202 | # INDEXER_ZKSYNC_L1_RPC= 203 | # INDEXER_ZKSYNC_BATCHES_STATUS_RECHECK_INTERVAL= 204 | # INDEXER_REALTIME_FETCHER_MAX_GAP= 205 | # INDEXER_FETCHER_INIT_QUERY_LIMIT= 206 | # INDEXER_TOKEN_BALANCES_FETCHER_INIT_QUERY_LIMIT= 207 | # INDEXER_COIN_BALANCES_FETCHER_INIT_QUERY_LIMIT= 208 | # WITHDRAWALS_FIRST_BLOCK= 209 | # INDEXER_OPTIMISM_L1_RPC= 210 | # INDEXER_OPTIMISM_L1_BATCH_START_BLOCK= 211 | # INDEXER_OPTIMISM_L1_BATCH_INBOX= 212 | # INDEXER_OPTIMISM_L1_BATCH_SUBMITTER= 213 | # INDEXER_OPTIMISM_L1_BATCH_BLOCKS_CHUNK_SIZE= 214 | # INDEXER_OPTIMISM_L2_BATCH_GENESIS_BLOCK_NUMBER= 215 | # INDEXER_OPTIMISM_L1_PORTAL_CONTRACT= 216 | # INDEXER_OPTIMISM_L1_OUTPUT_ROOTS_START_BLOCK= 217 | # INDEXER_OPTIMISM_L1_OUTPUT_ORACLE_CONTRACT= 218 | # INDEXER_OPTIMISM_L1_WITHDRAWALS_START_BLOCK= 219 | # INDEXER_OPTIMISM_L2_WITHDRAWALS_START_BLOCK= 220 | # INDEXER_OPTIMISM_L2_MESSAGE_PASSER_CONTRACT= 221 | # INDEXER_OPTIMISM_L1_DEPOSITS_START_BLOCK= 222 | # INDEXER_OPTIMISM_L1_DEPOSITS_BATCH_SIZE= 223 | # ROOTSTOCK_REMASC_ADDRESS= 224 | # ROOTSTOCK_BRIDGE_ADDRESS= 225 | # ROOTSTOCK_LOCKED_BTC_CACHE_PERIOD= 226 | # ROOTSTOCK_LOCKING_CAP= 227 | # INDEXER_DISABLE_ROOTSTOCK_DATA_FETCHER= 228 | # INDEXER_ROOTSTOCK_DATA_FETCHER_INTERVAL= 229 | # INDEXER_ROOTSTOCK_DATA_FETCHER_BATCH_SIZE= 230 | # INDEXER_ROOTSTOCK_DATA_FETCHER_CONCURRENCY= 231 | # INDEXER_ROOTSTOCK_DATA_FETCHER_DB_BATCH_SIZE= 232 | # INDEXER_BEACON_RPC_URL=http://localhost:5052 233 | # INDEXER_DISABLE_BEACON_BLOB_FETCHER= 234 | # INDEXER_BEACON_BLOB_FETCHER_SLOT_DURATION=12 235 | # INDEXER_BEACON_BLOB_FETCHER_REFERENCE_SLOT=8000000 236 | # INDEXER_BEACON_BLOB_FETCHER_REFERENCE_TIMESTAMP=1702824023 237 | # INDEXER_BEACON_BLOB_FETCHER_START_BLOCK=19200000 238 | # INDEXER_BEACON_BLOB_FETCHER_END_BLOCK=0 239 | # TOKEN_ID_MIGRATION_FIRST_BLOCK= 240 | # TOKEN_ID_MIGRATION_CONCURRENCY= 241 | # TOKEN_ID_MIGRATION_BATCH_SIZE= 242 | # INDEXER_INTERNAL_TRANSACTIONS_TRACER_TYPE= 243 | # WEBAPP_URL= 244 | # API_URL= 245 | SHOW_ADDRESS_MARKETCAP_PERCENTAGE=true 246 | CHECKSUM_ADDRESS_HASHES=true 247 | CHECKSUM_FUNCTION=eth 248 | DISABLE_EXCHANGE_RATES=true 249 | TXS_STATS_ENABLED=true 250 | SHOW_PRICE_CHART=false 251 | SHOW_PRICE_CHART_LEGEND=false 252 | SHOW_TXS_CHART=true 253 | TXS_HISTORIAN_INIT_LAG=0 254 | TXS_STATS_DAYS_TO_COMPILE_AT_INIT=10 255 | COIN_BALANCE_HISTORY_DAYS=90 256 | APPS_MENU=true 257 | EXTERNAL_APPS=[] 258 | # GAS_PRICE= 259 | # GAS_PRICE_ORACLE_CACHE_PERIOD= 260 | # GAS_PRICE_ORACLE_SIMPLE_TRANSACTION_GAS= 261 | # GAS_PRICE_ORACLE_NUM_OF_BLOCKS= 262 | # GAS_PRICE_ORACLE_SAFELOW_PERCENTILE= 263 | # GAS_PRICE_ORACLE_AVERAGE_PERCENTILE= 264 | # GAS_PRICE_ORACLE_FAST_PERCENTILE= 265 | # GAS_PRICE_ORACLE_SAFELOW_TIME_COEFFICIENT= 266 | # GAS_PRICE_ORACLE_AVERAGE_TIME_COEFFICIENT= 267 | # GAS_PRICE_ORACLE_FAST_TIME_COEFFICIENT= 268 | # RESTRICTED_LIST= 269 | # RESTRICTED_LIST_KEY= 270 | SHOW_MAINTENANCE_ALERT=false 271 | MAINTENANCE_ALERT_MESSAGE= 272 | CHAIN_ID= 273 | MAX_SIZE_UNLESS_HIDE_ARRAY=50 274 | HIDE_BLOCK_MINER=false 275 | DISPLAY_TOKEN_ICONS=false 276 | RE_CAPTCHA_SECRET_KEY= 277 | RE_CAPTCHA_CLIENT_KEY= 278 | RE_CAPTCHA_V3_SECRET_KEY= 279 | RE_CAPTCHA_V3_CLIENT_KEY= 280 | RE_CAPTCHA_DISABLED=false 281 | JSON_RPC= 282 | # API_RATE_LIMIT_HAMMER_REDIS_URL=redis://redis-db:6379/1 283 | # API_RATE_LIMIT_IS_BLOCKSCOUT_BEHIND_PROXY=false 284 | API_RATE_LIMIT_UI_V2_TOKEN_TTL_IN_SECONDS=18000 285 | FETCH_REWARDS_WAY=trace_block 286 | MICROSERVICE_SC_VERIFIER_ENABLED=true 287 | # MICROSERVICE_SC_VERIFIER_URL=http://smart-contract-verifier:8050/ 288 | # MICROSERVICE_SC_VERIFIER_TYPE=sc_verifier 289 | MICROSERVICE_SC_VERIFIER_URL=https://eth-bytecode-db.services.blockscout.com/ 290 | MICROSERVICE_SC_VERIFIER_TYPE=eth_bytecode_db 291 | MICROSERVICE_ETH_BYTECODE_DB_INTERVAL_BETWEEN_LOOKUPS=10m 292 | MICROSERVICE_ETH_BYTECODE_DB_MAX_LOOKUPS_CONCURRENCY=10 293 | MICROSERVICE_VISUALIZE_SOL2UML_ENABLED=true 294 | MICROSERVICE_VISUALIZE_SOL2UML_URL=http://visualizer:8050/ 295 | MICROSERVICE_SIG_PROVIDER_ENABLED=true 296 | MICROSERVICE_SIG_PROVIDER_URL=http://sig-provider:8050/ 297 | # MICROSERVICE_BENS_URL= 298 | # MICROSERVICE_BENS_ENABLED= 299 | #MICROSERVICE_ACCOUNT_ABSTRACTION_ENABLED=true 300 | #MICROSERVICE_ACCOUNT_ABSTRACTION_URL= 301 | DECODE_NOT_A_CONTRACT_CALLS=true 302 | # DATABASE_READ_ONLY_API_URL= 303 | # ACCOUNT_DATABASE_URL= 304 | # ACCOUNT_POOL_SIZE= 305 | # ACCOUNT_AUTH0_DOMAIN= 306 | # ACCOUNT_AUTH0_CLIENT_ID= 307 | # ACCOUNT_AUTH0_CLIENT_SECRET= 308 | # ACCOUNT_PUBLIC_TAGS_AIRTABLE_URL= 309 | # ACCOUNT_PUBLIC_TAGS_AIRTABLE_API_KEY= 310 | # ACCOUNT_SENDGRID_API_KEY= 311 | # ACCOUNT_SENDGRID_SENDER= 312 | # ACCOUNT_SENDGRID_TEMPLATE= 313 | # ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL= 314 | # ACCOUNT_PRIVATE_TAGS_LIMIT=2000 315 | # ACCOUNT_WATCHLIST_ADDRESSES_LIMIT=15 316 | ACCOUNT_CLOAK_KEY= 317 | ACCOUNT_ENABLED=false 318 | ACCOUNT_REDIS_URL=redis://redis-db:6379 319 | EIP_1559_ELASTICITY_MULTIPLIER=2 320 | # MIXPANEL_TOKEN= 321 | # MIXPANEL_URL= 322 | # AMPLITUDE_API_KEY= 323 | # AMPLITUDE_URL= 324 | # IPFS_GATEWAY_URL= 325 | # ADDRESSES_TABS_COUNTERS_TTL=10m 326 | # DENORMALIZATION_MIGRATION_BATCH_SIZE= 327 | # DENORMALIZATION_MIGRATION_CONCURRENCY= 328 | # TOKEN_TRANSFER_TOKEN_TYPE_MIGRATION_BATCH_SIZE= 329 | # TOKEN_TRANSFER_TOKEN_TYPE_MIGRATION_CONCURRENCY= 330 | # SANITIZE_INCORRECT_NFT_BATCH_SIZE= 331 | # SANITIZE_INCORRECT_NFT_CONCURRENCY= 332 | SOURCIFY_INTEGRATION_ENABLED=false 333 | SOURCIFY_SERVER_URL= 334 | SOURCIFY_REPO_URL= 335 | SHOW_TENDERLY_LINK=false 336 | TENDERLY_CHAIN_PATH= 337 | # SOLIDITYSCAN_CHAIN_ID= 338 | # SOLIDITYSCAN_API_TOKEN= 339 | # NOVES_FI_BASE_API_URL= 340 | # NOVES_FI_CHAIN_NAME= 341 | # NOVES_FI_API_TOKEN= 342 | # BRIDGED_TOKENS_ENABLED= 343 | # BRIDGED_TOKENS_ETH_OMNI_BRIDGE_MEDIATOR= 344 | # BRIDGED_TOKENS_BSC_OMNI_BRIDGE_MEDIATOR= 345 | # BRIDGED_TOKENS_POA_OMNI_BRIDGE_MEDIATOR= 346 | # BRIDGED_TOKENS_AMB_BRIDGE_MEDIATORS 347 | # BRIDGED_TOKENS_FOREIGN_JSON_RPC -------------------------------------------------------------------------------- /blockscout/envs/common-frontend.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_API_HOST=localhost:4240 2 | NEXT_PUBLIC_API_PROTOCOL=http 3 | NEXT_PUBLIC_STATS_API_HOST=http://localhost:8080 4 | NEXT_PUBLIC_NETWORK_NAME=Awesome chain 5 | NEXT_PUBLIC_NETWORK_SHORT_NAME=Awesome chain 6 | NEXT_PUBLIC_NETWORK_ID=5 7 | NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether 8 | NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH 9 | NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 10 | NEXT_PUBLIC_API_BASE_PATH=/ 11 | NEXT_PUBLIC_APP_HOST=localhost:4240 12 | NEXT_PUBLIC_APP_PROTOCOL=http 13 | NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] 14 | NEXT_PUBLIC_VISUALIZE_API_HOST=http://localhost:8081 15 | NEXT_PUBLIC_IS_TESTNET=true 16 | NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws 17 | NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml -------------------------------------------------------------------------------- /blockscout/envs/common-smart-contract-verifier.env: -------------------------------------------------------------------------------- 1 | # Those are examples of existing configuration variables and their default values. 2 | # When uncommented, they would overwrite corresponding values from `base.toml` 3 | # configuration file. 4 | 5 | SMART_CONTRACT_VERIFIER__SERVER__HTTP__ENABLED=true 6 | SMART_CONTRACT_VERIFIER__SERVER__HTTP__ADDR=0.0.0.0:8050 7 | SMART_CONTRACT_VERIFIER__SERVER__HTTP__MAX_BODY_SIZE=2097152 8 | 9 | SMART_CONTRACT_VERIFIER__SERVER__GRPC__ENABLED=false 10 | SMART_CONTRACT_VERIFIER__SERVER__GRPC__ADDR=0.0.0.0:8051 11 | 12 | SMART_CONTRACT_VERIFIER__SOLIDITY__ENABLED=true 13 | SMART_CONTRACT_VERIFIER__SOLIDITY__COMPILERS_DIR=/tmp/solidity-compilers 14 | SMART_CONTRACT_VERIFIER__SOLIDITY__REFRESH_VERSIONS_SCHEDULE=0 0 * * * * * 15 | 16 | # It depends on the OS you are running the service on 17 | SMART_CONTRACT_VERIFIER__SOLIDITY__FETCHER__LIST__LIST_URL=https://solc-bin.ethereum.org/linux-amd64/list.json 18 | #SMART_CONTRACT_VERIFIER__SOLIDITY__FETCHER__LIST__LIST_URL=https://solc-bin.ethereum.org/macosx-amd64/list.json 19 | #SMART_CONTRACT_VERIFIER__SOLIDITY__FETCHER__LIST__LIST_URL=https://solc-bin.ethereum.org/windows-amd64/list.json 20 | 21 | SMART_CONTRACT_VERIFIER__VYPER__ENABLED=true 22 | SMART_CONTRACT_VERIFIER__VYPER__COMPILERS_DIR=/tmp/vyper-compilers 23 | SMART_CONTRACT_VERIFIER__VYPER__REFRESH_VERSIONS_SCHEDULE=0 0 * * * * * 24 | 25 | # It depends on the OS you are running the service on 26 | SMART_CONTRACT_VERIFIER__VYPER__FETCHER__LIST__LIST_URL=https://raw.githubusercontent.com/blockscout/solc-bin/main/vyper.list.json 27 | #SMART_CONTRACT_VERIFIER__VYPER__FETCHER__LIST__LIST_URL=https://raw.githubusercontent.com/blockscout/solc-bin/main/vyper.macos.list.json 28 | 29 | SMART_CONTRACT_VERIFIER__SOURCIFY__ENABLED=true 30 | SMART_CONTRACT_VERIFIER__SOURCIFY__API_URL=https://sourcify.dev/server/ 31 | SMART_CONTRACT_VERIFIER__SOURCIFY__VERIFICATION_ATTEMPTS=3 32 | SMART_CONTRACT_VERIFIER__SOURCIFY__REQUEST_TIMEOUT=10 33 | 34 | SMART_CONTRACT_VERIFIER__METRICS__ENABLED=false 35 | SMART_CONTRACT_VERIFIER__METRICS__ADDR=0.0.0.0:6060 36 | SMART_CONTRACT_VERIFIER__METRICS__ROUTE=/metrics 37 | 38 | SMART_CONTRACT_VERIFIER__JAEGER__ENABLED=false 39 | SMART_CONTRACT_VERIFIER__JAEGER__AGENT_ENDPOINT=localhost:6831 40 | -------------------------------------------------------------------------------- /blockscout/envs/common-stats.env: -------------------------------------------------------------------------------- 1 | # Those are examples of existing configuration variables and their default values. 2 | # When uncommented, they would overwrite corresponding values from `base.toml` 3 | # configuration file. 4 | 5 | STATS__SERVER__HTTP__ENABLED=true 6 | STATS__SERVER__HTTP__ADDR=0.0.0.0:8050 7 | STATS__SERVER__HTTP__MAX_BODY_SIZE=2097152 8 | 9 | STATS__SERVER__GRPC__ENABLED=false 10 | STATS__SERVER__GRPC__ADDR=0.0.0.0:8051 11 | 12 | STATS__DB_URL= 13 | STATS__BLOCKSCOUT_DB_URL= 14 | STATS__CREATE_DATABASE=false 15 | STATS__RUN_MIGRATIONS=false 16 | STATS__DEFAULT_SCHEDULE=0 0 1 * * * * 17 | STATS__FORCE_UPDATE_ON_START=false 18 | 19 | STATS__METRICS__ENABLED=false 20 | STATS__METRICS__ADDR=0.0.0.0:6060 21 | STATS__METRICS__ROUTE=/metrics 22 | 23 | STATS__JAEGER__ENABLED=false 24 | STATS__JAEGER__AGENT_ENDPOINT=localhost:6831 25 | 26 | STATS__TRACING__ENABLED=true 27 | STATS__TRACING__FORMAT=default 28 | -------------------------------------------------------------------------------- /blockscout/envs/common-visualizer.env: -------------------------------------------------------------------------------- 1 | VISUALIZER__SERVER__GRPC__ENABLED=false 2 | -------------------------------------------------------------------------------- /blockscout/erigon.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | db-init: 10 | extends: 11 | file: ./services/db.yml 12 | service: db-init 13 | 14 | db: 15 | depends_on: 16 | db-init: 17 | condition: service_completed_successfully 18 | extends: 19 | file: ./services/db.yml 20 | service: db 21 | 22 | backend: 23 | depends_on: 24 | - db 25 | - redis-db 26 | extends: 27 | file: ./services/backend.yml 28 | service: backend 29 | links: 30 | - db:database 31 | environment: 32 | ETHEREUM_JSONRPC_VARIANT: 'erigon' 33 | 34 | visualizer: 35 | extends: 36 | file: ./services/visualizer.yml 37 | service: visualizer 38 | 39 | sig-provider: 40 | extends: 41 | file: ./services/sig-provider.yml 42 | service: sig-provider 43 | 44 | frontend: 45 | depends_on: 46 | - backend 47 | extends: 48 | file: ./services/frontend.yml 49 | service: frontend 50 | 51 | stats-db-init: 52 | extends: 53 | file: ./services/stats.yml 54 | service: stats-db-init 55 | 56 | stats-db: 57 | depends_on: 58 | stats-db-init: 59 | condition: service_completed_successfully 60 | extends: 61 | file: ./services/stats.yml 62 | service: stats-db 63 | 64 | stats: 65 | depends_on: 66 | - stats-db 67 | - backend 68 | extends: 69 | file: ./services/stats.yml 70 | service: stats 71 | 72 | proxy: 73 | depends_on: 74 | - backend 75 | - frontend 76 | - stats 77 | extends: 78 | file: ./services/nginx.yml 79 | service: proxy 80 | -------------------------------------------------------------------------------- /blockscout/external-backend.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | db-init: 10 | extends: 11 | file: ./services/db.yml 12 | service: db-init 13 | 14 | db: 15 | depends_on: 16 | db-init: 17 | condition: service_completed_successfully 18 | extends: 19 | file: ./services/db.yml 20 | service: db 21 | 22 | visualizer: 23 | extends: 24 | file: ./services/visualizer.yml 25 | service: visualizer 26 | 27 | sig-provider: 28 | extends: 29 | file: ./services/sig-provider.yml 30 | service: sig-provider 31 | 32 | frontend: 33 | extends: 34 | file: ./services/frontend.yml 35 | service: frontend 36 | 37 | stats-db-init: 38 | extends: 39 | file: ./services/stats.yml 40 | service: stats-db-init 41 | 42 | stats-db: 43 | depends_on: 44 | stats-db-init: 45 | condition: service_completed_successfully 46 | extends: 47 | file: ./services/stats.yml 48 | service: stats-db 49 | 50 | stats: 51 | depends_on: 52 | - stats-db 53 | extends: 54 | file: ./services/stats.yml 55 | service: stats 56 | 57 | proxy: 58 | depends_on: 59 | - frontend 60 | - stats 61 | extends: 62 | file: ./services/nginx.yml 63 | service: proxy 64 | -------------------------------------------------------------------------------- /blockscout/external-db.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | backend: 10 | depends_on: 11 | - redis-db 12 | extends: 13 | file: ./services/backend.yml 14 | service: backend 15 | environment: 16 | ETHEREUM_JSONRPC_VARIANT: 'geth' 17 | 18 | visualizer: 19 | extends: 20 | file: ./services/visualizer.yml 21 | service: visualizer 22 | 23 | sig-provider: 24 | extends: 25 | file: ./services/sig-provider.yml 26 | service: sig-provider 27 | 28 | frontend: 29 | depends_on: 30 | - backend 31 | extends: 32 | file: ./services/frontend.yml 33 | service: frontend 34 | 35 | stats-db-init: 36 | extends: 37 | file: ./services/stats.yml 38 | service: stats-db-init 39 | 40 | stats-db: 41 | depends_on: 42 | stats-db-init: 43 | condition: service_completed_successfully 44 | extends: 45 | file: ./services/stats.yml 46 | service: stats-db 47 | 48 | stats: 49 | depends_on: 50 | - stats-db 51 | - backend 52 | extends: 53 | file: ./services/stats.yml 54 | service: stats 55 | 56 | proxy: 57 | depends_on: 58 | - backend 59 | - frontend 60 | - stats 61 | extends: 62 | file: ./services/nginx.yml 63 | service: proxy 64 | -------------------------------------------------------------------------------- /blockscout/external-frontend.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | db-init: 10 | extends: 11 | file: ./services/db.yml 12 | service: db-init 13 | 14 | db: 15 | depends_on: 16 | db-init: 17 | condition: service_completed_successfully 18 | extends: 19 | file: ./services/db.yml 20 | service: db 21 | 22 | backend: 23 | depends_on: 24 | - db 25 | - redis-db 26 | extends: 27 | file: ./services/backend.yml 28 | service: backend 29 | links: 30 | - db:database 31 | environment: 32 | ETHEREUM_JSONRPC_VARIANT: 'ganache' 33 | ETHEREUM_JSONRPC_WS_URL: ws://host.docker.internal:8545/ 34 | INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER: 'true' 35 | INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER: 'true' 36 | CHAIN_ID: '1337' 37 | 38 | visualizer: 39 | extends: 40 | file: ./services/visualizer.yml 41 | service: visualizer 42 | 43 | sig-provider: 44 | extends: 45 | file: ./services/sig-provider.yml 46 | service: sig-provider 47 | 48 | stats-db-init: 49 | extends: 50 | file: ./services/stats.yml 51 | service: stats-db-init 52 | 53 | stats-db: 54 | depends_on: 55 | stats-db-init: 56 | condition: service_completed_successfully 57 | extends: 58 | file: ./services/stats.yml 59 | service: stats-db 60 | 61 | stats: 62 | depends_on: 63 | - stats-db 64 | - backend 65 | extends: 66 | file: ./services/stats.yml 67 | service: stats 68 | 69 | proxy: 70 | depends_on: 71 | - backend 72 | - stats 73 | extends: 74 | file: ./services/nginx.yml 75 | service: proxy -------------------------------------------------------------------------------- /blockscout/ganache.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | db-init: 10 | extends: 11 | file: ./services/db.yml 12 | service: db-init 13 | 14 | db: 15 | depends_on: 16 | db-init: 17 | condition: service_completed_successfully 18 | extends: 19 | file: ./services/db.yml 20 | service: db 21 | 22 | backend: 23 | depends_on: 24 | - db 25 | - redis-db 26 | extends: 27 | file: ./services/backend.yml 28 | service: backend 29 | links: 30 | - db:database 31 | environment: 32 | ETHEREUM_JSONRPC_VARIANT: 'ganache' 33 | ETHEREUM_JSONRPC_WS_URL: ws://host.docker.internal:8545/ 34 | INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER: 'true' 35 | INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER: 'true' 36 | CHAIN_ID: '1337' 37 | 38 | visualizer: 39 | extends: 40 | file: ./services/visualizer.yml 41 | service: visualizer 42 | 43 | sig-provider: 44 | extends: 45 | file: ./services/sig-provider.yml 46 | service: sig-provider 47 | 48 | frontend: 49 | depends_on: 50 | - backend 51 | extends: 52 | file: ./services/frontend.yml 53 | service: frontend 54 | environment: 55 | NEXT_PUBLIC_NETWORK_ID: '1337' 56 | NEXT_PUBLIC_NETWORK_RPC_URL: http://host.docker.internal:8545/ 57 | 58 | stats-db-init: 59 | extends: 60 | file: ./services/stats.yml 61 | service: stats-db-init 62 | 63 | stats-db: 64 | depends_on: 65 | stats-db-init: 66 | condition: service_completed_successfully 67 | extends: 68 | file: ./services/stats.yml 69 | service: stats-db 70 | 71 | stats: 72 | depends_on: 73 | - stats-db 74 | - backend 75 | extends: 76 | file: ./services/stats.yml 77 | service: stats 78 | 79 | proxy: 80 | depends_on: 81 | - backend 82 | - frontend 83 | - stats 84 | extends: 85 | file: ./services/nginx.yml 86 | service: proxy 87 | -------------------------------------------------------------------------------- /blockscout/geth-clique-consensus.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | db-init: 10 | extends: 11 | file: ./services/db.yml 12 | service: db-init 13 | 14 | db: 15 | depends_on: 16 | db-init: 17 | condition: service_completed_successfully 18 | extends: 19 | file: ./services/db.yml 20 | service: db 21 | 22 | backend: 23 | depends_on: 24 | - db 25 | - redis-db 26 | extends: 27 | file: ./services/backend.yml 28 | service: backend 29 | links: 30 | - db:database 31 | environment: 32 | ETHEREUM_JSONRPC_VARIANT: 'geth' 33 | BLOCK_TRANSFORMER: 'clique' 34 | 35 | visualizer: 36 | extends: 37 | file: ./services/visualizer.yml 38 | service: visualizer 39 | 40 | sig-provider: 41 | extends: 42 | file: ./services/sig-provider.yml 43 | service: sig-provider 44 | 45 | frontend: 46 | depends_on: 47 | - backend 48 | extends: 49 | file: ./services/frontend.yml 50 | service: frontend 51 | 52 | stats-db-init: 53 | extends: 54 | file: ./services/stats.yml 55 | service: stats-db-init 56 | 57 | stats-db: 58 | depends_on: 59 | stats-db-init: 60 | condition: service_completed_successfully 61 | extends: 62 | file: ./services/stats.yml 63 | service: stats-db 64 | 65 | stats: 66 | depends_on: 67 | - stats-db 68 | - backend 69 | extends: 70 | file: ./services/stats.yml 71 | service: stats 72 | 73 | proxy: 74 | depends_on: 75 | - backend 76 | - frontend 77 | - stats 78 | extends: 79 | file: ./services/nginx.yml 80 | service: proxy 81 | -------------------------------------------------------------------------------- /blockscout/geth.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | db-init: 10 | extends: 11 | file: ./services/db.yml 12 | service: db-init 13 | 14 | db: 15 | depends_on: 16 | db-init: 17 | condition: service_completed_successfully 18 | extends: 19 | file: ./services/db.yml 20 | service: db 21 | 22 | backend: 23 | depends_on: 24 | - db 25 | - redis-db 26 | extends: 27 | file: ./services/backend.yml 28 | service: backend 29 | links: 30 | - db:database 31 | environment: 32 | ETHEREUM_JSONRPC_VARIANT: 'geth' 33 | 34 | visualizer: 35 | extends: 36 | file: ./services/visualizer.yml 37 | service: visualizer 38 | 39 | sig-provider: 40 | extends: 41 | file: ./services/sig-provider.yml 42 | service: sig-provider 43 | 44 | frontend: 45 | depends_on: 46 | - backend 47 | extends: 48 | file: ./services/frontend.yml 49 | service: frontend 50 | 51 | stats-db-init: 52 | extends: 53 | file: ./services/stats.yml 54 | service: stats-db-init 55 | 56 | stats-db: 57 | depends_on: 58 | stats-db-init: 59 | condition: service_completed_successfully 60 | extends: 61 | file: ./services/stats.yml 62 | service: stats-db 63 | 64 | stats: 65 | depends_on: 66 | - stats-db 67 | - backend 68 | extends: 69 | file: ./services/stats.yml 70 | service: stats 71 | 72 | proxy: 73 | depends_on: 74 | - backend 75 | - frontend 76 | - stats 77 | extends: 78 | file: ./services/nginx.yml 79 | service: proxy 80 | -------------------------------------------------------------------------------- /blockscout/hardhat-network.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | extends: 6 | file: ./services/redis.yml 7 | service: redis-db 8 | 9 | db-init: 10 | extends: 11 | file: ./services/db.yml 12 | service: db-init 13 | 14 | db: 15 | depends_on: 16 | db-init: 17 | condition: service_completed_successfully 18 | extends: 19 | file: ./services/db.yml 20 | service: db 21 | 22 | backend: 23 | depends_on: 24 | - db 25 | - redis-db 26 | extends: 27 | file: ./services/backend.yml 28 | service: backend 29 | links: 30 | - db:database 31 | environment: 32 | ETHEREUM_JSONRPC_VARIANT: 'geth' 33 | ETHEREUM_JSONRPC_WS_URL: ws://host.docker.internal:8545/ 34 | INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER: 'true' 35 | INDEXER_INTERNAL_TRANSACTIONS_TRACER_TYPE: 'opcode' 36 | CHAIN_ID: '31337' 37 | 38 | visualizer: 39 | extends: 40 | file: ./services/visualizer.yml 41 | service: visualizer 42 | 43 | sig-provider: 44 | extends: 45 | file: ./services/sig-provider.yml 46 | service: sig-provider 47 | 48 | frontend: 49 | depends_on: 50 | - backend 51 | extends: 52 | file: ./services/frontend.yml 53 | service: frontend 54 | environment: 55 | NEXT_PUBLIC_NETWORK_ID: '31337' 56 | NEXT_PUBLIC_NETWORK_RPC_URL: http://host.docker.internal:8545/ 57 | 58 | stats-db-init: 59 | extends: 60 | file: ./services/stats.yml 61 | service: stats-db-init 62 | 63 | stats-db: 64 | depends_on: 65 | stats-db-init: 66 | condition: service_completed_successfully 67 | extends: 68 | file: ./services/stats.yml 69 | service: stats-db 70 | 71 | stats: 72 | depends_on: 73 | - stats-db 74 | - backend 75 | extends: 76 | file: ./services/stats.yml 77 | service: stats 78 | 79 | proxy: 80 | depends_on: 81 | - backend 82 | - frontend 83 | - stats 84 | extends: 85 | file: ./services/nginx.yml 86 | service: proxy 87 | -------------------------------------------------------------------------------- /blockscout/microservices.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | visualizer: 5 | extends: 6 | file: ./services/visualizer.yml 7 | service: visualizer 8 | 9 | sig-provider: 10 | extends: 11 | file: ./services/sig-provider.yml 12 | service: sig-provider 13 | ports: 14 | - 8083:8050 15 | 16 | 17 | sc-verifier: 18 | extends: 19 | file: ./services/smart-contract-verifier.yml 20 | service: smart-contract-verifier 21 | ports: 22 | - 8082:8050 23 | 24 | stats-db-init: 25 | extends: 26 | file: ./services/stats.yml 27 | service: stats-db-init 28 | 29 | stats-db: 30 | depends_on: 31 | stats-db-init: 32 | condition: service_completed_successfully 33 | extends: 34 | file: ./services/stats.yml 35 | service: stats-db 36 | 37 | stats: 38 | depends_on: 39 | - stats-db 40 | - backend 41 | extends: 42 | file: ./services/stats.yml 43 | service: stats 44 | 45 | proxy: 46 | depends_on: 47 | - visualizer 48 | - stats 49 | extends: 50 | file: ./services/nginx.yml 51 | service: proxy 52 | volumes: 53 | - "./proxy/microservices.conf.template:/etc/nginx/templates/default.conf.template" 54 | -------------------------------------------------------------------------------- /blockscout/proxy/default.conf.template: -------------------------------------------------------------------------------- 1 | map $http_upgrade $connection_upgrade { 2 | 3 | default upgrade; 4 | '' close; 5 | } 6 | 7 | server { 8 | listen 4240; 9 | server_name localhost; 10 | proxy_http_version 1.1; 11 | 12 | location ~ ^/(api|socket|sitemap.xml|auth/auth0|auth/auth0/callback|auth/logout) { 13 | proxy_pass ${BACK_PROXY_PASS}; 14 | proxy_http_version 1.1; 15 | proxy_set_header Host "$host"; 16 | proxy_set_header X-Real-IP "$remote_addr"; 17 | proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for"; 18 | proxy_set_header X-Forwarded-Proto "$scheme"; 19 | proxy_set_header Upgrade "$http_upgrade"; 20 | proxy_set_header Connection $connection_upgrade; 21 | proxy_cache_bypass $http_upgrade; 22 | } 23 | location / { 24 | proxy_pass ${FRONT_PROXY_PASS}; 25 | proxy_http_version 1.1; 26 | proxy_set_header Host "$host"; 27 | proxy_set_header X-Real-IP "$remote_addr"; 28 | proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for"; 29 | proxy_set_header X-Forwarded-Proto "$scheme"; 30 | proxy_set_header Upgrade "$http_upgrade"; 31 | proxy_set_header Connection $connection_upgrade; 32 | proxy_cache_bypass $http_upgrade; 33 | } 34 | } 35 | server { 36 | listen 8080; 37 | server_name localhost; 38 | proxy_http_version 1.1; 39 | proxy_hide_header Access-Control-Allow-Origin; 40 | proxy_hide_header Access-Control-Allow-Methods; 41 | add_header 'Access-Control-Allow-Origin' 'http://localhost' always; 42 | add_header 'Access-Control-Allow-Credentials' 'true' always; 43 | add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always; 44 | 45 | location / { 46 | proxy_pass http://stats:8050/; 47 | proxy_http_version 1.1; 48 | proxy_set_header Host "$host"; 49 | proxy_set_header X-Real-IP "$remote_addr"; 50 | proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for"; 51 | proxy_set_header X-Forwarded-Proto "$scheme"; 52 | proxy_set_header Upgrade "$http_upgrade"; 53 | proxy_set_header Connection $connection_upgrade; 54 | proxy_cache_bypass $http_upgrade; 55 | } 56 | } 57 | server { 58 | listen 8081; 59 | server_name localhost; 60 | proxy_http_version 1.1; 61 | proxy_hide_header Access-Control-Allow-Origin; 62 | proxy_hide_header Access-Control-Allow-Methods; 63 | add_header 'Access-Control-Allow-Origin' 'http://localhost' always; 64 | add_header 'Access-Control-Allow-Credentials' 'true' always; 65 | add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always; 66 | add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,x-csrf-token' always; 67 | 68 | location / { 69 | proxy_pass http://visualizer:8050/; 70 | proxy_http_version 1.1; 71 | proxy_buffering off; 72 | proxy_set_header Host "$host"; 73 | proxy_set_header X-Real-IP "$remote_addr"; 74 | proxy_connect_timeout 30m; 75 | proxy_read_timeout 30m; 76 | proxy_send_timeout 30m; 77 | proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for"; 78 | proxy_set_header X-Forwarded-Proto "$scheme"; 79 | proxy_set_header Upgrade "$http_upgrade"; 80 | proxy_set_header Connection $connection_upgrade; 81 | proxy_cache_bypass $http_upgrade; 82 | if ($request_method = 'OPTIONS') { 83 | add_header 'Access-Control-Allow-Origin' 'http://localhost' always; 84 | add_header 'Access-Control-Allow-Credentials' 'true' always; 85 | add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always; 86 | add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,x-csrf-token' always; 87 | add_header 'Access-Control-Max-Age' 1728000; 88 | add_header 'Content-Type' 'text/plain charset=UTF-8'; 89 | add_header 'Content-Length' 0; 90 | return 204; 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /blockscout/proxy/microservices.conf.template: -------------------------------------------------------------------------------- 1 | map $http_upgrade $connection_upgrade { 2 | 3 | default upgrade; 4 | '' close; 5 | } 6 | 7 | server { 8 | listen 8080; 9 | server_name localhost; 10 | proxy_http_version 1.1; 11 | proxy_hide_header Access-Control-Allow-Origin; 12 | proxy_hide_header Access-Control-Allow-Methods; 13 | add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always; 14 | add_header 'Access-Control-Allow-Credentials' 'true' always; 15 | add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always; 16 | 17 | location / { 18 | proxy_pass http://stats:8050/; 19 | proxy_http_version 1.1; 20 | proxy_set_header Host "$host"; 21 | proxy_set_header X-Real-IP "$remote_addr"; 22 | proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for"; 23 | proxy_set_header X-Forwarded-Proto "$scheme"; 24 | proxy_set_header Upgrade "$http_upgrade"; 25 | proxy_set_header Connection $connection_upgrade; 26 | proxy_cache_bypass $http_upgrade; 27 | } 28 | } 29 | server { 30 | listen 8081; 31 | server_name localhost; 32 | proxy_http_version 1.1; 33 | proxy_hide_header Access-Control-Allow-Origin; 34 | proxy_hide_header Access-Control-Allow-Methods; 35 | add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always; 36 | add_header 'Access-Control-Allow-Credentials' 'true' always; 37 | add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always; 38 | add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,x-csrf-token' always; 39 | 40 | location / { 41 | proxy_pass http://visualizer:8050/; 42 | proxy_http_version 1.1; 43 | proxy_buffering off; 44 | proxy_set_header Host "$host"; 45 | proxy_set_header X-Real-IP "$remote_addr"; 46 | proxy_connect_timeout 30m; 47 | proxy_read_timeout 30m; 48 | proxy_send_timeout 30m; 49 | proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for"; 50 | proxy_set_header X-Forwarded-Proto "$scheme"; 51 | proxy_set_header Upgrade "$http_upgrade"; 52 | proxy_set_header Connection $connection_upgrade; 53 | proxy_cache_bypass $http_upgrade; 54 | if ($request_method = 'OPTIONS') { 55 | add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always; 56 | add_header 'Access-Control-Allow-Credentials' 'true' always; 57 | add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always; 58 | add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,x-csrf-token' always; 59 | add_header 'Access-Control-Max-Age' 1728000; 60 | add_header 'Content-Type' 'text/plain charset=UTF-8'; 61 | add_header 'Content-Length' 0; 62 | return 204; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /blockscout/services/backend.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | backend: 5 | image: blockscout/${DOCKER_REPO:-blockscout-optimism}:${DOCKER_TAG:-latest} 6 | pull_policy: always 7 | restart: always 8 | stop_grace_period: 5m 9 | container_name: 'backend' 10 | command: sh -c "bin/blockscout eval \"Elixir.Explorer.ReleaseTasks.create_and_migrate()\" && bin/blockscout start" 11 | extra_hosts: 12 | - 'host.docker.internal:host-gateway' 13 | env_file: 14 | - ../envs/common-blockscout.env 15 | volumes: 16 | - ./logs/:/app/logs/ -------------------------------------------------------------------------------- /blockscout/services/db.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | db-init: 5 | image: postgres:15 6 | volumes: 7 | - ./blockscout-db-data:/var/lib/postgresql/data 8 | entrypoint: 9 | - sh 10 | - -c 11 | - | 12 | chown -R 2000:2000 /var/lib/postgresql/data 13 | 14 | db: 15 | image: postgres:15 16 | user: 2000:2000 17 | shm_size: 256m 18 | restart: always 19 | container_name: 'db' 20 | command: postgres -c 'max_connections=200' -c 'client_connection_check_interval=60000' 21 | environment: 22 | POSTGRES_DB: 'blockscout' 23 | POSTGRES_USER: 'blockscout' 24 | POSTGRES_PASSWORD: 'ceWb1MeLBEeOIfk65gU8EjF8' 25 | ports: 26 | - target: 5432 27 | published: 7432 28 | volumes: 29 | - ./blockscout-db-data:/var/lib/postgresql/data 30 | healthcheck: 31 | test: ["CMD-SHELL", "pg_isready -U blockscout -d blockscout"] 32 | interval: 10s 33 | timeout: 5s 34 | retries: 5 35 | start_period: 10s 36 | -------------------------------------------------------------------------------- /blockscout/services/frontend.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | frontend: 5 | image: ghcr.io/blockscout/frontend:${FRONTEND_DOCKER_TAG:-latest} 6 | pull_policy: always 7 | platform: linux/amd64 8 | restart: always 9 | container_name: 'frontend' 10 | env_file: 11 | - ../envs/common-frontend.env 12 | -------------------------------------------------------------------------------- /blockscout/services/nginx.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | proxy: 5 | image: nginx 6 | container_name: proxy 7 | extra_hosts: 8 | - 'host.docker.internal:host-gateway' 9 | volumes: 10 | - "../proxy:/etc/nginx/templates" 11 | environment: 12 | BACK_PROXY_PASS: ${BACK_PROXY_PASS:-http://backend:4000} 13 | FRONT_PROXY_PASS: ${FRONT_PROXY_PASS:-http://frontend:3000} 14 | ports: 15 | - target: 4240 16 | published: 4240 17 | - target: 8080 18 | published: 8080 19 | - target: 8081 20 | published: 8081 21 | -------------------------------------------------------------------------------- /blockscout/services/redis.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | redis-db: 5 | image: 'redis:alpine' 6 | container_name: redis-db 7 | command: redis-server 8 | volumes: 9 | - ./redis-data:/data 10 | -------------------------------------------------------------------------------- /blockscout/services/sig-provider.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | sig-provider: 5 | image: ghcr.io/blockscout/sig-provider:${SIG_PROVIDER_DOCKER_TAG:-latest} 6 | pull_policy: always 7 | platform: linux/amd64 8 | restart: always 9 | container_name: 'sig-provider' 10 | -------------------------------------------------------------------------------- /blockscout/services/smart-contract-verifier.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | smart-contract-verifier: 5 | image: ghcr.io/blockscout/smart-contract-verifier:${SMART_CONTRACT_VERIFIER_DOCKER_TAG:-latest} 6 | pull_policy: always 7 | platform: linux/amd64 8 | restart: always 9 | container_name: 'smart-contract-verifier' 10 | env_file: 11 | - ../envs/common-smart-contract-verifier.env 12 | -------------------------------------------------------------------------------- /blockscout/services/stats.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | stats-db-init: 5 | image: postgres:15 6 | volumes: 7 | - ./stats-db-data:/var/lib/postgresql/data 8 | entrypoint: 9 | - sh 10 | - -c 11 | - | 12 | chown -R 2000:2000 /var/lib/postgresql/data 13 | 14 | stats-db: 15 | image: postgres:15 16 | user: 2000:2000 17 | shm_size: 256m 18 | restart: always 19 | container_name: 'stats-db' 20 | command: postgres -c 'max_connections=200' 21 | environment: 22 | POSTGRES_DB: 'stats' 23 | POSTGRES_USER: 'stats' 24 | POSTGRES_PASSWORD: 'n0uejXPl61ci6ldCuE2gQU5Y' 25 | ports: 26 | - target: 5432 27 | published: 7433 28 | volumes: 29 | - ./stats-db-data:/var/lib/postgresql/data 30 | healthcheck: 31 | test: ["CMD-SHELL", "pg_isready -U stats -d stats"] 32 | interval: 10s 33 | timeout: 5s 34 | retries: 5 35 | start_period: 10s 36 | 37 | stats: 38 | image: ghcr.io/blockscout/stats:${STATS_DOCKER_TAG:-latest} 39 | pull_policy: always 40 | platform: linux/amd64 41 | restart: always 42 | container_name: 'stats' 43 | extra_hosts: 44 | - 'host.docker.internal:host-gateway' 45 | env_file: 46 | - ../envs/common-stats.env 47 | environment: 48 | - STATS__DB_URL=postgres://stats:n0uejXPl61ci6ldCuE2gQU5Y@stats-db:5432/stats 49 | - STATS__BLOCKSCOUT_DB_URL=${STATS__BLOCKSCOUT_DB_URL:-postgresql://blockscout:ceWb1MeLBEeOIfk65gU8EjF8@db:5432/blockscout} 50 | - STATS__CREATE_DATABASE=true 51 | - STATS__RUN_MIGRATIONS=true 52 | -------------------------------------------------------------------------------- /blockscout/services/visualizer.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | visualizer: 5 | image: ghcr.io/blockscout/visualizer:${VISUALIZER_DOCKER_TAG:-latest} 6 | pull_policy: always 7 | platform: linux/amd64 8 | restart: always 9 | container_name: 'visualizer' 10 | env_file: 11 | - ../envs/common-visualizer.env 12 | -------------------------------------------------------------------------------- /celestia.env: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # celestia-da Flags # 3 | ################################################## 4 | 5 | DA_GRPC_NAMESPACE=$CELESTIA_NAMESPACE 6 | DA_CORE_IP=${CELESTIA_RPC:-rpc-mocha.pops.one} 7 | DA_CORE_RPC_PORT=${CELESTIA_RPC_PORT:-26657} 8 | DA_CORE_GRPC_PORT=${CELESTIA_GRPC_PORT:-9090} 9 | DA_P2P_NETWORK=$P2P_NETWORK 10 | DA_KEYRING_MNEMONIC=$CELESTIA_KEYRING_MNEMONIC 11 | DA_FOLDER_NAME=$TARGET_FOLDER_NAME 12 | ACCNAME=$CELESTIA_ACCNAME 13 | -------------------------------------------------------------------------------- /clean: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Confirm with the user 4 | read -rp "WARNING: This will clean up the data directory. Are you sure you want to proceed? (yes/no) " confirmation 5 | 6 | if [ "$confirmation" != "yes" ] && [ "$confirmation" != "y" ]; then 7 | echo "Cleanup cancelled." 8 | exit 1 9 | fi 10 | 11 | # Clean up data directory 12 | echo "Cleaning up data directory..." 13 | rm -rf ./data/* 14 | echo "Cleanup complete." 15 | -------------------------------------------------------------------------------- /deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RED='\e[0;31m' 4 | GREEN='\e[0;32m' 5 | YELLOW='\e[0;33m' 6 | CYAN='\e[0;36m' 7 | PURPLE='\e[0;34m' 8 | NC='\e[0m' 9 | 10 | config_path=data/configurations 11 | default_optimism_repo=https://github.com/ethereum-optimism/optimism.git 12 | default_optimism_version=op-node/v1.3.0 13 | default_opgeth_repo=https://github.com/ethereum-optimism/op-geth.git 14 | default_opgeth_version=v1.101304.2 15 | 16 | set -e 17 | 18 | check_existing_deployment() { 19 | if [ -d "$config_path" ] && [ "$(ls -A $config_path)" ]; then 20 | echo -ne "${YELLOW}WARNING${NC}: There is an existing OP Stack deployment. Would you like to ${RED}ERASE all data${NC} and continue? (y/n): " 21 | read -r erase_decision 22 | if [[ "$erase_decision" == "y" ]]; then 23 | echo -e "${RED}Cleaning existing OP Stack deployment...${NC}" 24 | rm -rf ./data/* 25 | echo -e "${GREEN}Cleaning complete.${NC}" 26 | else 27 | echo -e "${CYAN}Exiting without making changes.${NC}" 28 | exit 0 29 | fi 30 | fi 31 | } 32 | 33 | get_l1_chain_id() { 34 | local rpc_url="$1" 35 | local chain_id_hex 36 | chain_id_hex="$(cast rpc eth_chainId --rpc-url "$rpc_url")" || exit 1 37 | chain_id_hex="${chain_id_hex//\"/}" 38 | echo "$((16#${chain_id_hex#*x}))" 39 | } 40 | 41 | detect_l1_kind() { 42 | local rpc_url="$1" 43 | local chain_id="$2" 44 | 45 | case "$rpc_url" in 46 | *alchemy.com*) echo "alchemy" ;; 47 | *quicknode.com* | *quiknode.pro*) [ "$chain_id" -eq 1 ] && echo "quicknode" || echo "basic" ;; 48 | *) echo "basic" ;; 49 | esac 50 | } 51 | 52 | get_address() { 53 | local key_name=$1 54 | local priv_key_var="${key_name}_PRIVATE_KEY" 55 | local address_var="${key_name}_ADDRESS" 56 | 57 | if [ -z "${!priv_key_var}" ]; then 58 | echo "Private key for $key_name not provided." 59 | return 1 60 | fi 61 | 62 | local address 63 | address="$(cast wallet address --private-key "${!priv_key_var}")" || exit 1 64 | eval "$address_var=$address" 65 | } 66 | 67 | display_addresses() { 68 | local max_label_width=0 69 | local address_width=0 70 | 71 | for arg in "$@"; do 72 | local label="${arg%%:*}:" 73 | local address="${arg#*:}" 74 | [ ${#label} -gt "$max_label_width" ] && max_label_width=${#label} 75 | [ ${#address} -gt "$address_width" ] && address_width=${#address} 76 | done 77 | 78 | local border_length=$((max_label_width + address_width + 4)) 79 | local border 80 | border=$(printf '%*s\n' "${border_length}" '' | tr ' ' '-') 81 | 82 | echo -e "${CYAN}${border}${NC}" 83 | for arg in "$@"; do 84 | local label="${arg%%:*}:" 85 | local address="${arg#*:}" 86 | printf "${CYAN}| %-${max_label_width}s %s |${NC}\n" "$label" "$address" 87 | done 88 | echo -e "${CYAN}${border}${NC}" 89 | } 90 | 91 | handle_aws_secrets() { 92 | read -rp "Are you using AWS Secret Manager? (y/n): " aws_decision 93 | if [[ "$aws_decision" == "y" ]]; then 94 | read -rp "AWS Secrets Manager ARN: " AWS_SECRET_ARN 95 | read -rp "AWS Secrets Manager Region: " AWS_REGION 96 | read -rp "AWS Key ID: " AWS_KEY_ID 97 | read -rp "AWS Secret: " AWS_SECRET 98 | 99 | if [ -z "$AWS_SECRET_ARN" ] || [ -z "$AWS_REGION" ] || [ -z "$AWS_KEY_ID" ] || [ -z "$AWS_SECRET" ]; then 100 | echo "AWS Secret Manager ARN, AWS Secret Manager Region, AWS Key ID, AWS Secret are required." 101 | exit 1 102 | fi 103 | 104 | read -rp "Admin private key: " ADMIN_PRIVATE_KEY 105 | get_address "ADMIN" 106 | display_addresses "Admin Address:$ADMIN_ADDRESS" 107 | else 108 | read -rp "Admin private key: " ADMIN_PRIVATE_KEY 109 | get_address "ADMIN" 110 | 111 | read -rp "Batcher private key: " BATCHER_PRIVATE_KEY 112 | get_address "BATCHER" 113 | 114 | read -rp "Proposer private key: " PROPOSER_PRIVATE_KEY 115 | get_address "PROPOSER" 116 | 117 | read -rp "Sequencer private key: " SEQUENCER_PRIVATE_KEY 118 | get_address "SEQUENCER" 119 | 120 | display_addresses "Admin Address:$ADMIN_ADDRESS" "Batcher Address:$BATCHER_ADDRESS" "Proposer Address:$PROPOSER_ADDRESS" "Sequencer Address:$SEQUENCER_ADDRESS" 121 | fi 122 | } 123 | 124 | handle_celestia() { 125 | PS3="> " 126 | echo "Select data availability provider:" 127 | select da_provider in "Ethereum L1" "Celestia"; do 128 | case $da_provider in 129 | "Ethereum L1") 130 | CELESTIA_MODE=false 131 | break 132 | ;; 133 | "Celestia") 134 | CELESTIA_MODE=true 135 | echo "Select Celestia P2P network:" 136 | select celestia_chain in "mocha" "celestia"; do 137 | case $celestia_chain in 138 | "mocha") 139 | CELESTIA_P2P_NETWORK=mocha 140 | break 141 | ;; 142 | "celestia") 143 | CELESTIA_P2P_NETWORK=celestia 144 | break 145 | ;; 146 | *) echo -e "${RED}Invalid option $REPLY${NC}" ;; 147 | esac 148 | done 149 | 150 | read -rp "Celestia target folder name (default: .celestia-light-mocha-4): " TARGET_FOLDER_NAME 151 | TARGET_FOLDER_NAME=${TARGET_FOLDER_NAME:-.celestia-light-mocha-4} 152 | 153 | if [ "$SEQUENCER_MODE" == "false" ]; then 154 | CELESTIA_KEYRING_MNEMONIC="test test test test test test test test test test test junk" 155 | echo "Using dummy mnemonic for RPC node." 156 | else 157 | read -rp "Celestia keyring mnemonic: " CELESTIA_KEYRING_MNEMONIC 158 | [ -z "$CELESTIA_KEYRING_MNEMONIC" ] && echo "Celestia keyring mnemonic is required." && exit 1 159 | fi 160 | 161 | echo -e "${YELLOW}NOTE${NC}: Remember to fund the Celestia wallet if you're running a sequencing node." 162 | 163 | break 164 | ;; 165 | *) echo -e "${RED}Invalid option $REPLY${NC}" ;; 166 | esac 167 | done 168 | } 169 | 170 | create_env_file() { 171 | cat <.env 172 | ################################################## 173 | # Global Configuration # 174 | ################################################## 175 | 176 | # SEQUENCER_MODE: 'true' enables the sequencer, runs op-batcher/op-proposer 177 | # 'false' disables them and starts the RPC node 178 | SEQUENCER_MODE=$SEQUENCER_MODE 179 | 180 | # CELESTIA_MODE: 'true' uses Celestia as data availability (runs the celestia-da service) 181 | # 'false' disables the celestia-da service and uses Ethereum L1 182 | CELESTIA_MODE=$CELESTIA_MODE 183 | 184 | ################################################## 185 | # Cloning Configuration # 186 | ################################################## 187 | 188 | # Repository configuration for optimism and op-geth 189 | # If not set, defaults to the official optimism implementation 190 | 191 | OPTIMISM_REPO_URL=${CUSTOM_OPTIMISM_REPO:-$default_optimism_repo} 192 | OPTIMISM_BRANCH_OR_COMMIT=${CUSTOM_OPTIMISM_BRANCH_OR_COMMIT:-$default_optimism_version} 193 | 194 | OP_GETH_REPO_URL=${CUSTOM_OPGETH_REPO:-$default_opgeth_repo} 195 | OP_GETH_BRANCH_OR_COMMIT=${CUSTOM_OPGETH_BRANCH_OR_COMMIT:-$default_opgeth_version} 196 | 197 | ################################################## 198 | # Accounts Info # 199 | ################################################## 200 | 201 | # Admin account 202 | ADMIN_PRIVATE_KEY=$ADMIN_PRIVATE_KEY 203 | 204 | # Batcher account 205 | BATCHER_PRIVATE_KEY=$BATCHER_PRIVATE_KEY 206 | 207 | # Proposer account 208 | PROPOSER_PRIVATE_KEY=$PROPOSER_PRIVATE_KEY 209 | 210 | # Sequencer account 211 | SEQUENCER_PRIVATE_KEY=$SEQUENCER_PRIVATE_KEY 212 | 213 | # Contract deployer account 214 | DEPLOYER_PRIVATE_KEY=$DEPLOYER_PRIVATE_KEY 215 | 216 | ################################################## 217 | # celestia-da Configuration # 218 | ################################################## 219 | 220 | # These variables are required when CELESTIA_MODE is true 221 | 222 | # Skips celestia-da light node sync check 223 | # In case the node cannot catch up with the last block for a long time 224 | SKIP_HEALTHCHECK=false 225 | 226 | # Necessary because it's used in the build of the celestia-da service and in celestia.env/paths.env 227 | TARGET_FOLDER_NAME=$TARGET_FOLDER_NAME 228 | # Necessary because it's used in the build of the celestia-da service and in celestia.env 229 | P2P_NETWORK=$CELESTIA_P2P_NETWORK 230 | 231 | # Used in celestia.env/paths.env 232 | CELESTIA_KEYRING_MNEMONIC="$CELESTIA_KEYRING_MNEMONIC" 233 | CELESTIA_ACCNAME=acc 234 | 235 | ################################################## 236 | # op-node Configuration # 237 | ################################################## 238 | 239 | # The kind of RPC provider used to inform optimal transactions receipts fetching. 240 | # Valid options: alchemy, quicknode, infura, parity, nethermind, 241 | # debug_geth, erigon, basic, any. 242 | L1_RPC_KIND=$L1_KIND 243 | 244 | # Used in opnode.env 245 | P2P_AGENT= 246 | P2P_ADVERTISE_IP= 247 | 248 | ################################################## 249 | # op-geth Configuration # 250 | ################################################## 251 | 252 | # The chain identifier for the L2 network 253 | L2_CHAIN_ID=$L2_CHAIN_ID 254 | 255 | # Used in opgeth.env 256 | MINER_ETHERBASE_ADDRESS= 257 | UNLOCK_ADDRESS= 258 | 259 | # If GETH_PASSWORD is set in opgeth.env 260 | PASSWORD= 261 | 262 | ################################################## 263 | # op-proposer Configuration # 264 | ################################################## 265 | 266 | # Used in opproposer.env 267 | L2OO_ADDRESS=$L2OO_ADDRESS 268 | 269 | ################################################## 270 | # Contract Deployment # 271 | ################################################## 272 | 273 | # RPC URL for the L1 network to interact with 274 | L1_RPC_URL=$L1_RPC_URL 275 | 276 | # Name for the deployed network 277 | DEPLOYMENT_CONTEXT=$DEPLOY_CONFIG_NAME 278 | 279 | # Optional Tenderly details for simulation link during deployment 280 | TENDERLY_PROJECT= 281 | TENDERLY_USERNAME= 282 | 283 | # Optional Etherscan API key for contract verification 284 | ETHERSCAN_API_KEY= 285 | 286 | ################################################## 287 | # AWS Credentials # 288 | ################################################## 289 | 290 | # AWS Secrets Manager ARN 291 | AWS_SECRET_ARN=$AWS_SECRET_ARN 292 | 293 | # AWS Credentials 294 | AWS_ACCESS_KEY_ID=$AWS_KEY_ID 295 | AWS_SECRET_ACCESS_KEY=$AWS_SECRET 296 | AWS_DEFAULT_REGION=$AWS_REGION 297 | EOF 298 | } 299 | 300 | set_basic_settings() { 301 | read -rp "L1 RPC URL: " L1_RPC_URL 302 | 303 | [ -z "$L1_RPC_URL" ] && echo "L1 RPC URL is required." && exit 1 304 | 305 | L1_CHAIN_ID=$(get_l1_chain_id "$L1_RPC_URL") 306 | L1_KIND=$(detect_l1_kind "$L1_RPC_URL" "$L1_CHAIN_ID") 307 | echo -e "L1 Chain ID: $L1_CHAIN_ID (Detected as ${GREEN}$L1_KIND${NC})" 308 | read -rp "L2 chain ID (default: 42069): " L2_CHAIN_ID 309 | L2_CHAIN_ID=${L2_CHAIN_ID:-42069} 310 | 311 | read -rp "Use custom optimism monorepo (default: $default_optimism_repo <-> $default_optimism_version)? (y/n): " custom_optimism_decision 312 | 313 | if [[ "$custom_optimism_decision" == "y" ]]; then 314 | read -rp "Custom optimism monorepo URL: " CUSTOM_OPTIMISM_REPO 315 | read -rp "Custom optimism branch/tag/commit: " CUSTOM_OPTIMISM_BRANCH_OR_COMMIT 316 | 317 | if [ -z "$CUSTOM_OPTIMISM_REPO" ] || [ -z "$CUSTOM_OPTIMISM_BRANCH_OR_COMMIT" ]; then 318 | echo "Custom optimism monorepo URL and branch/tag/commit are required." 319 | exit 1 320 | fi 321 | fi 322 | 323 | read -rp "Use custom op-geth repository (default: $default_opgeth_repo <-> $default_opgeth_version)? (y/n): " custom_opgeth_decision 324 | 325 | if [[ "$custom_opgeth_decision" == "y" ]]; then 326 | read -rp "Custom op-geth monorepo URL: " CUSTOM_OPGETH_REPO 327 | read -rp "Custom op-geth branch/tag/commit: " CUSTOM_OPGETH_BRANCH_OR_COMMIT 328 | 329 | if [ -z "$CUSTOM_OPGETH_REPO" ] || [ -z "$CUSTOM_OPGETH_BRANCH_OR_COMMIT" ]; then 330 | echo "Custom op-geth monorepo URL and branch/tag/commit are required." 331 | exit 1 332 | fi 333 | fi 334 | } 335 | 336 | set_deploy_config_name() { 337 | read -rp "Deploy config name (default: getting-started): " DEPLOY_CONFIG_NAME 338 | DEPLOY_CONFIG_NAME=${DEPLOY_CONFIG_NAME:-getting-started} 339 | } 340 | 341 | set_l2oo_address() { 342 | if [ ! -f "data/deployments/$DEPLOY_CONFIG_NAME/L2OutputOracleProxy.json" ] && [ -z "$L2OO_ADDRESS" ]; then 343 | echo -e "${YELLOW}WARNING${NC}: data/deployments/$DEPLOY_CONFIG_NAME/L2OutputOracleProxy.json doesn't exist and L2OO_ADDRESS is not set in .env." 344 | read -rp "Op proposer L2OO_ADDRESS: " L2OO_ADDRESS 345 | [ -z "$L2OO_ADDRESS" ] && echo "L2OO_ADDRESS is required." && exit 1 346 | export L2OO_ADDRESS 347 | fi 348 | } 349 | 350 | set_deployer_private_key() { 351 | read -rp "Deployer private key (default: ADMIN_PRIVATE_KEY): " DEPLOYER_PRIVATE_KEY 352 | DEPLOYER_PRIVATE_KEY=${DEPLOYER_PRIVATE_KEY:-$ADMIN_PRIVATE_KEY} 353 | get_address "DEPLOYER" 354 | display_addresses "Deployer Address:$DEPLOYER_ADDRESS" 355 | } 356 | 357 | deploy_new_opstack() { 358 | check_existing_deployment 359 | set_basic_settings 360 | 361 | set_deploy_config_name 362 | handle_aws_secrets 363 | 364 | set_deployer_private_key 365 | 366 | echo -e "${YELLOW}NOTE${NC}: Remember to fund the admin, batcher, proposer, and deployer wallet." 367 | 368 | handle_celestia 369 | 370 | read -rp "Confirm deployment? (y/n): " confirm_deployment 371 | if [[ "$confirm_deployment" == "y" ]]; then 372 | echo "Generating .env and running docker compose up..." 373 | create_env_file 374 | ./run 375 | else 376 | echo -e "${RED}Deployment cancelled.${NC}" 377 | fi 378 | } 379 | 380 | load_end() { 381 | # shellcheck disable=SC1091 382 | source .env 383 | } 384 | 385 | restore_configurations() { 386 | PS3="> " 387 | mkdir -p ./temp 388 | echo "How would you like to restore the configuration?" 389 | select restore_option in "Restore from opstack-compose backup archive" "Download each file from the internet"; do 390 | case $restore_option in 391 | "Restore from opstack-compose backup archive") 392 | read -rp "Backup archive file path / URL: " BACKUP_ARCHIVE_PATH 393 | if [ -z "$BACKUP_ARCHIVE_PATH" ]; then 394 | echo "Backup archive file path / URL is required." 395 | exit 1 396 | fi 397 | 398 | if [[ $BACKUP_ARCHIVE_PATH == http* ]]; then 399 | temp_backup_archive="./temp/backup_archive.tar.gz" 400 | echo "Downloading backup archive from $BACKUP_ARCHIVE_PATH..." 401 | curl -o "$temp_backup_archive" "$BACKUP_ARCHIVE_PATH" 402 | BACKUP_ARCHIVE_PATH="$temp_backup_archive" 403 | fi 404 | 405 | ./restore "$BACKUP_ARCHIVE_PATH" 406 | break 407 | ;; 408 | "Download each file from the internet") 409 | read -rp "rollup.json file path / URL: " ROLLUP_JSON_PATH 410 | if [[ $ROLLUP_JSON_PATH == http* ]]; then 411 | temp_rollup_json="./temp/rollup.json" 412 | echo "Downloading rollup.json from $ROLLUP_JSON_PATH..." 413 | curl -o "$temp_rollup_json" "$ROLLUP_JSON_PATH" 414 | ROLLUP_JSON_PATH="$temp_rollup_json" 415 | fi 416 | 417 | read -rp "genesis.json file path / URL: " GENESIS_JSON_PATH 418 | if [[ $GENESIS_JSON_PATH == http* ]]; then 419 | temp_genesis_json="./temp/genesis.json" 420 | echo "Downloading genesis.json from $GENESIS_JSON_PATH..." 421 | curl -o "$temp_genesis_json" "$GENESIS_JSON_PATH" 422 | GENESIS_JSON_PATH="$temp_genesis_json" 423 | fi 424 | 425 | mkdir -p "$config_path" 426 | mv "$ROLLUP_JSON_PATH" "$config_path/rollup.json" 427 | mv "$GENESIS_JSON_PATH" "$config_path/genesis.json" 428 | echo "Restore complete." 429 | break 430 | ;; 431 | *) echo -e "${RED}Invalid option $REPLY${NC}" ;; 432 | esac 433 | done 434 | } 435 | 436 | restore_existing_opstack_node() { 437 | echo -e "${GREEN}Restoring existing OP Stack node...${NC}" 438 | set_basic_settings 439 | 440 | if [ "$1" == "true" ]; then 441 | echo "Set SEQUENCER_MODE ('true' enables the sequencer, runs op-batcher/op-proposer, 'false' disables them and starts the RPC node)" 442 | read -rp "SEQUENCER_MODE (true/false): " SEQUENCER_MODE 443 | if [[ "$SEQUENCER_MODE" != "true" && "$SEQUENCER_MODE" != "false" ]]; then 444 | echo "Invalid input. Please enter 'true' or 'false'." 445 | exit 1 446 | fi 447 | fi 448 | 449 | if [ ! -f "$config_path/genesis.json" ] && [ ! -f "$config_path/rollup.json" ]; then 450 | restore_configurations 451 | else 452 | echo -e "${YELLOW}NOTE${NC}: The configuration files already exist. Skip restore_configurations..." 453 | fi 454 | 455 | if [ "$SEQUENCER_MODE" == "true" ]; then 456 | set_deploy_config_name 457 | set_l2oo_address 458 | handle_aws_secrets 459 | else 460 | echo "RPC node only. Skip setting up keys or AWS Secret Manager." 461 | fi 462 | 463 | handle_celestia 464 | 465 | read -rp "The .env file will be created or updated. Continue? (y/n): " confirm_run 466 | if [[ "$confirm_run" == "y" ]]; then 467 | echo "Generating .env and running docker compose up..." 468 | 469 | if [ -f ".env" ]; then 470 | cp .env .env.backup 471 | fi 472 | 473 | create_env_file 474 | 475 | ./run 476 | else 477 | echo -e "${RED}Launch canceled.${NC}" 478 | fi 479 | } 480 | 481 | launch_existing_opstack_node() { 482 | if [ ! -f ".env" ]; then 483 | echo "File .env not found." 484 | restore_existing_opstack_node true 485 | return 486 | fi 487 | 488 | load_end 489 | 490 | echo "Your currently Global Configuration in .env:" 491 | echo -e "${PURPLE}SEQUENCER_MODE${NC}: $SEQUENCER_MODE ('true' enables the sequencer, runs op-batcher/op-proposer, 'false' disables them and starts the RPC node)" 492 | 493 | echo -e "${YELLOW}NOTE${NC}: You can change this option if you select 'y'. Press Enter or type 'n' to skip." 494 | read -rp "Update this option in the .env file? (y/n)? " update_decision 495 | 496 | if [[ "$update_decision" == "y" ]]; then 497 | var="SEQUENCER_MODE" 498 | while true; do 499 | read -rp "$var (true/false): " value 500 | if [[ "$value" == "true" || "$value" == "false" ]]; then 501 | break 502 | else 503 | echo "Invalid input. Please enter 'true' or 'false'." 504 | fi 505 | done 506 | if grep -q "^$var=" ".env"; then 507 | sed -i "s/^$var=.*/$var=$value/" ".env" 508 | else 509 | echo "$var=$value" >> ".env" 510 | fi 511 | fi 512 | 513 | load_end 514 | 515 | if [ "$SEQUENCER_MODE" == "true" ]; then 516 | if [ -z "$BATCHER_PRIVATE_KEY" ] || [ -z "$PROPOSER_PRIVATE_KEY" ] || [ -z "$SEQUENCER_PRIVATE_KEY" ]; then 517 | if [ -z "$AWS_SECRET_ARN" ] || [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ] || [ -z "$AWS_DEFAULT_REGION" ]; then 518 | echo "Either BATCHER_PRIVATE_KEY, PROPOSER_PRIVATE_KEY, SEQUENCER_PRIVATE_KEY or AWS_SECRET_ARN, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION are required." 519 | restore_existing_opstack_node 520 | return 521 | fi 522 | fi 523 | 524 | if [ ! -f "data/deployments/$DEPLOYMENT_CONTEXT/L2OutputOracleProxy.json" ] && [ -z "$L2OO_ADDRESS" ]; then 525 | echo -e "${YELLOW}WARNING${NC}: data/deployments/$DEPLOYMENT_CONTEXT/L2OutputOracleProxy.json doesn't exist and L2OO_ADDRESS is not set in .env." 526 | var="L2OO_ADDRESS" 527 | read -rp "$var: " value 528 | if grep -q "^$var=" ".env"; then 529 | sed -i "s/^$var=.*/$var=$value/" ".env" 530 | else 531 | echo "$var=$value" >> ".env" 532 | fi 533 | fi 534 | fi 535 | 536 | load_end 537 | 538 | if [ -f "$config_path/genesis.json" ] && [ -f "$config_path/rollup.json" ]; then 539 | ./run 540 | else 541 | echo "Required config files (genesis.json, rollup.json) not found." 542 | restore_existing_opstack_node 543 | fi 544 | } 545 | 546 | backup_opstack_deployment() { 547 | echo -e "${GREEN}Backing up OP Stack deployment...${NC}" 548 | read -rp "Enter archive file name (tar.gz): " archive_name 549 | 550 | if [[ ! $archive_name =~ \.tar\.gz$ ]]; then 551 | archive_name="${archive_name}.tar.gz" 552 | fi 553 | 554 | ./backup "$archive_name" 555 | } 556 | 557 | main() { 558 | echo "###################################################################################" 559 | echo "# Welcome to opstack-compose OP Stack launcher by Upnode #" 560 | echo "###################################################################################" 561 | echo "" 562 | 563 | PS3="Choose what you want to do: " 564 | options=("Deploy a new OP Stack chain" "Launch a node for an existing OP Stack chain" "Backup OP stack deployment config") 565 | select opt in "${options[@]}"; do 566 | case $opt in 567 | "Deploy a new OP Stack chain") 568 | SEQUENCER_MODE=true 569 | deploy_new_opstack 570 | break 571 | ;; 572 | "Launch a node for an existing OP Stack chain") 573 | launch_existing_opstack_node 574 | break 575 | ;; 576 | "Backup OP stack deployment config") 577 | backup_opstack_deployment 578 | break 579 | ;; 580 | *) echo -e "${RED}Invalid option $REPLY${NC}" ;; 581 | esac 582 | done 583 | } 584 | 585 | main 586 | -------------------------------------------------------------------------------- /deploy-config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "finalSystemOwner": "$GS_ADMIN_ADDRESS", 3 | "superchainConfigGuardian": "$GS_ADMIN_ADDRESS", 4 | 5 | "l1StartingBlockTag": "$L1_BLOCKHASH", 6 | 7 | "l1ChainID": 11155111, 8 | "l2ChainID": $L2_CHAIN_ID, 9 | "l2BlockTime": 2, 10 | "l1BlockTime": 12, 11 | 12 | "maxSequencerDrift": 600, 13 | "sequencerWindowSize": 3600, 14 | "channelTimeout": 300, 15 | 16 | "p2pSequencerAddress": "$GS_SEQUENCER_ADDRESS", 17 | "batchInboxAddress": "0xff00000000000000000000000000000000042069", 18 | "batchSenderAddress": "$GS_BATCHER_ADDRESS", 19 | 20 | "l2OutputOracleSubmissionInterval": 120, 21 | "l2OutputOracleStartingBlockNumber": 0, 22 | "l2OutputOracleStartingTimestamp": $L1_TIMESTAMP, 23 | 24 | "l2OutputOracleProposer": "$GS_PROPOSER_ADDRESS", 25 | "l2OutputOracleChallenger": "$GS_ADMIN_ADDRESS", 26 | 27 | "finalizationPeriodSeconds": 12, 28 | 29 | "proxyAdminOwner": "$GS_ADMIN_ADDRESS", 30 | "baseFeeVaultRecipient": "$GS_ADMIN_ADDRESS", 31 | "l1FeeVaultRecipient": "$GS_ADMIN_ADDRESS", 32 | "sequencerFeeVaultRecipient": "$GS_ADMIN_ADDRESS", 33 | 34 | "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 35 | "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 36 | "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 37 | "baseFeeVaultWithdrawalNetwork": 0, 38 | "l1FeeVaultWithdrawalNetwork": 0, 39 | "sequencerFeeVaultWithdrawalNetwork": 0, 40 | 41 | "gasPriceOracleOverhead": 2100, 42 | "gasPriceOracleScalar": 1000000, 43 | 44 | "enableGovernance": true, 45 | "governanceTokenSymbol": "OP", 46 | "governanceTokenName": "Optimism", 47 | "governanceTokenOwner": "$GS_ADMIN_ADDRESS", 48 | 49 | "l2GenesisBlockGasLimit": "0x1c9c380", 50 | "l2GenesisBlockBaseFeePerGas": "0x3b9aca00", 51 | "l2GenesisRegolithTimeOffset": "0x0", 52 | 53 | "eip1559Denominator": 50, 54 | "eip1559DenominatorCanyon": 250, 55 | "eip1559Elasticity": 10, 56 | 57 | "systemConfigStartBlock": 0, 58 | 59 | "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", 60 | "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000" 61 | } 62 | -------------------------------------------------------------------------------- /deploy-config.modulargames.json: -------------------------------------------------------------------------------- 1 | { 2 | "finalSystemOwner": "$GS_ADMIN_ADDRESS", 3 | "portalGuardian": "$GS_ADMIN_ADDRESS", 4 | 5 | "l1StartingBlockTag": "$L1_BLOCKHASH", 6 | 7 | "l1ChainID": 84532, 8 | "l2ChainID": $L2_CHAIN_ID, 9 | "l2BlockTime": 2, 10 | "l1BlockTime": 2, 11 | 12 | "maxSequencerDrift": 600, 13 | "sequencerWindowSize": 3600, 14 | "channelTimeout": 300, 15 | 16 | "p2pSequencerAddress": "$GS_SEQUENCER_ADDRESS", 17 | "batchInboxAddress": "0xff00000000000000000000000000000000042069", 18 | "batchSenderAddress": "$GS_BATCHER_ADDRESS", 19 | 20 | "l2OutputOracleSubmissionInterval": 120, 21 | "l2OutputOracleStartingBlockNumber": 0, 22 | "l2OutputOracleStartingTimestamp": $L1_TIMESTAMP, 23 | 24 | "l2OutputOracleProposer": "$GS_PROPOSER_ADDRESS", 25 | "l2OutputOracleChallenger": "$GS_ADMIN_ADDRESS", 26 | 27 | "finalizationPeriodSeconds": 12, 28 | 29 | "proxyAdminOwner": "$GS_ADMIN_ADDRESS", 30 | "baseFeeVaultRecipient": "$GS_ADMIN_ADDRESS", 31 | "l1FeeVaultRecipient": "$GS_ADMIN_ADDRESS", 32 | "sequencerFeeVaultRecipient": "$GS_ADMIN_ADDRESS", 33 | 34 | "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 35 | "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 36 | "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 37 | "baseFeeVaultWithdrawalNetwork": 0, 38 | "l1FeeVaultWithdrawalNetwork": 0, 39 | "sequencerFeeVaultWithdrawalNetwork": 0, 40 | 41 | "gasPriceOracleOverhead": 1, 42 | "gasPriceOracleScalar": 500000, 43 | 44 | "enableGovernance": true, 45 | "governanceTokenSymbol": "GAME", 46 | "governanceTokenName": "Modular Games", 47 | "governanceTokenOwner": "$GS_ADMIN_ADDRESS", 48 | 49 | "l2GenesisBlockGasLimit": "0x3b9aca00", 50 | "l2GenesisBlockBaseFeePerGas": "0x3b9aca00", 51 | "l2GenesisRegolithTimeOffset": "0x0", 52 | "l2GenesisCanyonTimeOffset": "0x0", 53 | 54 | "eip1559Denominator": 250, 55 | "eip1559DenominatorCanyon": 250, 56 | "eip1559Elasticity": 6, 57 | 58 | "systemConfigStartBlock": 0, 59 | 60 | "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", 61 | "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000" 62 | } 63 | -------------------------------------------------------------------------------- /docker-compose-celestia.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | celestia-da: 5 | user: root 6 | build: 7 | context: . 8 | dockerfile: Dockerfile.celestia 9 | volumes: 10 | - ./data/celestia:/home/celestia/${TARGET_FOLDER_NAME}/ 11 | command: ["/bin/bash", "-c", "/app/celestia-da.sh"] 12 | env_file: 13 | - .env 14 | - paths.env 15 | - celestia.env 16 | expose: 17 | - 26650 18 | ports: 19 | - "26659:26659" 20 | - "26658:26658" 21 | healthcheck: 22 | test: ["CMD-SHELL", "\ 23 | if [ \"$${SKIP_HEALTHCHECK}\" = \"true\" ]; then \ 24 | curl -f http://localhost:26659/header/1; \ 25 | else \ 26 | authToken=$$(celestia-da ${CELESTIA_NODE_TYPE} auth admin --p2p.network $$DA_P2P_NETWORK) && \ 27 | catch_up_done=$$(curl -s -X POST -H 'Content-Type: application/json' -H \"Authorization: Bearer $$authToken\" --data '{\"id\":1, \"jsonrpc\":\"2.0\", \"method\":\"das.SamplingStats\", \"params\":[]}' http://localhost:26658 | jq -r '.result.catch_up_done') && \ 28 | [ \"$$catch_up_done\" = \"true\" ]; \ 29 | fi"] 30 | interval: 2m 31 | timeout: 10s 32 | retries: 60 33 | stop_grace_period: 10m 34 | restart: always 35 | extra_hosts: 36 | - "host.docker.internal:host-gateway" 37 | profiles: ["celestia"] 38 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | force-clone: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | volumes: 9 | - ./data/optimism:/app/data/optimism 10 | - ./data/op-geth:/app/data/op-geth 11 | - ./data/deployments:/app/data/deployments 12 | - ./data/configurations:/app/data/configurations 13 | - ./data/bin:/app/data/bin 14 | - ./data/datadir:/app/data/datadir 15 | env_file: 16 | - .env 17 | - paths.env 18 | 19 | celestia-da: 20 | user: root 21 | build: 22 | context: . 23 | dockerfile: Dockerfile.celestia 24 | volumes: 25 | - ./data/celestia:/home/celestia/${TARGET_FOLDER_NAME}/ 26 | command: ["/bin/bash", "-c", "/app/celestia-da.sh"] 27 | env_file: 28 | - .env 29 | - paths.env 30 | - celestia.env 31 | expose: 32 | - 26650 33 | ports: 34 | - "26659:26659" 35 | - "26658:26658" 36 | healthcheck: 37 | test: [ 38 | "CMD-SHELL", 39 | "\ 40 | if [ \"$${SKIP_HEALTHCHECK}\" = \"true\" ]; then \ 41 | curl -f http://localhost:26659/header/1; \ 42 | else \ 43 | authToken=$$(celestia-da ${CELESTIA_NODE_TYPE} auth admin --p2p.network $$DA_P2P_NETWORK) && \ 44 | catch_up_done=$$(curl -s -X POST -H 'Content-Type: application/json' -H \"Authorization: Bearer $$authToken\" --data '{\"id\":1, \"jsonrpc\":\"2.0\", \"method\":\"das.SamplingStats\", \"params\":[]}' http://localhost:26658 | jq -r '.result.catch_up_done') && \ 45 | [ \"$$catch_up_done\" = \"true\" ]; \ 46 | fi", 47 | ] 48 | interval: 2m 49 | timeout: 10s 50 | retries: 60 51 | stop_grace_period: 10m 52 | restart: always 53 | extra_hosts: 54 | - "host.docker.internal:host-gateway" 55 | profiles: ["celestia"] 56 | 57 | op-geth: 58 | build: 59 | context: . 60 | dockerfile: Dockerfile.services 61 | args: 62 | ENTRYPOINT_SCRIPT: op-geth.sh 63 | volumes: 64 | - ./data/bin:/app/data/bin 65 | - ./data/datadir:/app/data/datadir 66 | - ./data/configurations:/app/data/configurations 67 | depends_on: 68 | force-clone: 69 | condition: service_completed_successfully 70 | celestia-da: 71 | condition: service_healthy 72 | required: false 73 | env_file: 74 | - .env 75 | - paths.env 76 | - opgeth.env 77 | ports: 78 | - "8545:8545" 79 | - "7303:7303" 80 | - "30333:30333/udp" 81 | - "30333:30333/tcp" 82 | healthcheck: 83 | test: ["CMD-SHELL", "curl -f http://localhost:8545 || exit 1"] 84 | interval: 30s 85 | timeout: 10s 86 | retries: 15 87 | stop_grace_period: 1h 88 | extra_hosts: 89 | - "host.docker.internal:host-gateway" 90 | restart: unless-stopped 91 | 92 | op-node: 93 | build: 94 | context: . 95 | dockerfile: Dockerfile.services 96 | args: 97 | ENTRYPOINT_SCRIPT: op-node.sh 98 | volumes: 99 | - ./data/bin:/app/data/bin 100 | - ./data/configurations:/app/data/configurations 101 | depends_on: 102 | op-geth: 103 | condition: service_healthy 104 | env_file: 105 | - .env 106 | - paths.env 107 | - opnode.env 108 | ports: 109 | - "8547:8547" 110 | - "7300:7300" 111 | - "9221:9221/udp" 112 | - "9221:9221/tcp" 113 | healthcheck: 114 | test: ["CMD-SHELL", "curl -f http://localhost:8547 || exit 1"] 115 | interval: 30s 116 | timeout: 10s 117 | retries: 5 118 | stop_grace_period: 10m 119 | extra_hosts: 120 | - "host.docker.internal:host-gateway" 121 | restart: unless-stopped 122 | 123 | op-batcher: 124 | build: 125 | context: . 126 | dockerfile: Dockerfile.services 127 | args: 128 | ENTRYPOINT_SCRIPT: op-batcher.sh 129 | volumes: 130 | - ./data/bin:/app/data/bin 131 | depends_on: 132 | op-geth: 133 | condition: service_healthy 134 | op-node: 135 | condition: service_healthy 136 | env_file: 137 | - .env 138 | - paths.env 139 | - opbatcher.env 140 | ports: 141 | - "8548:8548" 142 | - "7301:7301" 143 | stop_grace_period: 1m30s 144 | restart: unless-stopped 145 | extra_hosts: 146 | - "host.docker.internal:host-gateway" 147 | profiles: ["sequencer"] 148 | 149 | op-proposer: 150 | build: 151 | context: . 152 | dockerfile: Dockerfile.services 153 | args: 154 | ENTRYPOINT_SCRIPT: op-proposer.sh 155 | volumes: 156 | - ./data/bin:/app/data/bin 157 | - ./data/deployments:/app/data/deployments 158 | depends_on: 159 | op-geth: 160 | condition: service_healthy 161 | op-node: 162 | condition: service_healthy 163 | env_file: 164 | - .env 165 | - paths.env 166 | - opproposer.env 167 | ports: 168 | - "8560:8560" 169 | - "7302:7302" 170 | stop_grace_period: 1m30s 171 | restart: unless-stopped 172 | extra_hosts: 173 | - "host.docker.internal:host-gateway" 174 | profiles: ["sequencer"] 175 | 176 | grafana: 177 | image: grafana/grafana:11.1.0 178 | restart: unless-stopped 179 | env_file: 180 | - grafana.env 181 | volumes: 182 | - ./monitoring/grafana/provisioning/:/etc/grafana/provisioning/:ro 183 | - ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards 184 | - grafana_data:/var/lib/grafana 185 | ports: 186 | - 3000:3000 187 | 188 | prometheus: 189 | image: prom/prometheus:latest 190 | restart: unless-stopped 191 | env_file: 192 | - .env 193 | volumes: 194 | - ./monitoring/prometheus:/etc/prometheus 195 | - prometheus_data:/prometheus 196 | ports: 197 | - 9090:9090 198 | json-server: 199 | build: 200 | context: ./serve 201 | dockerfile: Dockerfile 202 | volumes: 203 | - ./data/deployments:/app/data/deployments 204 | ports: 205 | - "3001:3001" 206 | restart: unless-stopped 207 | 208 | volumes: 209 | grafana_data: 210 | prometheus_data: 211 | -------------------------------------------------------------------------------- /entrypoints/celestia-da.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if keyring exists and recover key if it doesn't 4 | if [ ! -f "$CELESTIA_KEYRING_PATH" ]; then 5 | echo "Keyring not found or empty. Recovering key..." 6 | 7 | # Check if the mnemonic is provided 8 | if [ -z "$DA_KEYRING_MNEMONIC" ]; then 9 | echo "Error: Mnemonic not provided in DA_KEYRING_MNEMONIC" 10 | exit 1 11 | fi 12 | 13 | # Use the mnemonic to recover the key 14 | echo "$DA_KEYRING_MNEMONIC" | cel-key add "$ACCNAME" --recover --keyring-backend test --node.type light --keyring-dir "$CELESTIA_NODE_STORE"/keys --p2p.network "$DA_P2P_NETWORK" 15 | fi 16 | 17 | # Check if the node store is initialized 18 | if [ ! -f "$CELESTIA_NODE_STORE_CONFIG_PATH" ]; then 19 | echo "Initializing Celestia Node Store as $CELESTIA_NODE_STORE_CONFIG_PATH is missing..." 20 | celestia-da $CELESTIA_NODE_TYPE init --p2p.network="$DA_P2P_NETWORK" --node.store "$CELESTIA_NODE_STORE"/ 21 | fi 22 | 23 | # Start the Celestia node 24 | exec celestia-da $CELESTIA_NODE_TYPE start \ 25 | --da.grpc.namespace="$DA_GRPC_NAMESPACE" \ 26 | --da.grpc.listen=0.0.0.0:26650 \ 27 | --core.ip "$DA_CORE_IP" \ 28 | --core.rpc.port "${DA_CORE_RPC_PORT:-26657}" \ 29 | --core.grpc.port "${DA_CORE_GRPC_PORT:-9090}" \ 30 | --p2p.network="$DA_P2P_NETWORK" \ 31 | --keyring.accname="$ACCNAME" \ 32 | --gateway 33 | -------------------------------------------------------------------------------- /entrypoints/op-batcher.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check if OP_BATCHER_PRIVATE_KEY environment variable is set 4 | if [ -z "$OP_BATCHER_PRIVATE_KEY" ]; then 5 | echo "OP_BATCHER_PRIVATE_KEY are missing, fetching from AWS Secrets Manager..." 6 | secrets=$(aws secretsmanager get-secret-value --secret-id "$AWS_SECRET_ARN" | jq '.SecretString | fromjson') 7 | 8 | OP_BATCHER_PRIVATE_KEY="$(echo "${secrets}" | jq -r '.BATCHER_PRIVATE_KEY')" 9 | 10 | export OP_BATCHER_PRIVATE_KEY 11 | fi 12 | 13 | exec "$BIN_DIR"/op-batcher 14 | -------------------------------------------------------------------------------- /entrypoints/op-geth.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Initialize op-geth if datadir is empty 4 | if [ -d "$DATADIR_DIR" ] && [ -z "$(ls -A "$DATADIR_DIR")" ]; then 5 | echo "Initializing op-geth as $DATADIR_DIR is empty..." 6 | 7 | # Creating password file and block signer key file only if PASSWORD, GETH_PASSWORD is set and SEQUENCER_MODE is true 8 | if [ -n "$PASSWORD" ] && [ -n "$GETH_PASSWORD" ] && [ "$SEQUENCER_MODE" = "true" ]; then 9 | echo "$PASSWORD" > "$DATADIR_DIR/password" 10 | 11 | # Check if SEQUENCER_PRIVATE_KEY environment variable is set 12 | if [ -z "$SEQUENCER_PRIVATE_KEY" ]; then 13 | echo "SEQUENCER_PRIVATE_KEY are missing, fetching from AWS Secrets Manager..." 14 | secrets=$(aws secretsmanager get-secret-value --secret-id "$AWS_SECRET_ARN" | jq '.SecretString | fromjson') 15 | 16 | SEQUENCER_PRIVATE_KEY="$(echo "${secrets}" | jq -r '.SEQUENCER_PRIVATE_KEY')" 17 | 18 | export SEQUENCER_PRIVATE_KEY 19 | fi 20 | 21 | # Creating block signer key file and importing it 22 | echo "$SEQUENCER_PRIVATE_KEY" > "$DATADIR_DIR/block-signer-key" 23 | "$BIN_DIR"/geth account import --datadir="$DATADIR_DIR" --password="$DATADIR_DIR/password" "$DATADIR_DIR/block-signer-key" 24 | fi 25 | 26 | # Initialize with genesis block 27 | "$BIN_DIR"/geth init --datadir="$DATADIR_DIR" "$CONFIG_PATH"/genesis.json 28 | fi 29 | 30 | exec "$BIN_DIR"/geth 31 | -------------------------------------------------------------------------------- /entrypoints/op-node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check if SEQUENCER_MODE environment variable is set to false 4 | if [ "$SEQUENCER_MODE" != "true" ]; then 5 | unset OP_NODE_SEQUENCER_ENABLED 6 | unset OP_NODE_SEQUENCER_L1_CONFS 7 | unset OP_NODE_P2P_SEQUENCER_KEY 8 | fi 9 | 10 | # Check if OP_NODE_P2P_SEQUENCER_KEY environment variable is set 11 | if [ "$OP_NODE_SEQUENCER_ENABLED" = "true" ]; then 12 | if [ -z "$OP_NODE_P2P_SEQUENCER_KEY" ]; then 13 | echo "OP_NODE_P2P_SEQUENCER_KEY is missing, fetching from AWS Secrets Manager..." 14 | secrets=$(aws secretsmanager get-secret-value --secret-id "$AWS_SECRET_ARN" | jq '.SecretString | fromjson') 15 | 16 | OP_NODE_P2P_SEQUENCER_KEY="$(echo "${secrets}" | jq -r '.SEQUENCER_PRIVATE_KEY')" 17 | 18 | export OP_NODE_P2P_SEQUENCER_KEY 19 | fi 20 | else 21 | echo "Sequencer is not enabled. Skipping fetching OP_NODE_P2P_SEQUENCER_KEY." 22 | fi 23 | 24 | exec "$BIN_DIR"/op-node 25 | -------------------------------------------------------------------------------- /entrypoints/op-proposer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check if OP_PROPOSER_PRIVATE_KEY environment variable is set 4 | if [ -z "$OP_PROPOSER_PRIVATE_KEY" ]; then 5 | echo "OP_PROPOSER_PRIVATE_KEY are missing, fetching from AWS Secrets Manager..." 6 | secrets=$(aws secretsmanager get-secret-value --secret-id "$AWS_SECRET_ARN" | jq '.SecretString | fromjson') 7 | 8 | OP_PROPOSER_PRIVATE_KEY="$(echo "${secrets}" | jq -r '.PROPOSER_PRIVATE_KEY')" 9 | 10 | export OP_PROPOSER_PRIVATE_KEY 11 | fi 12 | 13 | # Check if OP_PROPOSER_L2OO_ADDRESS environment variable is set 14 | if [ -z "$OP_PROPOSER_L2OO_ADDRESS" ]; then 15 | # If not set, check if the file exists 16 | if [ ! -f "$DEPLOYMENT_DIR/artifact.json" ]; then 17 | echo "File $DEPLOYMENT_DIR/artifact.json does not exist. Please import data/deployments or set the OP_PROPOSER_L2OO_ADDRESS variable." 18 | exit 1 19 | fi 20 | # Use the address from the $DEPLOYMENT_DIR 21 | OP_PROPOSER_L2OO_ADDRESS=$(jq -r .L2OutputOracleProxy $DEPLOYMENT_DIR/artifact.json) 22 | fi 23 | 24 | exec "$BIN_DIR"/op-proposer 25 | -------------------------------------------------------------------------------- /faucet/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | evm-faucet: 5 | image: upnode/evm-faucet:latest 6 | ports: 7 | - "4244:8080" 8 | env_file: 9 | - .env 10 | restart: unless-stopped 11 | extra_hosts: 12 | - "host.docker.internal:host-gateway" 13 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x81af86360a8e964cc907a5689a62e94231c7e42e05f49c0586716975d72e2e2e" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /grafana.env: -------------------------------------------------------------------------------- 1 | GF_SECURITY_ADMIN_PASSWORD=optimism -------------------------------------------------------------------------------- /monitoring/grafana/dashboards/op_stack_compose_dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "grafana", 8 | "uid": "-- Grafana --" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "type": "dashboard" 15 | } 16 | ] 17 | }, 18 | "editable": true, 19 | "fiscalYearStartMonth": 0, 20 | "graphTooltip": 0, 21 | "id": 1, 22 | "links": [], 23 | "panels": [ 24 | { 25 | "collapsed": true, 26 | "gridPos": { 27 | "h": 1, 28 | "w": 24, 29 | "x": 0, 30 | "y": 0 31 | }, 32 | "id": 6, 33 | "panels": [], 34 | "title": "Sequencer", 35 | "type": "row" 36 | }, 37 | { 38 | "datasource": { 39 | "type": "prometheus", 40 | "uid": "ddshms3dlineoe" 41 | }, 42 | "fieldConfig": { 43 | "defaults": { 44 | "color": { 45 | "mode": "thresholds" 46 | }, 47 | "mappings": [], 48 | "thresholds": { 49 | "mode": "absolute", 50 | "steps": [ 51 | { 52 | "color": "red", 53 | "value": null 54 | }, 55 | { 56 | "color": "green", 57 | "value": 1 58 | } 59 | ] 60 | } 61 | }, 62 | "overrides": [] 63 | }, 64 | "gridPos": { 65 | "h": 4, 66 | "w": 6, 67 | "x": 0, 68 | "y": 1 69 | }, 70 | "id": 7, 71 | "options": { 72 | "colorMode": "value", 73 | "graphMode": "area", 74 | "justifyMode": "auto", 75 | "orientation": "auto", 76 | "percentChangeColorMode": "standard", 77 | "reduceOptions": { 78 | "calcs": [ 79 | "lastNotNull" 80 | ], 81 | "fields": "", 82 | "values": false 83 | }, 84 | "showPercentChange": false, 85 | "text": { 86 | "valueSize": 54 87 | }, 88 | "textMode": "auto", 89 | "wideLayout": true 90 | }, 91 | "pluginVersion": "11.1.0", 92 | "targets": [ 93 | { 94 | "datasource": { 95 | "type": "prometheus", 96 | "uid": "ddshms3dlineoe" 97 | }, 98 | "disableTextWrap": false, 99 | "editorMode": "builder", 100 | "expr": "op_node_default_refs_number{type=\"l2_unsafe\", layer=\"l2\"}", 101 | "fullMetaSearch": false, 102 | "includeNullMetadata": true, 103 | "instant": false, 104 | "legendFormat": "__auto", 105 | "range": true, 106 | "refId": "A", 107 | "useBackend": false 108 | } 109 | ], 110 | "title": "L2 Unsafe Block", 111 | "type": "stat" 112 | }, 113 | { 114 | "datasource": { 115 | "type": "prometheus", 116 | "uid": "ddshms3dlineoe" 117 | }, 118 | "fieldConfig": { 119 | "defaults": { 120 | "color": { 121 | "mode": "thresholds" 122 | }, 123 | "mappings": [], 124 | "thresholds": { 125 | "mode": "absolute", 126 | "steps": [ 127 | { 128 | "color": "red", 129 | "value": null 130 | }, 131 | { 132 | "color": "green", 133 | "value": 1 134 | } 135 | ] 136 | } 137 | }, 138 | "overrides": [] 139 | }, 140 | "gridPos": { 141 | "h": 4, 142 | "w": 6, 143 | "x": 6, 144 | "y": 1 145 | }, 146 | "id": 10, 147 | "options": { 148 | "colorMode": "value", 149 | "graphMode": "area", 150 | "justifyMode": "auto", 151 | "orientation": "auto", 152 | "percentChangeColorMode": "standard", 153 | "reduceOptions": { 154 | "calcs": [ 155 | "lastNotNull" 156 | ], 157 | "fields": "", 158 | "values": false 159 | }, 160 | "showPercentChange": false, 161 | "text": { 162 | "valueSize": 54 163 | }, 164 | "textMode": "auto", 165 | "wideLayout": true 166 | }, 167 | "pluginVersion": "11.1.0", 168 | "targets": [ 169 | { 170 | "datasource": { 171 | "type": "prometheus", 172 | "uid": "ddshms3dlineoe" 173 | }, 174 | "disableTextWrap": false, 175 | "editorMode": "builder", 176 | "expr": "op_node_default_refs_number{type=\"l2_safe\", layer=\"l2\"}", 177 | "fullMetaSearch": false, 178 | "includeNullMetadata": true, 179 | "instant": false, 180 | "legendFormat": "__auto", 181 | "range": true, 182 | "refId": "A", 183 | "useBackend": false 184 | } 185 | ], 186 | "title": "L2 Safe Block", 187 | "type": "stat" 188 | }, 189 | { 190 | "datasource": { 191 | "type": "prometheus", 192 | "uid": "ddshms3dlineoe" 193 | }, 194 | "fieldConfig": { 195 | "defaults": { 196 | "color": { 197 | "mode": "thresholds" 198 | }, 199 | "mappings": [], 200 | "thresholds": { 201 | "mode": "absolute", 202 | "steps": [ 203 | { 204 | "color": "red", 205 | "value": null 206 | }, 207 | { 208 | "color": "green", 209 | "value": 1 210 | } 211 | ] 212 | } 213 | }, 214 | "overrides": [] 215 | }, 216 | "gridPos": { 217 | "h": 4, 218 | "w": 6, 219 | "x": 12, 220 | "y": 1 221 | }, 222 | "id": 9, 223 | "options": { 224 | "colorMode": "value", 225 | "graphMode": "area", 226 | "justifyMode": "auto", 227 | "orientation": "auto", 228 | "percentChangeColorMode": "standard", 229 | "reduceOptions": { 230 | "calcs": [ 231 | "lastNotNull" 232 | ], 233 | "fields": "", 234 | "values": false 235 | }, 236 | "showPercentChange": false, 237 | "text": { 238 | "valueSize": 54 239 | }, 240 | "textMode": "auto", 241 | "wideLayout": true 242 | }, 243 | "pluginVersion": "11.1.0", 244 | "targets": [ 245 | { 246 | "datasource": { 247 | "type": "prometheus", 248 | "uid": "ddshms3dlineoe" 249 | }, 250 | "disableTextWrap": false, 251 | "editorMode": "builder", 252 | "expr": "op_node_default_refs_number{type=\"l2_finalized\", layer=\"l2\"}", 253 | "fullMetaSearch": false, 254 | "includeNullMetadata": true, 255 | "instant": false, 256 | "legendFormat": "__auto", 257 | "range": true, 258 | "refId": "A", 259 | "useBackend": false 260 | } 261 | ], 262 | "title": "L2 Finalized Block", 263 | "type": "stat" 264 | }, 265 | { 266 | "datasource": { 267 | "type": "prometheus", 268 | "uid": "ddshms3dlineoe" 269 | }, 270 | "fieldConfig": { 271 | "defaults": { 272 | "color": { 273 | "mode": "thresholds" 274 | }, 275 | "mappings": [], 276 | "thresholds": { 277 | "mode": "absolute", 278 | "steps": [ 279 | { 280 | "color": "red", 281 | "value": null 282 | }, 283 | { 284 | "color": "green", 285 | "value": 1 286 | } 287 | ] 288 | } 289 | }, 290 | "overrides": [] 291 | }, 292 | "gridPos": { 293 | "h": 4, 294 | "w": 6, 295 | "x": 0, 296 | "y": 5 297 | }, 298 | "id": 8, 299 | "options": { 300 | "colorMode": "value", 301 | "graphMode": "area", 302 | "justifyMode": "auto", 303 | "orientation": "auto", 304 | "percentChangeColorMode": "standard", 305 | "reduceOptions": { 306 | "calcs": [ 307 | "lastNotNull" 308 | ], 309 | "fields": "", 310 | "values": false 311 | }, 312 | "showPercentChange": false, 313 | "text": { 314 | "valueSize": 54 315 | }, 316 | "textMode": "auto", 317 | "wideLayout": true 318 | }, 319 | "pluginVersion": "11.1.0", 320 | "targets": [ 321 | { 322 | "datasource": { 323 | "type": "prometheus", 324 | "uid": "ddshms3dlineoe" 325 | }, 326 | "disableTextWrap": false, 327 | "editorMode": "builder", 328 | "expr": "op_node_default_refs_number{type=\"l1_head\"}", 329 | "fullMetaSearch": false, 330 | "includeNullMetadata": true, 331 | "instant": false, 332 | "legendFormat": "__auto", 333 | "range": true, 334 | "refId": "A", 335 | "useBackend": false 336 | } 337 | ], 338 | "title": "L1 Head", 339 | "type": "stat" 340 | }, 341 | { 342 | "datasource": { 343 | "type": "prometheus", 344 | "uid": "ddshms3dlineoe" 345 | }, 346 | "fieldConfig": { 347 | "defaults": { 348 | "color": { 349 | "mode": "thresholds" 350 | }, 351 | "mappings": [], 352 | "thresholds": { 353 | "mode": "absolute", 354 | "steps": [ 355 | { 356 | "color": "red", 357 | "value": null 358 | }, 359 | { 360 | "color": "green", 361 | "value": 1 362 | } 363 | ] 364 | } 365 | }, 366 | "overrides": [] 367 | }, 368 | "gridPos": { 369 | "h": 4, 370 | "w": 6, 371 | "x": 6, 372 | "y": 5 373 | }, 374 | "id": 11, 375 | "options": { 376 | "colorMode": "value", 377 | "graphMode": "area", 378 | "justifyMode": "auto", 379 | "orientation": "auto", 380 | "percentChangeColorMode": "standard", 381 | "reduceOptions": { 382 | "calcs": [ 383 | "lastNotNull" 384 | ], 385 | "fields": "", 386 | "values": false 387 | }, 388 | "showPercentChange": false, 389 | "text": { 390 | "valueSize": 54 391 | }, 392 | "textMode": "auto", 393 | "wideLayout": true 394 | }, 395 | "pluginVersion": "11.1.0", 396 | "targets": [ 397 | { 398 | "datasource": { 399 | "type": "prometheus", 400 | "uid": "ddshms3dlineoe" 401 | }, 402 | "disableTextWrap": false, 403 | "editorMode": "builder", 404 | "expr": "op_node_default_refs_number{type=\"l1_safe\"}", 405 | "fullMetaSearch": false, 406 | "includeNullMetadata": true, 407 | "instant": false, 408 | "legendFormat": "__auto", 409 | "range": true, 410 | "refId": "A", 411 | "useBackend": false 412 | } 413 | ], 414 | "title": "L1 Safe Block", 415 | "type": "stat" 416 | }, 417 | { 418 | "datasource": { 419 | "type": "prometheus", 420 | "uid": "ddshms3dlineoe" 421 | }, 422 | "fieldConfig": { 423 | "defaults": { 424 | "color": { 425 | "mode": "thresholds" 426 | }, 427 | "mappings": [], 428 | "thresholds": { 429 | "mode": "absolute", 430 | "steps": [ 431 | { 432 | "color": "red", 433 | "value": null 434 | }, 435 | { 436 | "color": "green", 437 | "value": 1 438 | } 439 | ] 440 | } 441 | }, 442 | "overrides": [] 443 | }, 444 | "gridPos": { 445 | "h": 4, 446 | "w": 6, 447 | "x": 12, 448 | "y": 5 449 | }, 450 | "id": 12, 451 | "options": { 452 | "colorMode": "value", 453 | "graphMode": "area", 454 | "justifyMode": "auto", 455 | "orientation": "auto", 456 | "percentChangeColorMode": "standard", 457 | "reduceOptions": { 458 | "calcs": [ 459 | "lastNotNull" 460 | ], 461 | "fields": "", 462 | "values": false 463 | }, 464 | "showPercentChange": false, 465 | "text": { 466 | "valueSize": 54 467 | }, 468 | "textMode": "auto", 469 | "wideLayout": true 470 | }, 471 | "pluginVersion": "11.1.0", 472 | "targets": [ 473 | { 474 | "datasource": { 475 | "type": "prometheus", 476 | "uid": "ddshms3dlineoe" 477 | }, 478 | "disableTextWrap": false, 479 | "editorMode": "builder", 480 | "expr": "op_node_default_refs_number{type=\"l1_finalized\"}", 481 | "fullMetaSearch": false, 482 | "includeNullMetadata": true, 483 | "instant": false, 484 | "legendFormat": "__auto", 485 | "range": true, 486 | "refId": "A", 487 | "useBackend": false 488 | } 489 | ], 490 | "title": "L1 Finalized Block", 491 | "type": "stat" 492 | }, 493 | { 494 | "collapsed": false, 495 | "gridPos": { 496 | "h": 1, 497 | "w": 24, 498 | "x": 0, 499 | "y": 9 500 | }, 501 | "id": 5, 502 | "panels": [], 503 | "title": "Balances", 504 | "type": "row" 505 | }, 506 | { 507 | "datasource": { 508 | "type": "prometheus", 509 | "uid": "ddshms3dlineoe" 510 | }, 511 | "fieldConfig": { 512 | "defaults": { 513 | "color": { 514 | "mode": "thresholds" 515 | }, 516 | "decimals": 4, 517 | "mappings": [], 518 | "thresholds": { 519 | "mode": "absolute", 520 | "steps": [ 521 | { 522 | "color": "red", 523 | "value": null 524 | }, 525 | { 526 | "color": "yellow", 527 | "value": 0.5 528 | }, 529 | { 530 | "color": "green", 531 | "value": 1 532 | } 533 | ] 534 | } 535 | }, 536 | "overrides": [] 537 | }, 538 | "gridPos": { 539 | "h": 4, 540 | "w": 6, 541 | "x": 0, 542 | "y": 10 543 | }, 544 | "id": 3, 545 | "options": { 546 | "colorMode": "value", 547 | "graphMode": "area", 548 | "justifyMode": "auto", 549 | "orientation": "auto", 550 | "percentChangeColorMode": "standard", 551 | "reduceOptions": { 552 | "calcs": [ 553 | "lastNotNull" 554 | ], 555 | "fields": "", 556 | "values": false 557 | }, 558 | "showPercentChange": false, 559 | "text": { 560 | "valueSize": 54 561 | }, 562 | "textMode": "auto", 563 | "wideLayout": true 564 | }, 565 | "pluginVersion": "11.1.0", 566 | "targets": [ 567 | { 568 | "datasource": { 569 | "type": "prometheus", 570 | "uid": "ddshms3dlineoe" 571 | }, 572 | "disableTextWrap": false, 573 | "editorMode": "builder", 574 | "expr": "op_batcher_default_balance", 575 | "fullMetaSearch": false, 576 | "includeNullMetadata": true, 577 | "instant": false, 578 | "legendFormat": "__auto", 579 | "range": true, 580 | "refId": "A", 581 | "useBackend": false 582 | } 583 | ], 584 | "title": "Batcher Balance", 585 | "type": "stat" 586 | }, 587 | { 588 | "datasource": { 589 | "type": "prometheus", 590 | "uid": "ddshms3dlineoe" 591 | }, 592 | "fieldConfig": { 593 | "defaults": { 594 | "color": { 595 | "mode": "palette-classic" 596 | }, 597 | "custom": { 598 | "axisBorderShow": false, 599 | "axisCenteredZero": false, 600 | "axisColorMode": "text", 601 | "axisLabel": "", 602 | "axisPlacement": "auto", 603 | "barAlignment": 0, 604 | "drawStyle": "line", 605 | "fillOpacity": 0, 606 | "gradientMode": "none", 607 | "hideFrom": { 608 | "legend": false, 609 | "tooltip": false, 610 | "viz": false 611 | }, 612 | "insertNulls": false, 613 | "lineInterpolation": "linear", 614 | "lineWidth": 1, 615 | "pointSize": 5, 616 | "scaleDistribution": { 617 | "type": "linear" 618 | }, 619 | "showPoints": "auto", 620 | "spanNulls": false, 621 | "stacking": { 622 | "group": "A", 623 | "mode": "none" 624 | }, 625 | "thresholdsStyle": { 626 | "mode": "off" 627 | } 628 | }, 629 | "mappings": [], 630 | "thresholds": { 631 | "mode": "absolute", 632 | "steps": [ 633 | { 634 | "color": "green", 635 | "value": null 636 | }, 637 | { 638 | "color": "red", 639 | "value": 80 640 | } 641 | ] 642 | } 643 | }, 644 | "overrides": [ 645 | { 646 | "matcher": { 647 | "id": "byFrameRefID", 648 | "options": "A" 649 | }, 650 | "properties": [ 651 | { 652 | "id": "displayName", 653 | "value": "Balance" 654 | } 655 | ] 656 | } 657 | ] 658 | }, 659 | "gridPos": { 660 | "h": 8, 661 | "w": 9, 662 | "x": 6, 663 | "y": 10 664 | }, 665 | "id": 1, 666 | "options": { 667 | "legend": { 668 | "calcs": [], 669 | "displayMode": "list", 670 | "placement": "bottom", 671 | "showLegend": true 672 | }, 673 | "tooltip": { 674 | "hoverProximity": -46, 675 | "mode": "single", 676 | "sort": "none" 677 | } 678 | }, 679 | "targets": [ 680 | { 681 | "datasource": { 682 | "type": "prometheus", 683 | "uid": "ddshms3dlineoe" 684 | }, 685 | "disableTextWrap": false, 686 | "editorMode": "builder", 687 | "expr": "op_batcher_default_balance", 688 | "fullMetaSearch": false, 689 | "includeNullMetadata": true, 690 | "instant": false, 691 | "legendFormat": "__auto", 692 | "range": true, 693 | "refId": "A", 694 | "useBackend": false 695 | } 696 | ], 697 | "title": "Batcher Balance", 698 | "type": "timeseries" 699 | }, 700 | { 701 | "datasource": { 702 | "type": "prometheus", 703 | "uid": "ddshms3dlineoe" 704 | }, 705 | "description": "", 706 | "fieldConfig": { 707 | "defaults": { 708 | "color": { 709 | "mode": "palette-classic" 710 | }, 711 | "custom": { 712 | "axisBorderShow": false, 713 | "axisCenteredZero": false, 714 | "axisColorMode": "text", 715 | "axisLabel": "", 716 | "axisPlacement": "auto", 717 | "barAlignment": 0, 718 | "drawStyle": "line", 719 | "fillOpacity": 0, 720 | "gradientMode": "none", 721 | "hideFrom": { 722 | "legend": false, 723 | "tooltip": false, 724 | "viz": false 725 | }, 726 | "insertNulls": false, 727 | "lineInterpolation": "linear", 728 | "lineWidth": 1, 729 | "pointSize": 5, 730 | "scaleDistribution": { 731 | "type": "linear" 732 | }, 733 | "showPoints": "auto", 734 | "spanNulls": false, 735 | "stacking": { 736 | "group": "A", 737 | "mode": "none" 738 | }, 739 | "thresholdsStyle": { 740 | "mode": "off" 741 | } 742 | }, 743 | "mappings": [], 744 | "thresholds": { 745 | "mode": "absolute", 746 | "steps": [ 747 | { 748 | "color": "green", 749 | "value": null 750 | }, 751 | { 752 | "color": "red", 753 | "value": 80 754 | } 755 | ] 756 | } 757 | }, 758 | "overrides": [ 759 | { 760 | "matcher": { 761 | "id": "byFrameRefID", 762 | "options": "A" 763 | }, 764 | "properties": [ 765 | { 766 | "id": "displayName", 767 | "value": "Balance" 768 | } 769 | ] 770 | } 771 | ] 772 | }, 773 | "gridPos": { 774 | "h": 8, 775 | "w": 9, 776 | "x": 15, 777 | "y": 10 778 | }, 779 | "id": 2, 780 | "options": { 781 | "legend": { 782 | "calcs": [], 783 | "displayMode": "list", 784 | "placement": "bottom", 785 | "showLegend": true 786 | }, 787 | "tooltip": { 788 | "mode": "single", 789 | "sort": "none" 790 | } 791 | }, 792 | "targets": [ 793 | { 794 | "datasource": { 795 | "type": "prometheus", 796 | "uid": "ddshms3dlineoe" 797 | }, 798 | "disableTextWrap": false, 799 | "editorMode": "builder", 800 | "expr": "op_proposer_default_balance", 801 | "fullMetaSearch": false, 802 | "includeNullMetadata": true, 803 | "instant": false, 804 | "legendFormat": "__auto", 805 | "range": true, 806 | "refId": "A", 807 | "useBackend": false 808 | } 809 | ], 810 | "title": "Proposer Balance", 811 | "type": "timeseries" 812 | }, 813 | { 814 | "datasource": { 815 | "type": "prometheus", 816 | "uid": "ddshms3dlineoe" 817 | }, 818 | "fieldConfig": { 819 | "defaults": { 820 | "color": { 821 | "mode": "thresholds" 822 | }, 823 | "decimals": 4, 824 | "mappings": [], 825 | "thresholds": { 826 | "mode": "absolute", 827 | "steps": [ 828 | { 829 | "color": "red", 830 | "value": null 831 | }, 832 | { 833 | "color": "yellow", 834 | "value": 1 835 | }, 836 | { 837 | "color": "green", 838 | "value": 1 839 | } 840 | ] 841 | } 842 | }, 843 | "overrides": [] 844 | }, 845 | "gridPos": { 846 | "h": 4, 847 | "w": 6, 848 | "x": 0, 849 | "y": 14 850 | }, 851 | "id": 4, 852 | "options": { 853 | "colorMode": "value", 854 | "graphMode": "area", 855 | "justifyMode": "auto", 856 | "orientation": "auto", 857 | "percentChangeColorMode": "standard", 858 | "reduceOptions": { 859 | "calcs": [ 860 | "lastNotNull" 861 | ], 862 | "fields": "", 863 | "values": false 864 | }, 865 | "showPercentChange": false, 866 | "text": { 867 | "valueSize": 54 868 | }, 869 | "textMode": "auto", 870 | "wideLayout": true 871 | }, 872 | "pluginVersion": "11.1.0", 873 | "targets": [ 874 | { 875 | "datasource": { 876 | "type": "prometheus", 877 | "uid": "ddshms3dlineoe" 878 | }, 879 | "disableTextWrap": false, 880 | "editorMode": "builder", 881 | "expr": "op_proposer_default_balance", 882 | "fullMetaSearch": false, 883 | "includeNullMetadata": true, 884 | "instant": false, 885 | "legendFormat": "__auto", 886 | "range": true, 887 | "refId": "A", 888 | "useBackend": false 889 | } 890 | ], 891 | "title": "Proposer Balance", 892 | "type": "stat" 893 | } 894 | ], 895 | "refresh": "", 896 | "schemaVersion": 39, 897 | "tags": [], 898 | "templating": { 899 | "list": [] 900 | }, 901 | "time": { 902 | "from": "now-15m", 903 | "to": "now" 904 | }, 905 | "timepicker": {}, 906 | "timezone": "browser", 907 | "title": "OP Stack Compose", 908 | "uid": "ddshn0bgt86ioc", 909 | "version": 23, 910 | "weekStart": "" 911 | } -------------------------------------------------------------------------------- /monitoring/grafana/provisioning/dashboards/all.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: 'default' 5 | orgId: 1 6 | folder: '' 7 | type: file 8 | disableDeletion: true 9 | editable: true 10 | options: 11 | path: /var/lib/grafana/dashboards 12 | -------------------------------------------------------------------------------- /monitoring/grafana/provisioning/datasources/all.yml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | deleteDatasources: 4 | - name: 'Prometheus' 5 | 6 | datasources: 7 | - access: 'proxy' 8 | editable: true 9 | is_default: true 10 | name: 'Prometheus' 11 | uid: 'ddshms3dlineoe' 12 | org_id: 1 13 | type: 'prometheus' 14 | url: 'http://prometheus:9090' 15 | version: 1 -------------------------------------------------------------------------------- /monitoring/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | scrape_configs: 6 | - job_name: 'op-node' 7 | static_configs: 8 | - targets: ['op-node:7300'] 9 | 10 | - job_name: 'op-batcher' 11 | static_configs: 12 | - targets: ['op-batcher:7301'] 13 | 14 | - job_name: 'op-proposer' 15 | static_configs: 16 | - targets: ['op-proposer:7302'] 17 | 18 | - job_name: 'op-geth' 19 | static_configs: 20 | - targets: ['op-geth:7303'] 21 | -------------------------------------------------------------------------------- /opbatcher.env: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # op-batcher Flags # 3 | ################################################## 4 | 5 | OP_BATCHER_L2_ETH_RPC=http://op-geth:8545 6 | OP_BATCHER_ROLLUP_RPC=http://op-node:8547 7 | OP_BATCHER_POLL_INTERVAL=0.5s 8 | OP_BATCHER_SUB_SAFETY_MARGIN=6 9 | OP_BATCHER_NUM_CONFIRMATIONS=1 10 | OP_BATCHER_SAFE_ABORT_NONCE_TOO_LOW_COUNT=3 11 | OP_BATCHER_RESUBMISSION_TIMEOUT=30s 12 | OP_BATCHER_RPC_ADDR=0.0.0.0 13 | OP_BATCHER_RPC_PORT=8548 14 | OP_BATCHER_MAX_CHANNEL_DURATION=300 15 | OP_BATCHER_L1_ETH_RPC=$L1_RPC_URL 16 | OP_BATCHER_PRIVATE_KEY=$BATCHER_PRIVATE_KEY 17 | OP_BATCHER_DA_RPC=celestia-da:26650 18 | OP_BATCHER_BATCH_TYPE=${OP_BATCHER_BATCH_TYPE:-1} 19 | OP_BATCHER_DATA_AVAILABILITY_TYPE=calldata 20 | 21 | OP_BATCHER_METRICS_ENABLED=true 22 | OP_BATCHER_METRICS_ADDR=0.0.0.0 23 | OP_BATCHER_METRICS_PORT=7301 24 | -------------------------------------------------------------------------------- /opgeth.env: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # op-geth Flags # 3 | ################################################## 4 | 5 | GETH_DATADIR=$DATADIR_DIR 6 | GETH_HTTP=true 7 | GETH_HTTP_CORSDOMAIN="*" 8 | GETH_HTTP_VHOSTS="*" 9 | GETH_HTTP_ADDR=0.0.0.0 10 | GETH_HTTP_API=web3,debug,eth,txpool,net,engine 11 | GETH_WS=true 12 | GETH_WS_ADDR=0.0.0.0 13 | GETH_WS_PORT=8545 14 | GETH_WS_ORIGINS="*" 15 | GETH_WS_API=debug,eth,txpool,net,engine 16 | GETH_PORT=30333 17 | GETH_DISCOVERY_PORT=30333 18 | GETH_SYNCMODE=full 19 | GETH_GCMODE=archive 20 | GETH_NODISCOVER=false 21 | GETH_MAXPEERS=200 22 | GETH_NETWORKID=$L2_CHAIN_ID 23 | GETH_AUTHRPC_VHOSTS="*" 24 | GETH_AUTHRPC_ADDR=0.0.0.0 25 | GETH_AUTHRPC_PORT=8551 26 | GETH_AUTHRPC_JWTSECRET=$CONFIG_PATH/jwt.txt 27 | GETH_ROLLUP_DISABLETXPOOLGOSSIP=true 28 | GETH_RPC_ALLOW_UNPROTECTED_TXS=true 29 | GETH_PASSWORD=$DATADIR_DIR/password 30 | 31 | GETH_METRICS=true 32 | GETH_METRICS_ADDR=0.0.0.0 33 | GETH_METRICS_PORT=7303 34 | 35 | # For the second node 36 | # GETH_WS=true 37 | # GETH_WS_PORT=8546 38 | # GETH_WS_ADDR=0.0.0.0 39 | # GETH_WS_ORIGINS="*" 40 | # GETH_WS_API=debug,eth,txpool,net,engine 41 | # GETH_HTTP=true 42 | # GETH_HTTP_PORT=8545 43 | # GETH_HTTP_ADDR=0.0.0.0 44 | # GETH_HTTP_VHOSTS="*" 45 | # GETH_HTTP_CORSDOMAIN="*" 46 | # GETH_AUTHRPC_ADDR=0.0.0.0 47 | # GETH_AUTHRPC_JWTSECRET=$CONFIG_PATH/jwt.txt 48 | # GETH_AUTHRPC_PORT=8551 49 | # GETH_AUTHRPC_VHOSTS="*" 50 | # GETH_DATADIR=$DATADIR_DIR 51 | # GETH_ROLLUP_DISABLETXPOOLGOSSIP=true 52 | # GETH_ROLLUP_SEQUENCERHTTP=https://testnet.hokum.gg/ 53 | # GETH_HTTP_API=web3,debug,eth,txpool,net,engine 54 | # GETH_NODISCOVER=true 55 | # GETH_SYNCMODE=full 56 | # GETH_MAXPEERS=0 57 | # GETH_NETWORKID=$L2_CHAIN_ID 58 | # GETH_RPC_ALLOW_UNPROTECTED_TXS=true 59 | -------------------------------------------------------------------------------- /opnode.env: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # op-node Flags # 3 | ################################################## 4 | 5 | #OP_NODE_SYNCMODE=execution-layer 6 | OP_NODE_L2_ENGINE_RPC=ws://op-geth:8551 7 | OP_NODE_L2_ENGINE_AUTH=$CONFIG_PATH/jwt.txt 8 | OP_NODE_L1_EPOCH_POLL_INTERVAL=2s 9 | OP_NODE_L1_HTTP_POLL_INTERVAL=2s 10 | OP_NODE_SEQUENCER_ENABLED=$SEQUENCER_MODE 11 | OP_NODE_SEQUENCER_L1_CONFS=3 12 | OP_NODE_VERIFIER_L1_CONFS=3 13 | OP_NODE_ROLLUP_CONFIG=$CONFIG_PATH/rollup.json 14 | OP_NODE_RPC_ADDR=0.0.0.0 15 | OP_NODE_RPC_PORT=8547 16 | OP_NODE_RPC_ENABLE_ADMIN=false 17 | OP_NODE_P2P_SEQUENCER_KEY=$SEQUENCER_PRIVATE_KEY 18 | OP_NODE_L1_ETH_RPC=$L1_RPC_URL 19 | OP_NODE_L1_RPC_KIND=$L1_RPC_KIND 20 | OP_NODE_L1_TRUST_RPC=true 21 | OP_NODE_L1_BEACON_IGNORE=true 22 | OP_NODE_P2P_AGENT=$P2P_AGENT 23 | OP_NODE_P2P_LISTEN_IP=0.0.0.0 24 | OP_NODE_P2P_LISTEN_TCP_PORT=9221 25 | OP_NODE_P2P_LISTEN_UDP_PORT=9221 26 | OP_NODE_P2P_ADVERTISE_IP=$P2P_ADVERTISE_IP 27 | OP_NODE_DA_RPC=celestia-da:26650 28 | 29 | OP_NODE_METRICS_ENABLED=true 30 | OP_NODE_METRICS_ADDR=0.0.0.0 31 | OP_NODE_METRICS_PORT=7300 32 | 33 | # Uncomment this only in case sequencer is stuck 34 | #OP_NODE_L2_SKIP_SYNC_START_CHECK=true 35 | 36 | # For the second node 37 | # OP_NODE_L1_ETH_RPC=$L1_RPC_URL 38 | # OP_NODE_L1_RPC_KIND=$L1_RPC_KIND 39 | # OP_NODE_L1_EPOCH_POLL_INTERVAL=2s 40 | # OP_NODE_L1_HTTP_POLL_INTERVAL=2s 41 | # OP_NODE_L1_TRUST_RPC=true 42 | # OP_NODE_L2_ENGINE_RPC=ws://op-geth:8551 43 | # OP_NODE_L2_ENGINE_AUTH=$CONFIG_PATH/jwt.txt 44 | # OP_NODE_RPC_ENABLE_ADMIN=true 45 | # OP_NODE_ROLLUP_CONFIG=$CONFIG_PATH/rollup.json 46 | # OP_NODE_RPC_ADDR=0.0.0.0 47 | # OP_NODE_RPC_PORT=8547 48 | # OP_NODE_DA_RPC=celestia-da:26650 49 | 50 | # OP_NODE_P2P_LISTEN_IP=0.0.0.0 51 | # OP_NODE_P2P_LISTEN_TCP_PORT=9221 52 | # OP_NODE_P2P_LISTEN_UDP_PORT=9221 53 | # OP_NODE_P2P_ADVERTISE_IP=$P2P_ADVERTISE_IP 54 | 55 | # OP_NODE_VERIFIER_L1_CONFS=3 56 | -------------------------------------------------------------------------------- /opproposer.env: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # op-proposer Flags # 3 | ################################################## 4 | 5 | OP_PROPOSER_ALLOW_NON_FINALIZED=true 6 | OP_PROPOSER_POLL_INTERVAL=12s 7 | OP_PROPOSER_RPC_PORT=8560 8 | OP_PROPOSER_ROLLUP_RPC=http://op-node:8547 9 | OP_PROPOSER_L2OO_ADDRESS=$L2OO_ADDRESS 10 | OP_PROPOSER_PRIVATE_KEY=$PROPOSER_PRIVATE_KEY 11 | OP_PROPOSER_L1_ETH_RPC=$L1_RPC_URL 12 | 13 | OP_PROPOSER_METRICS_ENABLED=true 14 | OP_PROPOSER_METRICS_ADDR=0.0.0.0 15 | OP_PROPOSER_METRICS_PORT=7302 16 | -------------------------------------------------------------------------------- /paths.env: -------------------------------------------------------------------------------- 1 | ################################################## 2 | # Path Variables # 3 | ################################################## 4 | 5 | CONFIG_PATH=/app/data/configurations 6 | DATADIR_DIR=/app/data/datadir 7 | DEPLOYMENT_DIR=/app/data/deployments 8 | OPTIMISM_DIR=/app/data/optimism 9 | OP_GETH_DIR=/app/data/op-geth 10 | BIN_DIR=/app/data/bin 11 | CELESTIA_KEYRING_PATH=/home/celestia/$TARGET_FOLDER_NAME/keys/keyring-test/$CELESTIA_ACCNAME.info 12 | CELESTIA_NODE_STORE=/home/celestia/$TARGET_FOLDER_NAME 13 | CELESTIA_NODE_STORE_CONFIG_PATH=$CELESTIA_NODE_STORE/config.toml 14 | -------------------------------------------------------------------------------- /restore: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if argument is provided 4 | if [ $# -ne 1 ]; then 5 | echo "Usage: ./restore .tar.gz" 6 | exit 1 7 | fi 8 | 9 | # Check if file exists 10 | if [ ! -f "$1" ]; then 11 | echo "Backup file $1 not found." 12 | exit 1 13 | fi 14 | 15 | # Create the data directory if it doesn't exist 16 | if [ ! -d "./data" ]; then 17 | echo "Data directory not found. Creating it..." 18 | mkdir -p ./data 19 | fi 20 | 21 | # Restore data 22 | echo "Restoring data from $1..." 23 | tar -xzvf "$1" -C ./data 24 | echo "Restore complete." 25 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Define colors 4 | ORANGE='\e[0;33m' 5 | BLUE='\e[0;34m' 6 | RED='\e[0;31m' 7 | GREEN='\e[0;32m' 8 | NC='\e[0m' 9 | 10 | # Check if .env file exists 11 | if [ ! -f .env ]; then 12 | if [ -f .env.example ]; then 13 | echo -e "${RED}Error${NC}: .env file not found." 14 | echo -ne "${ORANGE}Do you want to use .env.example and rename it to .env? (yes/no): ${NC}" 15 | read -r rename_confirm 16 | if [[ "$rename_confirm" =~ ^(yes|y)$ ]]; then 17 | mv .env.example .env 18 | echo -e "${GREEN}.env.example has been renamed to .env.${NC}" 19 | else 20 | echo "Exiting." 21 | exit 1 22 | fi 23 | else 24 | echo -e "${RED}Error${NC}: .env and .env.example files not found. Exiting." 25 | exit 1 26 | fi 27 | fi 28 | 29 | # Load environment variables from .env file 30 | # shellcheck disable=SC1091 31 | source .env 32 | 33 | # Initialize the command 34 | command="docker compose" 35 | 36 | # Add profiles based on SEQUENCER_MODE and Celestia support 37 | [ "$SEQUENCER_MODE" = "true" ] && command+=" --profile sequencer" 38 | [ "$CELESTIA_MODE" = "true" ] && command+=" --profile celestia" 39 | 40 | if [ "$SKIP_DEPLOYMENT_CHECK" = "true" ]; then 41 | echo -e "${ORANGE}NOTE${NC}: Only genesis.json and rollup.json will be checked (SKIP_DEPLOYMENT_CHECK=$SKIP_DEPLOYMENT_CHECK)." 42 | fi 43 | 44 | if [ "$SKIP_HEALTHCHECK" = "true" ]; then 45 | echo -e "${ORANGE}WARNING${NC}: Celestia da light node sync check will be skipped (SKIP_HEALTHCHECK=$SKIP_HEALTHCHECK)." 46 | fi 47 | 48 | # Add the rest of the command 49 | command+=" up --build -d" 50 | 51 | # Confirm before running the command 52 | echo -ne "About to run: ${BLUE}$command${NC} (SEQUENCER_MODE: $SEQUENCER_MODE, CELESTIA_MODE: $CELESTIA_MODE). Do you want to continue? (yes/no): " 53 | read -r confirm 54 | if [[ "$confirm" =~ ^(yes|y)$ ]]; then 55 | eval "$command" 56 | else 57 | echo "Command execution cancelled." 58 | fi 59 | -------------------------------------------------------------------------------- /scripts/clone-repos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to clear and clone a repository 4 | clone_repo() { 5 | local repo_url=$1 6 | local branch_or_commit=$2 7 | local dest_dir=$3 8 | 9 | cd "$dest_dir" || exit 1 10 | 11 | # Check if the repository is on the correct version 12 | if [ -d ".git" ]; then 13 | echo "Checking repository version in $dest_dir" 14 | git fetch --all -q 15 | 16 | local remote_commit 17 | if git ls-remote --heads origin | grep -qE "refs/heads/$branch_or_commit$"; then 18 | # branch_or_commit is a branch 19 | remote_commit=$(git rev-parse origin/"$branch_or_commit") 20 | elif git ls-remote --tags origin | grep -qE "refs/tags/$branch_or_commit$"; then 21 | # branch_or_commit is a tag 22 | remote_commit=$(git rev-parse "refs/tags/$branch_or_commit^{commit}") 23 | else 24 | # Verify if branch_or_commit is a valid commit hash 25 | if ! git cat-file -e "$branch_or_commit^{commit}" 2> /dev/null; then 26 | echo "Error: '$branch_or_commit' is not a valid branch, tag, or commit hash." 27 | cd - > /dev/null || exit 28 | return 1 29 | fi 30 | # branch_or_commit is a commit hash 31 | remote_commit=$(git rev-parse "$branch_or_commit") 32 | fi 33 | 34 | local current_commit 35 | current_commit=$(git rev-parse HEAD) 36 | 37 | if [ "$current_commit" != "$remote_commit" ]; then 38 | echo "Version mismatch. Clearing binaries and existing repository..." 39 | # Remove binaries 40 | rm -f "$BIN_DIR"/op-node "$BIN_DIR"/op-batcher "$BIN_DIR"/op-proposer "$BIN_DIR"/geth 41 | 42 | # Remove all contents including hidden files and directories 43 | rm -rf ./{,.[!.],..?}* 44 | else 45 | if [ ! -f "$BIN_DIR/op-node" ] || [ ! -f "$BIN_DIR/op-batcher" ] || [ ! -f "$BIN_DIR/op-proposer" ] || [ ! -f "$BIN_DIR/geth" ]; then 46 | echo "Some binary is missing. Force clearing repository..." 47 | rm -rf ./{,.[!.],..?}* 48 | else 49 | echo "Repository in $dest_dir is already up to date." 50 | cd - > /dev/null || exit 51 | return 0 52 | fi 53 | fi 54 | fi 55 | 56 | # Clone the repository 57 | echo "Cloning $repo_url into $dest_dir" 58 | git clone "$repo_url" . 59 | echo "Cloning complete" 60 | 61 | # Checkout to the specific branch or commit 62 | echo "Checking out to $branch_or_commit" 63 | git checkout "$branch_or_commit" 64 | 65 | cd - > /dev/null || exit 66 | } 67 | 68 | # Use environment variables if set, otherwise default to the official repositories 69 | OPTIMISM_REPO=${OPTIMISM_REPO_URL:-https://github.com/ethereum-optimism/optimism.git} 70 | OPTIMISM_BRANCH_OR_COMMIT=${OPTIMISM_BRANCH_OR_COMMIT:-v1.9.0} 71 | OP_GETH_REPO=${OP_GETH_REPO_URL:-https://github.com/ethereum-optimism/op-geth.git} 72 | OP_GETH_BRANCH_OR_COMMIT=${OP_GETH_BRANCH_OR_COMMIT:-v1.101315.3} 73 | 74 | # Cloning repositories 75 | clone_repo "$OPTIMISM_REPO" "$OPTIMISM_BRANCH_OR_COMMIT" "$OPTIMISM_DIR" || exit 1 76 | clone_repo "$OP_GETH_REPO" "$OP_GETH_BRANCH_OR_COMMIT" "$OP_GETH_DIR" || exit 1 77 | 78 | git config --global --add safe.directory '*' 79 | 80 | exec "$@" 81 | -------------------------------------------------------------------------------- /scripts/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Ensure script stops on first error 4 | set -e 5 | 6 | # Clone repositories if necessary 7 | /app/clone-repos.sh 8 | 9 | # Check and build binaries if at least one doesn't exist 10 | if [ ! -f "$BIN_DIR/op-node" ] || [ ! -f "$BIN_DIR/op-batcher" ] || [ ! -f "$BIN_DIR/op-proposer" ] || [ ! -f "$BIN_DIR/geth" ]; then 11 | # Build op-node, op-batcher and op-proposer 12 | cd "$OPTIMISM_DIR" 13 | pnpm install 14 | make op-node op-batcher op-proposer 15 | pnpm build 16 | 17 | # Copy binaries to the bin volume 18 | cp -f "$OPTIMISM_DIR"/op-node/bin/op-node "$BIN_DIR"/ 19 | cp -f "$OPTIMISM_DIR"/op-batcher/bin/op-batcher "$BIN_DIR"/ 20 | cp -f "$OPTIMISM_DIR"/op-proposer/bin/op-proposer "$BIN_DIR"/ 21 | 22 | # Build op-geth 23 | cd "$OP_GETH_DIR" 24 | make geth 25 | 26 | # Copy geth binary to the bin volume 27 | cp ./build/bin/geth "$BIN_DIR"/ 28 | fi 29 | 30 | # Create jwt.txt if it does not exist 31 | [ -f "$CONFIG_PATH/jwt.txt" ] || openssl rand -hex 32 > "$CONFIG_PATH"/jwt.txt 32 | 33 | # Check if all required config files exist 34 | if [ -f "$CONFIG_PATH/genesis.json" ] && [ -f "$CONFIG_PATH/rollup.json" ]; then 35 | echo "L2 config files are present, skipping prepare.sh script." 36 | exec "$@" 37 | exit 0 38 | elif [ -f "$CONFIG_PATH/genesis.json" ] || [ -f "$CONFIG_PATH/rollup.json" ]; then 39 | echo "Error: One of the genesis.json or rollup.json files is missing." 40 | exit 1 41 | fi 42 | 43 | # If no L2 config files exist, continue with the script 44 | echo "No required L2 config files are present, continuing script execution." 45 | 46 | # Check if all or none of the private keys are provided 47 | if [ -z "$BATCHER_PRIVATE_KEY" ] && [ -z "$PROPOSER_PRIVATE_KEY" ] && [ -z "$SEQUENCER_PRIVATE_KEY" ]; then 48 | echo "All private keys are missing, fetching from AWS Secrets Manager..." 49 | secrets=$(aws secretsmanager get-secret-value --secret-id "$AWS_SECRET_ARN" | jq '.SecretString | fromjson') 50 | 51 | BATCHER_PRIVATE_KEY="$(echo "${secrets}" | jq -r '.BATCHER_PRIVATE_KEY')" 52 | PROPOSER_PRIVATE_KEY="$(echo "${secrets}" | jq -r '.PROPOSER_PRIVATE_KEY')" 53 | SEQUENCER_PRIVATE_KEY="$(echo "${secrets}" | jq -r '.SEQUENCER_PRIVATE_KEY')" 54 | 55 | export BATCHER_PRIVATE_KEY PROPOSER_PRIVATE_KEY SEQUENCER_PRIVATE_KEY 56 | elif [ -n "$BATCHER_PRIVATE_KEY" ] && [ -n "$PROPOSER_PRIVATE_KEY" ] && [ -n "$SEQUENCER_PRIVATE_KEY" ]; then 57 | echo "All private keys are provided, continuing..." 58 | else 59 | echo "Error: Private keys must be all provided or all fetched from AWS Secrets Manager." 60 | exit 1 61 | fi 62 | 63 | # Get L1 chain ID and export it 64 | L1_CHAIN_ID=$(cast chain-id --rpc-url "$L1_RPC_URL") 65 | export L1_CHAIN_ID 66 | 67 | # Source the utils.sh file 68 | # shellcheck disable=SC1091 69 | source /app/utils.sh 70 | 71 | # Derive addresses from private keys and check for conflicts 72 | derive_and_check "ADMIN_PRIVATE_KEY" "GS_ADMIN_ADDRESS" 73 | derive_and_check "BATCHER_PRIVATE_KEY" "GS_BATCHER_ADDRESS" 74 | derive_and_check "PROPOSER_PRIVATE_KEY" "GS_PROPOSER_ADDRESS" 75 | derive_and_check "SEQUENCER_PRIVATE_KEY" "GS_SEQUENCER_ADDRESS" 76 | 77 | cd "$OPTIMISM_DIR"/packages/contracts-bedrock 78 | 79 | # Remove old generated internal-opstack-compose.json deploy config 80 | rm -f ./deploy-config/internal-opstack-compose.json 81 | 82 | # Check if deploy-config.json exists 83 | if [ -f "$CONFIG_PATH/deploy-config.json" ]; then 84 | # Populate deploy-config.json with env variables 85 | echo "Populating deploy-config.json with env variables..." 86 | envsubst < "$CONFIG_PATH"/deploy-config.json > /app/temp-deploy-config.json && mv /app/temp-deploy-config.json ./deploy-config/internal-opstack-compose.json 87 | else 88 | # If deploy-config.json does not exist, use config.sh to generate getting-started.json 89 | echo "Generating getting-started.json..." 90 | 91 | ./scripts/getting-started/config.sh 92 | mv ./deploy-config/getting-started.json ./deploy-config/internal-opstack-compose.json 93 | fi 94 | 95 | # Fix L1 and L2 Chain ID to the one set in the environment variable 96 | BATCH_INBOX_ADDRESS_TEMP=$(openssl rand -hex 32 | head -c 40) 97 | export BATCH_INBOX_ADDRESS_TEMP 98 | jq \ 99 | --argjson l1ChainID "$L1_CHAIN_ID" \ 100 | --argjson l2ChainID "$L2_CHAIN_ID" \ 101 | --arg batchInboxAddress "0x$BATCH_INBOX_ADDRESS_TEMP" \ 102 | '.l1ChainID = $l1ChainID | .l2ChainID = $l2ChainID | .batchInboxAddress = $batchInboxAddress' \ 103 | ./deploy-config/internal-opstack-compose.json > /app/temp-deploy-config.json && mv /app/temp-deploy-config.json ./deploy-config/internal-opstack-compose.json 104 | 105 | # Merge deploy override 106 | if [ -f "$CONFIG_PATH"/deploy-override.json ]; then 107 | jq -s '.[0] * .[1]' ./deploy-config/internal-opstack-compose.json "$CONFIG_PATH"/deploy-override.json > /app/temp-deploy-config.json && mv /app/temp-deploy-config.json ./deploy-config/internal-opstack-compose.json 108 | fi 109 | 110 | # Show deployment config for better debuggability 111 | cat ./deploy-config/internal-opstack-compose.json 112 | 113 | # Generate IMPL_SALT 114 | if [ -z "$IMPL_SALT" ]; then 115 | IMPL_SALT=$(sha256sum ./deploy-config/internal-opstack-compose.json | cut -d ' ' -f1) 116 | export IMPL_SALT 117 | fi 118 | 119 | # NOTE: The $DEPLOYMENT_OUTFILE and $DEPLOY_CONFIG_PATH vars are required for line 136 120 | export DEPLOYMENT_OUTFILE=./deployments/artifact.json 121 | export DEPLOY_CONFIG_PATH=./deploy-config/internal-opstack-compose.json # "$CONFIG_PATH"/deploy-config.json not suitable due to the error "... not allowed to be accessed for read operations" 122 | 123 | # If not deployed 124 | if [ ! -f "$DEPLOYMENT_DIR"/artifact.json ]; then 125 | # Determine the script path (fix for v1.7.7) 126 | DEPLOY_SCRIPT_PATH=$(test -f scripts/deploy/Deploy.s.sol && echo "scripts/deploy/Deploy.s.sol" || echo "scripts/Deploy.s.sol") 127 | 128 | # Deploy the L1 contracts 129 | forge script "$DEPLOY_SCRIPT_PATH" --private-key "$DEPLOYER_PRIVATE_KEY" --broadcast --rpc-url "$L1_RPC_URL" 130 | 131 | # Copy the deployment files to the data volume 132 | cp $DEPLOYMENT_OUTFILE "$DEPLOYMENT_DIR"/ 133 | cp $DEPLOY_CONFIG_PATH "$CONFIG_PATH"/deploy-config.json 134 | fi 135 | 136 | # Generating L2 Allocs 137 | export CONTRACT_ADDRESSES_PATH=$DEPLOYMENT_DIR/artifact.json 138 | export STATE_DUMP_PATH=$DEPLOYMENT_DIR/allocs.json 139 | 140 | if [ -f "$STATE_DUMP_PATH" ]; then 141 | echo "State dump already exists, skipping state dump generation." 142 | else 143 | forge script scripts/L2Genesis.s.sol:L2Genesis --chain-id "$L2_CHAIN_ID" --sig 'runWithAllUpgrades()' --private-key "$DEPLOYER_PRIVATE_KEY" # OR runWithStateDump() 144 | fi 145 | 146 | export DEPLOY_CONFIG_PATH="$CONFIG_PATH"/deploy-config.json 147 | # Generate the L2 genesis files 148 | cd "$OPTIMISM_DIR"/op-node 149 | go run cmd/main.go genesis l2 \ 150 | --deploy-config "$DEPLOY_CONFIG_PATH" \ 151 | --l1-deployments "$CONTRACT_ADDRESSES_PATH" \ 152 | --outfile.l2 genesis.json \ 153 | --outfile.rollup rollup.json \ 154 | --l1-rpc "$L1_RPC_URL" \ 155 | --l2-allocs "$STATE_DUMP_PATH" 156 | cp genesis.json "$CONFIG_PATH"/ 157 | cp rollup.json "$CONFIG_PATH"/ 158 | 159 | # Reset repository for cleanup 160 | cd "$OPTIMISM_DIR" 161 | git reset HEAD --hard 162 | 163 | exec "$@" 164 | -------------------------------------------------------------------------------- /scripts/utils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to derive address and check for conflicts 4 | derive_and_check() { 5 | local key_var_name=$1 6 | local addr_var_name=$2 7 | local private_key=${!key_var_name} 8 | local passed_address=${!addr_var_name} 9 | 10 | if [ -n "$private_key" ]; then 11 | local derived_address 12 | derived_address=$(cast wallet address --private-key "$private_key") 13 | echo "$addr_var_name: $derived_address" 14 | 15 | if [ -n "$passed_address" ] && [ "$derived_address" != "$passed_address" ]; then 16 | echo "Error: Derived address for $addr_var_name conflicts with the passed address." 17 | exit 1 18 | fi 19 | 20 | export "$addr_var_name"="$derived_address" 21 | fi 22 | } 23 | -------------------------------------------------------------------------------- /serve/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /serve/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /serve/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use an official Node.js runtime as a parent image 2 | FROM node:16 3 | 4 | # Set the working directory 5 | WORKDIR /app 6 | 7 | # Copy the current directory contents into the container at /app 8 | COPY package*.json ./ 9 | COPY index.js ./ 10 | 11 | # Install dependencies 12 | RUN npm install 13 | 14 | # Make port 3001 available to the world outside this container 15 | EXPOSE 3001 16 | 17 | # Run the app when the container launches 18 | CMD ["node", "index.js"] 19 | -------------------------------------------------------------------------------- /serve/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | const app = express(); 6 | const deploymentsDir = path.join(__dirname, 'data', 'deployments'); 7 | 8 | // Middleware to check if deployments directory exists 9 | app.use((req, res, next) => { 10 | if (fs.existsSync(deploymentsDir)) { 11 | next(); 12 | } else { 13 | res.status(404).json({ error: 'Deployments directory not found' }); 14 | } 15 | }); 16 | 17 | // Serve JSON files from the deployments directory 18 | app.get('/:filename', (req, res) => { 19 | const filePath = path.join(deploymentsDir, req.params.filename); 20 | 21 | // Check if the requested file exists and is a JSON file 22 | if (fs.existsSync(filePath) && filePath.endsWith('.json')) { 23 | res.sendFile(filePath); 24 | } else { 25 | res.status(404).json({ error: 'File not found or not a JSON file' }); 26 | } 27 | }); 28 | 29 | // Start the server on port 3001 30 | const PORT = 3001; 31 | app.listen(PORT, () => { 32 | console.log(`JSON file server running on port ${PORT}`); 33 | }); 34 | -------------------------------------------------------------------------------- /serve/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serve", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "serve", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "express": "^4.21.0" 13 | } 14 | }, 15 | "node_modules/accepts": { 16 | "version": "1.3.8", 17 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 18 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 19 | "dependencies": { 20 | "mime-types": "~2.1.34", 21 | "negotiator": "0.6.3" 22 | }, 23 | "engines": { 24 | "node": ">= 0.6" 25 | } 26 | }, 27 | "node_modules/array-flatten": { 28 | "version": "1.1.1", 29 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 30 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 31 | }, 32 | "node_modules/body-parser": { 33 | "version": "1.20.3", 34 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", 35 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", 36 | "dependencies": { 37 | "bytes": "3.1.2", 38 | "content-type": "~1.0.5", 39 | "debug": "2.6.9", 40 | "depd": "2.0.0", 41 | "destroy": "1.2.0", 42 | "http-errors": "2.0.0", 43 | "iconv-lite": "0.4.24", 44 | "on-finished": "2.4.1", 45 | "qs": "6.13.0", 46 | "raw-body": "2.5.2", 47 | "type-is": "~1.6.18", 48 | "unpipe": "1.0.0" 49 | }, 50 | "engines": { 51 | "node": ">= 0.8", 52 | "npm": "1.2.8000 || >= 1.4.16" 53 | } 54 | }, 55 | "node_modules/bytes": { 56 | "version": "3.1.2", 57 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 58 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 59 | "engines": { 60 | "node": ">= 0.8" 61 | } 62 | }, 63 | "node_modules/call-bind": { 64 | "version": "1.0.7", 65 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", 66 | "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", 67 | "dependencies": { 68 | "es-define-property": "^1.0.0", 69 | "es-errors": "^1.3.0", 70 | "function-bind": "^1.1.2", 71 | "get-intrinsic": "^1.2.4", 72 | "set-function-length": "^1.2.1" 73 | }, 74 | "engines": { 75 | "node": ">= 0.4" 76 | }, 77 | "funding": { 78 | "url": "https://github.com/sponsors/ljharb" 79 | } 80 | }, 81 | "node_modules/content-disposition": { 82 | "version": "0.5.4", 83 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 84 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 85 | "dependencies": { 86 | "safe-buffer": "5.2.1" 87 | }, 88 | "engines": { 89 | "node": ">= 0.6" 90 | } 91 | }, 92 | "node_modules/content-type": { 93 | "version": "1.0.5", 94 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 95 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 96 | "engines": { 97 | "node": ">= 0.6" 98 | } 99 | }, 100 | "node_modules/cookie": { 101 | "version": "0.6.0", 102 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", 103 | "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", 104 | "engines": { 105 | "node": ">= 0.6" 106 | } 107 | }, 108 | "node_modules/cookie-signature": { 109 | "version": "1.0.6", 110 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 111 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 112 | }, 113 | "node_modules/debug": { 114 | "version": "2.6.9", 115 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 116 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 117 | "dependencies": { 118 | "ms": "2.0.0" 119 | } 120 | }, 121 | "node_modules/define-data-property": { 122 | "version": "1.1.4", 123 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", 124 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", 125 | "dependencies": { 126 | "es-define-property": "^1.0.0", 127 | "es-errors": "^1.3.0", 128 | "gopd": "^1.0.1" 129 | }, 130 | "engines": { 131 | "node": ">= 0.4" 132 | }, 133 | "funding": { 134 | "url": "https://github.com/sponsors/ljharb" 135 | } 136 | }, 137 | "node_modules/depd": { 138 | "version": "2.0.0", 139 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 140 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 141 | "engines": { 142 | "node": ">= 0.8" 143 | } 144 | }, 145 | "node_modules/destroy": { 146 | "version": "1.2.0", 147 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 148 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 149 | "engines": { 150 | "node": ">= 0.8", 151 | "npm": "1.2.8000 || >= 1.4.16" 152 | } 153 | }, 154 | "node_modules/ee-first": { 155 | "version": "1.1.1", 156 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 157 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 158 | }, 159 | "node_modules/encodeurl": { 160 | "version": "2.0.0", 161 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", 162 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", 163 | "engines": { 164 | "node": ">= 0.8" 165 | } 166 | }, 167 | "node_modules/es-define-property": { 168 | "version": "1.0.0", 169 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", 170 | "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", 171 | "dependencies": { 172 | "get-intrinsic": "^1.2.4" 173 | }, 174 | "engines": { 175 | "node": ">= 0.4" 176 | } 177 | }, 178 | "node_modules/es-errors": { 179 | "version": "1.3.0", 180 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", 181 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", 182 | "engines": { 183 | "node": ">= 0.4" 184 | } 185 | }, 186 | "node_modules/escape-html": { 187 | "version": "1.0.3", 188 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 189 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 190 | }, 191 | "node_modules/etag": { 192 | "version": "1.8.1", 193 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 194 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 195 | "engines": { 196 | "node": ">= 0.6" 197 | } 198 | }, 199 | "node_modules/express": { 200 | "version": "4.21.0", 201 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", 202 | "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", 203 | "dependencies": { 204 | "accepts": "~1.3.8", 205 | "array-flatten": "1.1.1", 206 | "body-parser": "1.20.3", 207 | "content-disposition": "0.5.4", 208 | "content-type": "~1.0.4", 209 | "cookie": "0.6.0", 210 | "cookie-signature": "1.0.6", 211 | "debug": "2.6.9", 212 | "depd": "2.0.0", 213 | "encodeurl": "~2.0.0", 214 | "escape-html": "~1.0.3", 215 | "etag": "~1.8.1", 216 | "finalhandler": "1.3.1", 217 | "fresh": "0.5.2", 218 | "http-errors": "2.0.0", 219 | "merge-descriptors": "1.0.3", 220 | "methods": "~1.1.2", 221 | "on-finished": "2.4.1", 222 | "parseurl": "~1.3.3", 223 | "path-to-regexp": "0.1.10", 224 | "proxy-addr": "~2.0.7", 225 | "qs": "6.13.0", 226 | "range-parser": "~1.2.1", 227 | "safe-buffer": "5.2.1", 228 | "send": "0.19.0", 229 | "serve-static": "1.16.2", 230 | "setprototypeof": "1.2.0", 231 | "statuses": "2.0.1", 232 | "type-is": "~1.6.18", 233 | "utils-merge": "1.0.1", 234 | "vary": "~1.1.2" 235 | }, 236 | "engines": { 237 | "node": ">= 0.10.0" 238 | } 239 | }, 240 | "node_modules/finalhandler": { 241 | "version": "1.3.1", 242 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", 243 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", 244 | "dependencies": { 245 | "debug": "2.6.9", 246 | "encodeurl": "~2.0.0", 247 | "escape-html": "~1.0.3", 248 | "on-finished": "2.4.1", 249 | "parseurl": "~1.3.3", 250 | "statuses": "2.0.1", 251 | "unpipe": "~1.0.0" 252 | }, 253 | "engines": { 254 | "node": ">= 0.8" 255 | } 256 | }, 257 | "node_modules/forwarded": { 258 | "version": "0.2.0", 259 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 260 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 261 | "engines": { 262 | "node": ">= 0.6" 263 | } 264 | }, 265 | "node_modules/fresh": { 266 | "version": "0.5.2", 267 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 268 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 269 | "engines": { 270 | "node": ">= 0.6" 271 | } 272 | }, 273 | "node_modules/function-bind": { 274 | "version": "1.1.2", 275 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 276 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 277 | "funding": { 278 | "url": "https://github.com/sponsors/ljharb" 279 | } 280 | }, 281 | "node_modules/get-intrinsic": { 282 | "version": "1.2.4", 283 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", 284 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", 285 | "dependencies": { 286 | "es-errors": "^1.3.0", 287 | "function-bind": "^1.1.2", 288 | "has-proto": "^1.0.1", 289 | "has-symbols": "^1.0.3", 290 | "hasown": "^2.0.0" 291 | }, 292 | "engines": { 293 | "node": ">= 0.4" 294 | }, 295 | "funding": { 296 | "url": "https://github.com/sponsors/ljharb" 297 | } 298 | }, 299 | "node_modules/gopd": { 300 | "version": "1.0.1", 301 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 302 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 303 | "dependencies": { 304 | "get-intrinsic": "^1.1.3" 305 | }, 306 | "funding": { 307 | "url": "https://github.com/sponsors/ljharb" 308 | } 309 | }, 310 | "node_modules/has-property-descriptors": { 311 | "version": "1.0.2", 312 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", 313 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", 314 | "dependencies": { 315 | "es-define-property": "^1.0.0" 316 | }, 317 | "funding": { 318 | "url": "https://github.com/sponsors/ljharb" 319 | } 320 | }, 321 | "node_modules/has-proto": { 322 | "version": "1.0.3", 323 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", 324 | "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", 325 | "engines": { 326 | "node": ">= 0.4" 327 | }, 328 | "funding": { 329 | "url": "https://github.com/sponsors/ljharb" 330 | } 331 | }, 332 | "node_modules/has-symbols": { 333 | "version": "1.0.3", 334 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 335 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 336 | "engines": { 337 | "node": ">= 0.4" 338 | }, 339 | "funding": { 340 | "url": "https://github.com/sponsors/ljharb" 341 | } 342 | }, 343 | "node_modules/hasown": { 344 | "version": "2.0.2", 345 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 346 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 347 | "dependencies": { 348 | "function-bind": "^1.1.2" 349 | }, 350 | "engines": { 351 | "node": ">= 0.4" 352 | } 353 | }, 354 | "node_modules/http-errors": { 355 | "version": "2.0.0", 356 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 357 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 358 | "dependencies": { 359 | "depd": "2.0.0", 360 | "inherits": "2.0.4", 361 | "setprototypeof": "1.2.0", 362 | "statuses": "2.0.1", 363 | "toidentifier": "1.0.1" 364 | }, 365 | "engines": { 366 | "node": ">= 0.8" 367 | } 368 | }, 369 | "node_modules/iconv-lite": { 370 | "version": "0.4.24", 371 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 372 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 373 | "dependencies": { 374 | "safer-buffer": ">= 2.1.2 < 3" 375 | }, 376 | "engines": { 377 | "node": ">=0.10.0" 378 | } 379 | }, 380 | "node_modules/inherits": { 381 | "version": "2.0.4", 382 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 383 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 384 | }, 385 | "node_modules/ipaddr.js": { 386 | "version": "1.9.1", 387 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 388 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 389 | "engines": { 390 | "node": ">= 0.10" 391 | } 392 | }, 393 | "node_modules/media-typer": { 394 | "version": "0.3.0", 395 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 396 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 397 | "engines": { 398 | "node": ">= 0.6" 399 | } 400 | }, 401 | "node_modules/merge-descriptors": { 402 | "version": "1.0.3", 403 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", 404 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", 405 | "funding": { 406 | "url": "https://github.com/sponsors/sindresorhus" 407 | } 408 | }, 409 | "node_modules/methods": { 410 | "version": "1.1.2", 411 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 412 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 413 | "engines": { 414 | "node": ">= 0.6" 415 | } 416 | }, 417 | "node_modules/mime": { 418 | "version": "1.6.0", 419 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 420 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 421 | "bin": { 422 | "mime": "cli.js" 423 | }, 424 | "engines": { 425 | "node": ">=4" 426 | } 427 | }, 428 | "node_modules/mime-db": { 429 | "version": "1.52.0", 430 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 431 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 432 | "engines": { 433 | "node": ">= 0.6" 434 | } 435 | }, 436 | "node_modules/mime-types": { 437 | "version": "2.1.35", 438 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 439 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 440 | "dependencies": { 441 | "mime-db": "1.52.0" 442 | }, 443 | "engines": { 444 | "node": ">= 0.6" 445 | } 446 | }, 447 | "node_modules/ms": { 448 | "version": "2.0.0", 449 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 450 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 451 | }, 452 | "node_modules/negotiator": { 453 | "version": "0.6.3", 454 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 455 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 456 | "engines": { 457 | "node": ">= 0.6" 458 | } 459 | }, 460 | "node_modules/object-inspect": { 461 | "version": "1.13.2", 462 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", 463 | "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", 464 | "engines": { 465 | "node": ">= 0.4" 466 | }, 467 | "funding": { 468 | "url": "https://github.com/sponsors/ljharb" 469 | } 470 | }, 471 | "node_modules/on-finished": { 472 | "version": "2.4.1", 473 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 474 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 475 | "dependencies": { 476 | "ee-first": "1.1.1" 477 | }, 478 | "engines": { 479 | "node": ">= 0.8" 480 | } 481 | }, 482 | "node_modules/parseurl": { 483 | "version": "1.3.3", 484 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 485 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 486 | "engines": { 487 | "node": ">= 0.8" 488 | } 489 | }, 490 | "node_modules/path-to-regexp": { 491 | "version": "0.1.10", 492 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", 493 | "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" 494 | }, 495 | "node_modules/proxy-addr": { 496 | "version": "2.0.7", 497 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 498 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 499 | "dependencies": { 500 | "forwarded": "0.2.0", 501 | "ipaddr.js": "1.9.1" 502 | }, 503 | "engines": { 504 | "node": ">= 0.10" 505 | } 506 | }, 507 | "node_modules/qs": { 508 | "version": "6.13.0", 509 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", 510 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", 511 | "dependencies": { 512 | "side-channel": "^1.0.6" 513 | }, 514 | "engines": { 515 | "node": ">=0.6" 516 | }, 517 | "funding": { 518 | "url": "https://github.com/sponsors/ljharb" 519 | } 520 | }, 521 | "node_modules/range-parser": { 522 | "version": "1.2.1", 523 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 524 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 525 | "engines": { 526 | "node": ">= 0.6" 527 | } 528 | }, 529 | "node_modules/raw-body": { 530 | "version": "2.5.2", 531 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", 532 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", 533 | "dependencies": { 534 | "bytes": "3.1.2", 535 | "http-errors": "2.0.0", 536 | "iconv-lite": "0.4.24", 537 | "unpipe": "1.0.0" 538 | }, 539 | "engines": { 540 | "node": ">= 0.8" 541 | } 542 | }, 543 | "node_modules/safe-buffer": { 544 | "version": "5.2.1", 545 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 546 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 547 | "funding": [ 548 | { 549 | "type": "github", 550 | "url": "https://github.com/sponsors/feross" 551 | }, 552 | { 553 | "type": "patreon", 554 | "url": "https://www.patreon.com/feross" 555 | }, 556 | { 557 | "type": "consulting", 558 | "url": "https://feross.org/support" 559 | } 560 | ] 561 | }, 562 | "node_modules/safer-buffer": { 563 | "version": "2.1.2", 564 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 565 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 566 | }, 567 | "node_modules/send": { 568 | "version": "0.19.0", 569 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", 570 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", 571 | "dependencies": { 572 | "debug": "2.6.9", 573 | "depd": "2.0.0", 574 | "destroy": "1.2.0", 575 | "encodeurl": "~1.0.2", 576 | "escape-html": "~1.0.3", 577 | "etag": "~1.8.1", 578 | "fresh": "0.5.2", 579 | "http-errors": "2.0.0", 580 | "mime": "1.6.0", 581 | "ms": "2.1.3", 582 | "on-finished": "2.4.1", 583 | "range-parser": "~1.2.1", 584 | "statuses": "2.0.1" 585 | }, 586 | "engines": { 587 | "node": ">= 0.8.0" 588 | } 589 | }, 590 | "node_modules/send/node_modules/encodeurl": { 591 | "version": "1.0.2", 592 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 593 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 594 | "engines": { 595 | "node": ">= 0.8" 596 | } 597 | }, 598 | "node_modules/send/node_modules/ms": { 599 | "version": "2.1.3", 600 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 601 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 602 | }, 603 | "node_modules/serve-static": { 604 | "version": "1.16.2", 605 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", 606 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", 607 | "dependencies": { 608 | "encodeurl": "~2.0.0", 609 | "escape-html": "~1.0.3", 610 | "parseurl": "~1.3.3", 611 | "send": "0.19.0" 612 | }, 613 | "engines": { 614 | "node": ">= 0.8.0" 615 | } 616 | }, 617 | "node_modules/set-function-length": { 618 | "version": "1.2.2", 619 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", 620 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", 621 | "dependencies": { 622 | "define-data-property": "^1.1.4", 623 | "es-errors": "^1.3.0", 624 | "function-bind": "^1.1.2", 625 | "get-intrinsic": "^1.2.4", 626 | "gopd": "^1.0.1", 627 | "has-property-descriptors": "^1.0.2" 628 | }, 629 | "engines": { 630 | "node": ">= 0.4" 631 | } 632 | }, 633 | "node_modules/setprototypeof": { 634 | "version": "1.2.0", 635 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 636 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 637 | }, 638 | "node_modules/side-channel": { 639 | "version": "1.0.6", 640 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", 641 | "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", 642 | "dependencies": { 643 | "call-bind": "^1.0.7", 644 | "es-errors": "^1.3.0", 645 | "get-intrinsic": "^1.2.4", 646 | "object-inspect": "^1.13.1" 647 | }, 648 | "engines": { 649 | "node": ">= 0.4" 650 | }, 651 | "funding": { 652 | "url": "https://github.com/sponsors/ljharb" 653 | } 654 | }, 655 | "node_modules/statuses": { 656 | "version": "2.0.1", 657 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 658 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 659 | "engines": { 660 | "node": ">= 0.8" 661 | } 662 | }, 663 | "node_modules/toidentifier": { 664 | "version": "1.0.1", 665 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 666 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 667 | "engines": { 668 | "node": ">=0.6" 669 | } 670 | }, 671 | "node_modules/type-is": { 672 | "version": "1.6.18", 673 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 674 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 675 | "dependencies": { 676 | "media-typer": "0.3.0", 677 | "mime-types": "~2.1.24" 678 | }, 679 | "engines": { 680 | "node": ">= 0.6" 681 | } 682 | }, 683 | "node_modules/unpipe": { 684 | "version": "1.0.0", 685 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 686 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 687 | "engines": { 688 | "node": ">= 0.8" 689 | } 690 | }, 691 | "node_modules/utils-merge": { 692 | "version": "1.0.1", 693 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 694 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 695 | "engines": { 696 | "node": ">= 0.4.0" 697 | } 698 | }, 699 | "node_modules/vary": { 700 | "version": "1.1.2", 701 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 702 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 703 | "engines": { 704 | "node": ">= 0.8" 705 | } 706 | } 707 | } 708 | } 709 | -------------------------------------------------------------------------------- /serve/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serve", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "author": "", 9 | "license": "ISC", 10 | "description": "", 11 | "dependencies": { 12 | "express": "^4.21.0" 13 | } 14 | } 15 | --------------------------------------------------------------------------------