Skip to content

Commit

Permalink
Misc TODOs, deployment steps, and things from first mainnet run
Browse files Browse the repository at this point in the history
  • Loading branch information
b-j-roberts committed Jul 13, 2024
1 parent 491896a commit 4158410
Show file tree
Hide file tree
Showing 18 changed files with 342 additions and 22 deletions.
45 changes: 45 additions & 0 deletions backend/cmd/video-gen/video.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package main

import (
"flag"

"github.com/keep-starknet-strange/art-peace/backend/config"
"github.com/keep-starknet-strange/art-peace/backend/core"
"github.com/keep-starknet-strange/art-peace/backend/routes"
"github.com/keep-starknet-strange/art-peace/backend/routes/indexer"
)

func main() {
canvasConfigFilename := flag.String("canvas-config", config.DefaultCanvasConfigPath, "Canvas config file")
databaseConfigFilename := flag.String("database-config", config.DefaultDatabaseConfigPath, "Database config file")
backendConfigFilename := flag.String("backend-config", config.DefaultBackendConfigPath, "Backend config file")

flag.Parse()

canvasConfig, err := config.LoadCanvasConfig(*canvasConfigFilename)
if err != nil {
panic(err)
}

databaseConfig, err := config.LoadDatabaseConfig(*databaseConfigFilename)
if err != nil {
panic(err)
}

backendConfig, err := config.LoadBackendConfig(*backendConfigFilename)
if err != nil {
panic(err)
}

databases := core.NewDatabases(databaseConfig)
defer databases.Close()

core.ArtPeaceBackend = core.NewBackend(databases, canvasConfig, backendConfig, true)

routes.InitBaseRoutes()
routes.InitCanvasRoutes()
indexer.InitIndexerRoutes()
indexer.StartMessageProcessor()

core.ArtPeaceBackend.Start(core.ArtPeaceBackend.BackendConfig.ConsumerPort)
}
4 changes: 1 addition & 3 deletions backend/core/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import (
)

