Skip to content

Commit

Permalink
Merge pull request #341 from Lumerin-protocol/test
Browse files Browse the repository at this point in the history
ConfigChecker & Docker for proxy-router
  • Loading branch information
abs2023 authored Dec 5, 2024
2 parents f03588d + 60c954d commit d3540e3
Show file tree
Hide file tree
Showing 40 changed files with 1,161 additions and 162 deletions.
2 changes: 1 addition & 1 deletion .github/actions/gen_tag_name/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ runs:
VMIN=0
VPAT=0
set +o pipefail
VLAST=$(git describe --tags --abbrev=0 --match='v[1-9]*' 2>/dev/null | cut -c2-)
VLAST=$(git describe --tags --abbrev=0 --match='v[1-9]*' refs/remotes/origin/main 2>/dev/null | cut -c2-)
[ $VLAST ] && declare $(echo $VLAST | awk -F '.' '{print "VMAJ="$1" VMIN="$2" VPAT="$3}')
if [ "$GITHUB_REF_NAME" = "main" ]
then
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
--form "ref=${{ env.gitlab_branch }}" \
--form "variables[SOURCE_REPO]=${{ github.repository }}" \
--form "variables[SOURCE_BRANCH]=${{ github.ref_name }}" \
--form "variables[GITHUB_VFULL]=${{ env.VFULL }}" \
--form "variables[GITHUB_TAG]=${{ env.TAG_NAME }}")

# Parse JSON response using jq
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/proxy-router.main.env
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ PROXY_ADDRESS=0.0.0.0:3333
WEB_ADDRESS=0.0.0.0:8082
WEB_PUBLIC_URL=http://localhost:8082
MODELS_CONFIG_PATH=
RATING_CONFIG_PATH=
ETH_NODE_USE_SUBSCRIPTIONS=false
ETH_NODE_ADDRESS=
ETH_NODE_LEGACY_TX=false
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/proxy-router.test.env
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ PROXY_ADDRESS=0.0.0.0:3333
WEB_ADDRESS=0.0.0.0:8082
WEB_PUBLIC_URL=http://localhost:8082
MODELS_CONFIG_PATH=
RATING_CONFIG_PATH=
ETH_NODE_USE_SUBSCRIPTIONS=false
ETH_NODE_ADDRESS=
ETH_NODE_LEGACY_TX=false
Expand Down
76 changes: 76 additions & 0 deletions docs/02a-proxy-router-docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@

# Proxy-Router Docker Setup:

**This document describes setting up the proxy-router component of the Morpheus AI Network in a Docker container ONLY and accessing it via the Swagger API Interface...no GUI or Wallet components are included in this setup**

## Overview:
* The Proxy-Router is a critical component of the Morpheus AI Network. It is responsible for monitoring the blockchain for events and managing the AI models and providers that are available to the network.
* The Proxy-Router is a standalone application that can be run on any server that has access to the blockchain and the AI models.
* This document walks through using Docker to build and run the proxy-router image on your server.

## Pre-Requisites:
* Your AI model has been configured, started and made available to the proxy-router server via a private endpoint (IP:PORT or DNS:PORT) eg: `http://mycoolaimodel.domain.com:8080`
* You have an existing funded wallet with MOR and ETH and also have the `private key` for the wallet (this will be needed for the .env file configuration)
* Your proxy-router must have a **publicly accessible endpoint** for the provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` - this will be used when creating the provider on the blockchain
* Docker and Git are installed and current on your server
* The three key configuration files are located in the same directory as the proxy-router code:
* .env
* models-config.json
* rating-config.json

## Installation & Configuration Steps:
1. Clone the source code from the repository:
* `git clone -b main https://github.com/Lumerin-protocol/Morpheus-Lumerin-Node.git`
1. Change to the proxy-router directory:
* `cd Morpheus-Lumerin-Node\proxy-router`
1. Configure the 3 key files for your environment:
1. Environment file configuration
1. Copy the example file to .env:
* Linux/Mac: `cp .env.example .env`
* Windows: `copy .env.example.win .env`
1. Edit values within the .env as desired
* Add your private key to`WALLET_PRIVATE_KEY=`
* Modify the following values to ensure that those files remain "outside of the running container" for persistence and are mounted by the docker-compose.yml file's `volume` directive
* `MODELS_CONFIG_PATH=/app/data/models-config.json`
* `RATING_CONFIG_PATH=/app/data/rating-config.json`
* `PROXY_STORAGE_PATH=/app/data/`
1. Choose the **blockchain** you'd like to work on...**Arbitrum MAINNET is the default**
* To operate on the Sepolia Arbitrum TESTNET,
* Uncomment the `TESTNET VALUES` and comment the `MAINNET VALUES` lines & save the file
1. Models Configuration file
1. Copy the example file to models-config.json:
* Linux/Mac: `cp models-config.json.example models-config.json`
* Windows: `copy models-config.json.example models-config.json`
1. Edit the models-config.json file to include the models you'd like to use.
1. Details here: [models-config.json.md](models-config.json.md)
1. Once your provider is up and running, deploy a new model and model bid via the API interface (you will need to update the `modelId` for the configuration)
1. Rating Configuration file
1. Copy the example file to rating-config.json:
* Linux/Mac: `cp rating-config.json.example rating-config.json`
* Windows: `copy rating-config.json.example rating-config.json`
1. Edit the rating-config.json file to include the weights and preferred providers you'd like to use.
1. Details here: [rating-config.json.md](rating-config.json.md)