type Backend struct {
Databases *Databases
// TODO: Is this thread safe?
Databases *Databases
WSConnections []*websocket.Conn
WSConnectionsLock sync.Mutex

Expand Down Expand Up @@ -41,7 +40,6 @@ func (b *Backend) Start(port int) {

func (b *Backend) GetBackendUrl() string {
if b.BackendConfig.Production {
// TODO: To config
return "https://api.art-peace.net"
} else {
return fmt.Sprintf("http://%s:%d", b.BackendConfig.Host, b.BackendConfig.Port)
Expand Down
1 change: 0 additions & 1 deletion backend/routes/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ func getContractAddress(w http.ResponseWriter, r *http.Request) {
routeutils.WriteDataJson(w, "\""+contractAddress+"\"")
}

// TODO: Set env var on infra level in production
func setContractAddress(w http.ResponseWriter, r *http.Request) {
// Only allow admin to set contract address
if routeutils.AdminMiddleware(w, r) {
Expand Down
2 changes: 1 addition & 1 deletion backend/routes/factions.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func initFactions(w http.ResponseWriter, r *http.Request) {
return
}

// TODO: check if quests already exist
// TODO: check if factions already exist
factionJson, err := routeutils.ReadJsonBody[FactionsConfig](r)
if err != nil {
routeutils.WriteErrorJson(w, http.StatusBadRequest, "Failed to parse request body")
Expand Down
1 change: 0 additions & 1 deletion backend/routes/indexer/nft.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ func processNFTMintedEvent(event IndexerEvent) {

x := position % int64(core.ArtPeaceBackend.CanvasConfig.Canvas.Width)
y := position / int64(core.ArtPeaceBackend.CanvasConfig.Canvas.Width)
// TODO: Name from onchain mint event
metadata := map[string]interface{}{
"name": name,
"description": "User minted art/peace NFT from the canvas.",
Expand Down
1 change: 0 additions & 1 deletion backend/routes/nft.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ func getCanvasNFTAddress(w http.ResponseWriter, r *http.Request) {
routeutils.WriteDataJson(w, "\""+contractAddress+"\"")
}

// TODO: Set env var on infra level in production
func setCanvasNFTAddress(w http.ResponseWriter, r *http.Request) {
// Only allow admin to set contract address
if routeutils.AdminMiddleware(w, r) {
Expand Down
2 changes: 1 addition & 1 deletion backend/routes/quests.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ func GetDailyQuests(w http.ResponseWriter, r *http.Request) {
routeutils.WriteDataJson(w, string(jsonQuests))
}

// TODO: Here
func GetMainQuests(w http.ResponseWriter, r *http.Request) {
quests, err := core.PostgresQuery[MainQuest]("SELECT key - 1 as quest_id, name, description, reward FROM MainQuests ORDER BY quest_id ASC")
if err != nil {
Expand Down Expand Up @@ -314,6 +313,7 @@ func GetMainUserQuests(w http.ResponseWriter, r *http.Request) {

// Add claim params to quests
for _, questClaimParam := range questClaimParams {
// TODO: Assumes no gaps in quest ids
quests[questClaimParam.QuestId].ClaimParams = append(quests[questClaimParam.QuestId].ClaimParams, questClaimParam)
}

Expand Down
1 change: 0 additions & 1 deletion backend/routes/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func getUsernameStoreAddress(w http.ResponseWriter, r *http.Request) {
routeutils.WriteDataJson(w, "\""+contractAddress+"\"")
}

// TODO: Set env var on infra level in production
func setUsernameStoreAddress(w http.ResponseWriter, r *http.Request) {
// Only allow admin to set contract address
if routeutils.AdminMiddleware(w, r) {
Expand Down
3 changes: 3 additions & 0 deletions backend/video/indexer.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ART_PEACE_CONTRACT_ADDRESS='0x0384e5fa826e1151715dbc3df0bd1b3aaec234dfc344394d02c39b670e354c48'
CONSUMER_TARGET_URL='http://localhost:8081/consume-indexer-msg'
APIBARA_STREAM_URL='https://mainnet.starknet.a5a.ch'
80 changes: 80 additions & 0 deletions backend/video/video.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package video

import (
"context"
"fmt"
"image"
"image/color"
"image/png"
"os"
"strconv"

"github.com/keep-starknet-strange/art-peace/backend/core"
)

func GenerateImageFromCanvas(orderId int) {
ctx := context.Background()

colorWidth := core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth
canvasWidth := int(core.ArtPeaceBackend.CanvasConfig.Canvas.Width)
canvasHeight := int(core.ArtPeaceBackend.CanvasConfig.Canvas.Height)

// TODO: Make generic & initialize only once
colorPalette := make([]color.RGBA, 0)
colorPaletteHex := []string{"fafafa", "080808", "ba2112", "ff403d", "ff7714", "ffd115", "f5ff05", "199f27", "00ef3f", "152665", "1542ff", "5cfffe", "a13dff", "ff7ad7", "c1d9e6", "ea1608", "1991f4", "3c3c84", "ff5c5d", "fde578", "74401b", "f86949", "46b093", "d4d7d9"}
for _, colorHex := range colorPaletteHex {
r, err := strconv.ParseInt(colorHex[0:2], 16, 64)
if err != nil {
fmt.Println("Failed to parse hex color: ", colorHex, " Error: ", err)
return
}
g, err := strconv.ParseInt(colorHex[2:4], 16, 64)
if err != nil {
fmt.Println("Failed to parse hex color: ", colorHex, " Error: ", err)
return
}
b, err := strconv.ParseInt(colorHex[4:6], 16, 64)
if err != nil {
fmt.Println("Failed to parse hex color: ", colorHex, " Error: ", err)
return
}
colorPalette = append(colorPalette, color.RGBA{uint8(r), uint8(g), uint8(b), 255})
}
generatedImage := image.NewRGBA(image.Rect(0, 0, canvasWidth, canvasHeight))
bitfieldType := "u" + strconv.Itoa(int(core.ArtPeaceBackend.CanvasConfig.ColorsBitWidth))
for y := 0; y < canvasHeight; y++ {
for x := 0; x < canvasWidth; x++ {
position := y*canvasWidth + x
pos := position * int(colorWidth)
val, err := core.ArtPeaceBackend.Databases.Redis.BitField(ctx, "canvas", "GET", bitfieldType, pos).Result()
if err != nil {
fmt.Println("Failed to get bitfield value. Error: ", err)
return
}
color := colorPalette[val[0]]
generatedImage.Set(x, y, color)
}
}

if _, err := os.Stat("images"); os.IsNotExist(err) {
err := os.Mkdir("images", os.ModePerm)
if err != nil {
fmt.Println("Failed to create images directory. Error: ", err)
return
}
}

fileName := fmt.Sprintf("images/%d.png", orderId)
f, err := os.Create(fileName)
if err != nil {
fmt.Println("Failed to create image file. Error: ", err)
return
}
defer f.Close()

if err := png.Encode(f, generatedImage); err != nil {
fmt.Println("Failed to encode image. Error: ", err)
return
}
fmt.Println("Generated image for orderId: ", orderId)
}
14 changes: 7 additions & 7 deletions configs/factions.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"id": 1,
"name": "Ducks Everywhere",
"icon": "$BACKEND_URL/faction-images/ducks-everywhere.png",
"leader": "0x07c313ea8b45044c2272b77ec7332b65bdfef089c4de0fffab3de3fd6b85d124",
"leader": "0x05bd7adfE8AfaA58300aDC72bF5584b191E236987Fe16A217b1a3e067869A0Aa",
"joinable": true,
"allocation": 1,
"links": {
Expand All @@ -20,7 +20,7 @@
"id": 2,
"name": "WASD",
"icon": "$BACKEND_URL/faction-images/wasd.png",
"leader": "0x07c313ea8b45044c2272b77ec7332b65bdfef089c4de0fffab3de3fd6b85d124",
"leader": "0x05bd7adfE8AfaA58300aDC72bF5584b191E236987Fe16A217b1a3e067869A0Aa",
"joinable": true,
"allocation": 1,
"links": {
Expand All @@ -36,7 +36,7 @@
"id": 3,
"name": "Influence",
"icon": "$BACKEND_URL/faction-images/influence.png",
"leader": "0x07c313ea8b45044c2272b77ec7332b65bdfef089c4de0fffab3de3fd6b85d124",
"leader": "0x05bd7adfE8AfaA58300aDC72bF5584b191E236987Fe16A217b1a3e067869A0Aa",
"joinable": true,
"allocation": 1,
"links": {
Expand All @@ -52,7 +52,7 @@
"id": 4,
"name": "Ark Project",
"icon": "$BACKEND_URL/faction-images/ark-project.png",
"leader": "0x07c313ea8b45044c2272b77ec7332b65bdfef089c4de0fffab3de3fd6b85d124",
"leader": "0x05bd7adfE8AfaA58300aDC72bF5584b191E236987Fe16A217b1a3e067869A0Aa",
"joinable": true,
"allocation": 1,
"links": {
Expand All @@ -68,7 +68,7 @@
"id": 5,
"name": "Everai",
"icon": "$BACKEND_URL/faction-images/everai.png",
"leader": "0x07c313ea8b45044c2272b77ec7332b65bdfef089c4de0fffab3de3fd6b85d124",
"leader": "0x05bd7adfE8AfaA58300aDC72bF5584b191E236987Fe16A217b1a3e067869A0Aa",
"joinable": true,
"allocation": 1,
"links": {
Expand All @@ -84,7 +84,7 @@
"id": 6,
"name": "2077 Collective",
"icon": "$BACKEND_URL/faction-images/2077.png",
"leader": "0x07c313ea8b45044c2272b77ec7332b65bdfef089c4de0fffab3de3fd6b85d124",
"leader": "0x05bd7adfE8AfaA58300aDC72bF5584b191E236987Fe16A217b1a3e067869A0Aa",
"joinable": true,
"allocation": 1,
"links": {
Expand All @@ -100,7 +100,7 @@
"id": 7,
"name": "Argent",
"icon": "$BACKEND_URL/faction-images/argent.png",
"leader": "0x07c313ea8b45044c2272b77ec7332b65bdfef089c4de0fffab3de3fd6b85d124",
"leader": "0x05bd7adfE8AfaA58300aDC72bF5584b191E236987Fe16A217b1a3e067869A0Aa",
"joinable": true,
"allocation": 1,
"links": {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/utils/TimerInjector.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const TimerInjector = ({ children, props, isLastDay, endTimestamp }) => {
}
const now = new Date();
let thisDayEnd = now;
console.log(props);
// TODO: isLastDay || game ended
if (isLastDay) {
thisDayEnd = new Date(endTimestamp * 1000);
} else {
Expand Down
28 changes: 28 additions & 0 deletions indexer/video-script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const config = {
streamUrl: Deno.env.get("APIBARA_STREAM_URL"),
startingBlock: 650_000,
network: "starknet",
finality: "DATA_STATUS_PENDING",
filter: {
events: [
{
// Pixel Placed Event
fromAddress: Deno.env.get("ART_PEACE_CONTRACT_ADDRESS"),
keys: [
"0x2D7B50EBF415606D77C7E7842546FC13F8ACFBFD16F7BCF2BC2D08F54114C23"
],
includeReverted: false,
includeTransaction: false,
includeReceipt: false
}
]
},
sinkType: "webhook",
sinkOptions: {
targetUrl: Deno.env.get("CONSUMER_TARGET_URL")
}
};

export default function transform(block) {
return block;
}
83 changes: 83 additions & 0 deletions infra/instructions/helm-deploy-steps.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
setup .env w/ STARKNET_KEYSTORE=$HOME/.starkli-sepolia/starkli-keystore.json
STARKNET_ACCOUNT=$HOME/.starkli-sepolia/starkli-account.json

source .env

build contracts : scarb build
deploy username store to sepolia
./tests/integration/sepolia/deploy-username-store.sh
save address
deploy art peace to sepolia
vim ./tests/integration/sepolia/deploy.sh
change start & end time
./tests/integration/sepolia/deploy.sh
save address
deploy canvas nft to sepolia
./tests/integration/sepolia/deploy-canvas-nft.sh
save address
and set in art_peace contract
deploy quests
vim ./tests/integration/sepolia/deploy_quests.sh
change art peace address, canvas contract address, username store, ...
./tests/integration/sepolia/deploy_quests.sh

setup nft contract
setup factions
vim ./tests/integration/sepolia/setup_factions.sh
change art-peace contract
./tests/integration/sepolia/setup_factions.sh

copy abis to frontend
make update-frontend-contracts

build prod docker images w/ new version & push to docker hub
Update docker version in infra/art-peace-infra/Chart.yaml if needed
Update contracts in values.yaml
commit and merge changes
make docker-build
make docker-push

apply changes to cloud
cloud console
clone / pull latest main
git clone https://github.com/keep-starknet-strange/art-peace.git
git pull origin main
cd art-peace
If full reset
make helm-uninstall
POSTGRES_PASSWORD=test AUTH_TOKEN=dna_abc make helm-install
make init-infra-prod
else
POSTGRES_PASSWORD=test AUTH_TOKEN=dna_abc make helm-upgrade

change frontend contract addresses in vercel
https://vercel.com/keep-starknet-strange/art-peace/settings
REACT_APP_STARKNET_CONTRACT_ADDRESS=
REACT_APP_USERNAME_STORE_CONTRACT_ADDRESS=
REACT_APP_CANVAS_NFT_CONTRACT_ADDRESS=
ART_PEACE_END_TIME=
ART_PEACE_HOST=


kubectl cp ../postgres/init.sql pod:/home
kubectl exec -it pod/pod-name bash
psql -U art-peace-user -d art-peace-db -f /home/init.sql
reset :
kubectl delete pvc nft-volume-claim redis-volume-claim
kubectl delete deployment.apps/backend deployment.apps/admin-backend deployment.apps/consumer deployment.apps/indexer deployment.apps/redis

setup canvas, quests, and faction backend




video:
redis-server
redis-cli del canvas
backend/video/video.go - set color palette
backend/routes/indexer/route.go - add video.GenerateImageFromCanvas(message.Data.Cursor.OrderKey) after LastFinalizedCursor = message.Data.Cursor.OrderKey
go run cmd/video-gen/video.go
curl http://localhost:8081/init-canvas
setup indexer.env for art peace contract
AUTH_TOKEN=dna_abc apibara run indexer/video-script.js --allow-env backend/video/indexer.env
render video from frames in blender
Loading

0 comments on commit 4158410

Please sign in to comment.