## Build the proxy-router Docker Image:
1. Build the Docker image using the provided `docker_build.sh` script
* `./docker_build.sh --build`
* This script pulls the current Git tag and version, builds the docker image with all the port and defaults defined in the docker-compose.yml file

## Running the proxy-router Docker Container:
1. Run the Docker container using the provided `docker_build.sh` script
* `./docker_build.sh --run`
* This script runs the docker container with the port and volume mappings defined in the docker-compose.yml file
* The proxy-router will start and begin listening for blockchain events

## Validating Steps:
1. Once the proxy-router is running, you can navigate to the Swagger API Interface (http://localhost:8082/swagger/index.html as example) to validate that the proxy-router is running and listening for blockchain events
1. Once validated, you can move on and create your provider, model and bid on the blockchain [03-provider-offer.md](03-provider-offer.md)

## NOTES:
* We have created docker-compose.yml, Dockerfile and docker_build.sh scripts to ease configuration and deployment of the proxy-router in a containerized environment
* Use these files as guides for applying to your system needs and configurations, private key, eth_node, ports, endpoints, volumes, .env, models-config.json and rating-config.json will need to be adjusted to your specific needs
* In most cases, the default .env file will work for the proxy-router...In some cases you will want to modify the .env file with advanced capability (log entries, private keys, private endpoints, etc)
* Please see the following for more information on these key config files:
* [proxy-router.all.env](proxy-router.all.env)
* [models-config.json.md](models-config.json.md)
* [rating-config.json.md](rating-config.json.md)
1 change: 1 addition & 0 deletions proxy-router/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ PROXY_ADDRESS=0.0.0.0:3333
WEB_ADDRESS=0.0.0.0:8082
WEB_PUBLIC_URL=http://localhost:8082
MODELS_CONFIG_PATH=
RATING_CONFIG_PATH=
ETH_NODE_USE_SUBSCRIPTIONS=false
ETH_NODE_ADDRESS=
ETH_NODE_LEGACY_TX=false
Expand Down
1 change: 1 addition & 0 deletions proxy-router/.env.example.win
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ PROXY_ADDRESS=0.0.0.0:3333
WEB_ADDRESS=0.0.0.0:8082
WEB_PUBLIC_URL=http://localhost:8082
MODELS_CONFIG_PATH=
RATING_CONFIG_PATH=
ETH_NODE_USE_SUBSCRIPTIONS=false
ETH_NODE_ADDRESS=
ETH_NODE_LEGACY_TX=false
Expand Down
12 changes: 11 additions & 1 deletion proxy-router/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,14 @@ bin

data*

models-config.json
models-config.json
rating-config.json

#Badger DB
*.vlog
*.mem
DISCARD
KEYREGISTRY
LOCK
MANIFEST
chats/
15 changes: 5 additions & 10 deletions proxy-router/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Stage 1: Build
FROM golang:1.22.3-alpine as builder
FROM golang:1.22.3-alpine AS builder

# Capture the Git tag and commit hash during build
ARG TAG_NAME
Expand All @@ -10,16 +10,11 @@ ENV COMMIT=$COMMIT
WORKDIR /app
COPY . .

# Build the Go binary (recommended for linux/amd64...for MacARM use buildx)
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
# Build the Go binary (Docker will build automatically to the OS and Arch that is hosting)
RUN CGO_ENABLED=0 \
TAG_NAME=$TAG_NAME COMMIT=$COMMIT ./build.sh && \
cp /bin/sh /app/sh && chmod +x /app/sh

# Multiplatform Build Notes:
# to support both amd64 and arm64, use Docker’s Buildx to create a multi-architecture image
# docker buildx create --use
# docker buildx build --platform linux/amd64,linux/arm64 -t proxy-router:latest .

# Stage 2: Final Image
FROM scratch
WORKDIR /app
Expand All @@ -29,8 +24,8 @@ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/bin/proxy-router /usr/bin/

# Optional Copy utilities from busybox image
# COPY --from=busybox /bin /bin
# COPY --from=busybox /lib /lib
COPY --from=busybox /bin /bin
COPY --from=busybox /lib /lib

SHELL ["/bin/sh", "-c"]
EXPOSE 3333 8082
Expand Down
30 changes: 14 additions & 16 deletions proxy-router/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ func start() error {
docs.SwaggerInfo.Host = hostWithoutProtocol
} else if cfg.Web.Address != "" {
docs.SwaggerInfo.Host = cfg.Web.Address
} else {
docs.SwaggerInfo.Host = "localhost:8082"
}
docs.SwaggerInfo.Version = config.BuildVersion

docs.SwaggerInfo.Version = config.BuildVersion

log, err := lib.NewLogger(cfg.Log.LevelApp, cfg.Log.Color, cfg.Log.IsProd, cfg.Log.JSON, mainLogFilePath)
if err != nil {
return err
Expand Down Expand Up @@ -227,11 +227,6 @@ func start() error {
}
appLog.Infof("connected to ethereum node: %s, chainID: %d", cfg.Blockchain.EthNodeAddress, chainID)

publicUrl, err := url.Parse(cfg.Web.PublicUrl)
if err != nil {
return err
}

storage := storages.NewStorage(badgerLog, cfg.Proxy.StoragePath)
sessionStorage := storages.NewSessionStorage(storage)

Expand All @@ -246,19 +241,13 @@ func start() error {

var logWatcher contracts.LogWatcher
if cfg.Blockchain.UseSubscriptions {
logWatcher = contracts.NewLogWatcherSubscription(ethClient, cfg.Blockchain.MaxReconnects, log)
logWatcher = contracts.NewLogWatcherSubscription(ethClient, cfg.Blockchain.MaxReconnects, rpcLog)
appLog.Infof("using websocket log subscription for blockchain events")
} else {
logWatcher = contracts.NewLogWatcherPolling(ethClient, cfg.Blockchain.PollingInterval, cfg.Blockchain.MaxReconnects, log)
logWatcher = contracts.NewLogWatcherPolling(ethClient, cfg.Blockchain.PollingInterval, cfg.Blockchain.MaxReconnects, rpcLog)
appLog.Infof("using polling for blockchain events")
}

modelConfigLoader := config.NewModelConfigLoader(cfg.Proxy.ModelsConfigPath, log)
err = modelConfigLoader.Init()
if err != nil {
log.Warnf("failed to load model config: %s, run with empty", err)
}

scorer, err := config.LoadRating(cfg.Proxy.RatingConfigPath, log)
if err != nil {
return err
Expand All @@ -271,10 +260,17 @@ func start() error {
sessionRouter := registries.NewSessionRouter(*cfg.Marketplace.DiamondContractAddress, ethClient, multicallBackend, log)
marketplace := registries.NewMarketplace(*cfg.Marketplace.DiamondContractAddress, ethClient, multicallBackend, log)
sessionRepo := sessionrepo.NewSessionRepositoryCached(sessionStorage, sessionRouter, marketplace)
proxyRouterApi := proxyapi.NewProxySender(chainID, publicUrl, wallet, contractLogStorage, sessionStorage, sessionRepo, log)
proxyRouterApi := proxyapi.NewProxySender(chainID, wallet, contractLogStorage, sessionStorage, sessionRepo, log)
explorer := blockchainapi.NewExplorerClient(cfg.Blockchain.ExplorerApiUrl, *cfg.Marketplace.MorTokenAddress, cfg.Blockchain.ExplorerRetryDelay, cfg.Blockchain.ExplorerMaxRetries)
blockchainApi := blockchainapi.NewBlockchainService(ethClient, multicallBackend, *cfg.Marketplace.DiamondContractAddress, *cfg.Marketplace.MorTokenAddress, explorer, wallet, proxyRouterApi, sessionRepo, scorer, proxyLog, cfg.Blockchain.EthLegacyTx)
proxyRouterApi.SetSessionService(blockchainApi)

modelConfigLoader := config.NewModelConfigLoader(cfg.Proxy.ModelsConfigPath, valid, blockchainApi, &aiengine.ConnectionChecker{}, log)
err = modelConfigLoader.Init()
if err != nil {
log.Warnf("failed to load model config, running with empty: %s", err)
}

aiEngine := aiengine.NewAiEngine(proxyRouterApi, chatStorage, modelConfigLoader, log)

eventListener := blockchainapi.NewEventsListener(sessionRepo, sessionRouter, wallet, logWatcher, log)
Expand All @@ -299,6 +295,8 @@ func start() error {
cancel()
}()

log.Infof("API docs available at %s/swagger/index.html", cfg.Web.PublicUrl)

proxy := proxyctl.NewProxyCtl(eventListener, wallet, chainID, log, connLog, cfg.Proxy.Address, schedulerLogFactory, sessionStorage, modelConfigLoader, valid, aiEngine, blockchainApi, sessionRepo, sessionExpiryHandler)
err = proxy.Run(ctx)

Expand Down
13 changes: 10 additions & 3 deletions proxy-router/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
services:
proxy-router:
build: .
build:
context: .
args:
COMMIT: ${COMMIT:-unknown}
TAG_NAME: ${TAG_NAME:-latest}
image: proxy-router:${TAG_NAME}
env_file:
- .env
ports:
- 8082:8082
- 3333:3333
- "8082:8082"
- "3333:3333"
volumes:
- .:/app/data
43 changes: 43 additions & 0 deletions proxy-router/docker_build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/sh

# This script assumes you've cloned the repository and want to build with proper commit and version numbers
# It will use the latest Git tag as the version number and the latest short commit hash as the commit number
# It also leverages the docker-compose.yml file to build the Docker image

# Pre-requisites: Docker & Git installed

# Assumptions:
# - properly formatted .env in current directory
# - properly formatted models-config.json in current directory
# - properly formatted rating-config.json in current directory

# Check if TAG_NAME is set; if not, use the latest Git tag
if [ -z "$TAG_NAME" ]; then
VLAST=$(git describe --tags --abbrev=0 --match='v[1-9]*' refs/remotes/origin/main 2>/dev/null | cut -c2-)
[ $VLAST ] && declare $(echo $VLAST | awk -F '.' '{print "VMAJ="$1" VMIN="$2" VPAT="$3}')
MB=$(git merge-base refs/remotes/origin/main HEAD)
VPAT=$(git rev-list --count --no-merges ${MB}..HEAD)
TAG_NAME=${VMAJ}.${VMIN}.${VPAT}
fi
VERSION=$TAG_NAME
echo VERSION=$VERSION

# if commit is not set, use the latest commit
if [ -z "$COMMIT" ]; then
SHORT_COMMIT=$(git rev-parse --short HEAD)
fi
COMMIT=$SHORT_COMMIT
echo COMMIT=$COMMIT
export VERSION COMMIT TAG_NAME

# Check if the user wants to build or run the Docker image
if [ "$1" = "--build" ]; then
echo "Building Docker image..."
docker-compose build
docker tag proxy-router:$VERSION proxy-router:latest
elif [ "$1" = "--run" ]; then
echo "Running Docker container..."
docker-compose up
else
echo "Usage: $0 [--build | --run]"
fi
54 changes: 54 additions & 0 deletions proxy-router/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,37 @@ const docTemplate = `{
}
}
},
"/proxy/provider/ping": {
"post": {
"description": "sends a ping to the provider on the RPC level",
"produces": [
"application/json"
],
"tags": [
"chat"
],
"summary": "Ping Provider",
"parameters": [
{
"description": "Ping Request",
"name": "pingReq",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/proxyapi.PingReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/proxyapi.PingRes"
}
}
}
}
},
"/proxy/sessions/initiate": {
"post": {
"description": "sends a handshake to the provider",
Expand Down Expand Up @@ -1844,6 +1875,29 @@ const docTemplate = `{
}
}
},
"proxyapi.PingReq": {
"type": "object",
"required": [
"providerAddr",
"providerUrl"
],
"properties": {
"providerAddr": {
"type": "string"
},
"providerUrl": {
"type": "string"
}
}
},
"proxyapi.PingRes": {
"type": "object",
"properties": {
"ping": {
"type": "integer"
}
}
},
"proxyapi.ResultResponse": {
"type": "object",
"properties": {
Expand Down
Loading

0 comments on commit d3540e3

Please sign in to comment.