Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6aae023
Ethereum Oracle
ezeike Jul 23, 2025
b51ec58
Increased max net address length
ezeike Dec 13, 2025
7a718bb
🐛 fix: add embed directives and respect wss scheme for secure connect…
ezeike Dec 17, 2025
31b74d2
🔊 feat: format oracle log output with hex-encoded byte fields
ezeike Dec 17, 2025
b2b106a
Optimized Dockerfile
ezeike Dec 17, 2025
b1bf557
🔊 feat: add logging for websocket connection lifecycle events
ezeike Dec 19, 2025
d2da83b
📈 feat: add comprehensive oracle metrics for observability
ezeike Dec 19, 2025
1de71ce
📈 feat: add comprehensive Eth block provider metrics
ezeike Dec 19, 2025
11dcdc2
📈 feat: add block height metrics to eth block provider
ezeike Dec 19, 2025
13a8a1d
📝 docs: add comprehensive oracle metrics documentation
ezeike Dec 19, 2025
b9b4ce1
🎨 style: fix formatting and trailing newlines
ezeike Dec 19, 2025
8d88523
Oracle nil fix
ezeike Dec 22, 2025
e68b38c
log updates
ezeike Dec 22, 2025
b4f03cd
🔊 feat: promote safe height check log to info level
ezeike Dec 22, 2025
5b1aa4b
Logging updates
ezeike Dec 23, 2025
5c84034
log updates
ezeike Dec 23, 2025
c8b3934
🔊 feat: improve order hold logging with specific reasons at info level
ezeike Dec 23, 2025
b6d7713
git diff cleanup
andrewnguyen22 Dec 25, 2025
a105c13
patch for warning
andrewnguyen22 Dec 25, 2025
c65e164
🚚 refactor: rename CanopyOrders endpoint to OracleOrders
ezeike Jan 3, 2026
9ba30c5
✨ feat: add indexer-snapshot endpoint for aggregated block data
ezeike Jan 6, 2026
6a6b847
✨ feat: add IndexerSnapshot WebSocket support for RCManager
ezeike Jan 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions .docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
FROM golang:1.24-alpine AS builder
FROM golang:1.24.0-alpine AS builder

RUN apk update && apk add --no-cache make bash nodejs npm
run apk update && apk add --no-cache make bash nodejs npm

ARG EXPLORER_BASE_PATH
ARG WALLET_BASE_PATH

WORKDIR /go/src/github.com/canopy-network/canopy
COPY . /go/src/github.com/canopy-network/canopy

RUN make build/wallet
RUN make build/explorer
ENV EXPLORER_BASE_PATH=${EXPLORER_BASE_PATH}
ENV WALLET_BASE_PATH=${WALLET_BASE_PATH}

#RUN make build/wallet
#RUN make build/explorer
RUN go build -a -o bin ./cmd/main/...

FROM alpine:3.19
WORKDIR /app
COPY --from=builder /go/src/github.com/canopy-network/canopy/bin ./
ENTRYPOINT ["/app/bin"]
from alpine:3.19
workdir /app
copy --from=builder /go/src/github.com/canopy-network/canopy/bin ./
entrypoint ["/app/bin"]
78 changes: 78 additions & 0 deletions .docker/Dockerfile.optimized
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# syntax=docker/dockerfile:1

FROM golang:1.24.0-alpine AS builder

# Install build dependencies
RUN apk update && apk add --no-cache make bash nodejs npm git

ARG EXPLORER_BASE_PATH
ARG WALLET_BASE_PATH

WORKDIR /go/src/github.com/canopy-network/canopy

# ============================================
# OPTIMIZATION 1: Cache Go module dependencies
# Copy only go.mod and go.sum first to cache dependencies layer
# This layer only invalidates when dependencies change
# ============================================
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download

# ============================================
# OPTIMIZATION 2: Cache NPM dependencies for wallet
# Copy only package.json files first to cache npm install layer
# ============================================
COPY cmd/rpc/web/wallet/package*.json ./cmd/rpc/web/wallet/
RUN --mount=type=cache,target=/root/.npm \
npm install --prefix ./cmd/rpc/web/wallet

# ============================================
# OPTIMIZATION 3: Cache NPM dependencies for explorer
# ============================================
COPY cmd/rpc/web/explorer/package*.json ./cmd/rpc/web/explorer/
RUN --mount=type=cache,target=/root/.npm \
npm install --prefix ./cmd/rpc/web/explorer

# ============================================
# OPTIMIZATION 4: Copy web source and build BEFORE copying all source
# This caches web builds - only invalidates when web files change
# ============================================
COPY cmd/rpc/web/wallet/ ./cmd/rpc/web/wallet/
COPY cmd/rpc/web/explorer/ ./cmd/rpc/web/explorer/

ENV EXPLORER_BASE_PATH=${EXPLORER_BASE_PATH}
ENV WALLET_BASE_PATH=${WALLET_BASE_PATH}

# Build web assets (cached unless web source changes)
RUN --mount=type=cache,target=/root/.npm \
npm run build --prefix ./cmd/rpc/web/wallet
RUN --mount=type=cache,target=/root/.npm \
npm run build --prefix ./cmd/rpc/web/explorer

# ============================================
# OPTIMIZATION 5: Copy remaining source code
# Web builds are already cached above
# ============================================
COPY . .

# ============================================
# OPTIMIZATION 6: Use build cache mounts for Go
# Preserves Go build cache and module cache between builds
# This can speed up rebuilds by 5-10x
# ============================================
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
go build -a -o bin ./cmd/main/...

# ============================================
# Final stage - minimal runtime image
# ============================================
FROM alpine:3.19

WORKDIR /app

# Copy only the built binary (web assets are embedded)
COPY --from=builder /go/src/github.com/canopy-network/canopy/bin ./bin

ENTRYPOINT ["/app/bin"]
90 changes: 59 additions & 31 deletions .docker/compose.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,32 @@
services:
anvil:
image: ghcr.io/foundry-rs/foundry:latest
container_name: anvil
ports:
- 8545:8545
networks:
- canopy
entrypoint: ["anvil", "-vvv", "--host", "0.0.0.0", "--block-time", "2", "--port", "8545"]
volumes:
- ./anvil:/anvil
healthcheck:
test: ["CMD", "cast", "block-number", "--rpc-url", "http://localhost:8545"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
anvil-init:
image: ghcr.io/foundry-rs/foundry:latest
container_name: anvil-init
user: "0"
networks:
- canopy
depends_on:
- anvil
entrypoint: ["/anvil/anvil.sh"]
volumes:
- ./anvil:/anvil
working_dir: /anvil
node-1:
container_name: node-1
build:
Expand All @@ -22,7 +50,6 @@ services:
# limits:
# memory: 2G
# cpus: "1.0"

node-2:
container_name: node-2
build:
Expand All @@ -33,43 +60,44 @@ services:
- 40001:40001 # Explorer
- 40002:40002 # RPC
- 40003:40003 # Admin RPC
- 9002:9002 # TCP P2P
- 9003:9003 # TCP P2P
- 6061:6060 # Debug
- 9091:9091 # Metrics
networks:
- canopy
command: ["start"]
volumes:
- ./volumes/node_2:/root/.canopy
# deploy:
# resources:
# limits:
# memory: 2G
# cpus: "1.0"
# node-3:
# container_name: node-3
# build:
# context: ..
# dockerfile: .docker/Dockerfile
# args:
# BUILD_PATH: cmd/cli
# ports:
# - 30000:30000 # Wallet
# - 30001:30001 # Explorer
# - 30002:30002 # RPC
# - 30003:30003 # Admin RPC
# - 9003:9003 # TCP P2P
# networks:
# - canopy
# command: ["start"]
# volumes:
# - ./volumes/node_3:/root/.canopy
# deploy:
# resources:
# limits:
# memory: 2G
# cpus: "1.0"
# deploy:
# resources:
# limits:
# memory: 1G
# cpus: "1.0"
# node-3:
# container_name: node-3
# build:
# context: ..
# dockerfile: .docker/Dockerfile
# args:
# EXPLORER_BASE_PATH: ""
# WALLET_BASE_PATH: ""
# ports:
# - 30000:30000 # Wallet
# - 30001:30001 # Explorer
# - 30002:30002 # RPC
# - 30003:30003 # Admin RPC
# - 9003:9003 # TCP P2P
# networks:
# - canopy
# command: ["start"]
# volumes:
# - ./volumes/node_3:/root/.canopy
# deploy:
# resources:
# limits:
# memory: 2G
# cpus: "1.0"

networks:
canopy:
driver: bridge
driver: bridge
71 changes: 71 additions & 0 deletions .docker/oracle-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
services:
node-1:
container_name: node-1
image: canopy-node:latest
ports:
- 50000:50000 # Wallet
- 50001:50001 # Explorer
- 50002:50002 # RPC
- 50003:50003 # Admin RPC
- 9001:9001 # TCP P2P
- 6060:6060 # Debug
- 9090:9090 # Metrics
networks:
- canopy
command: ["start"]
volumes:
- ./volumes/node_1:/root/.canopy
# deploy:
# resources:
# limits:
# memory: 2G
# cpus: "1.0"
node-2:
container_name: node-2
image: canopy-node:latest
ports:
- 40000:40000 # Wallet
- 40001:40001 # Explorer
- 40002:40002 # RPC
- 40003:40003 # Admin RPC
- 9003:9003 # TCP P2P
- 6061:6060 # Debug
- 9091:9091 # Metrics
networks:
- canopy
command: ["start"]
volumes:
- ./volumes/node_2:/root/.canopy
# deploy:
# resources:
# limits:
# memory: 1G
# cpus: "1.0"
# node-3:
# container_name: node-3
# build:
# context: ..
# dockerfile: .docker/Dockerfile
# args:
# EXPLORER_BASE_PATH: ""
# WALLET_BASE_PATH: ""
# ports:
# - 30000:30000 # Wallet
# - 30001:30001 # Explorer
# - 30002:30002 # RPC
# - 30003:30003 # Admin RPC
# - 9003:9003 # TCP P2P
# networks:
# - canopy
# command: ["start"]
# volumes:
# - ./volumes/node_3:/root/.canopy
# deploy:
# resources:
# limits:
# memory: 2G
# cpus: "1.0"

networks:
canopy:
driver: bridge
82 changes: 47 additions & 35 deletions .docker/volumes/node_1/config.json
Original file line number Diff line number Diff line change
@@ -1,48 +1,60 @@
{
"logLevel": "debug",
"chainId": 1,
"sleepUntil": 0,
"rootChain": [
{
"chainId": 1,
"url": "http://node-1:50002"
}
],
"runVDF": false,
"headless": false,
"walletPort": "50000",
"explorerPort": "50001",
"rpcPort": "50002",
"adminPort": "50003",
"rpcURL": "http://localhost:50002",
"adminRPCUrl": "http://localhost:50003",
"timeoutS": 3,
"adminRPCUrl": "http://node-1:50003",
"bannedIPs": null,
"bannedPeerIDs": null,
"chainId": 1,
"commitTimeoutMS": 2000,
"dataDirPath": "/root/.canopy",
"dbName": "canopy",
"inMemory": false,
"networkID": 1,
"listenAddress": "0.0.0.0:9001",
"dialPeers": [],
"dropPercentage": 35,
"electionTimeoutMS": 1500,
"electionVoteTimeoutMS": 1500,
"ethBlockProviderConfig": {
"ethChainId": 1,
"ethNodeUrl": "http://anvil:8545",
"ethNodeWsUrl": "ws://anvil:8545",
"retryDelay": 5,
"safeBlockConfirmations": 5
},
"explorerPort": "50001",
"externalAddress": "node-1",
"headless": false,
"inMemory": false,
"individualMaxTxSize": 4000,
"listenAddress": "127.0.0.101:9001",
"logLevel": "debug",
"maxInbound": 21,
"maxOutbound": 7,
"trustedPeerIDs": null,
"dialPeers": [],
"bannedPeerIDs": null,
"bannedIPs": null,
"maxTotalBytes": 1000000,
"maxTransactionCount": 5000,
"metricsEnabled": true,
"minimumPeersToStart": 0,
"networkID": 1,
"newHeightTimeoutMS": 4500,
"electionTimeoutMS": 1500,
"electionVoteTimeoutMS": 1500,
"proposeTimeoutMS": 2500,
"proposeVoteTimeoutMS": 4000,
"oracleConfig": {
"committee": 2,
"orderResubmitDelay": 1,
"stateSaveFile": "last_block_height.txt"
},
"precommitTimeoutMS": 2000,
"precommitVoteTimeoutMS": 2000,
"commitTimeoutMS": 2000,
"prometheusAddress": "0.0.0.0:9090",
"proposeTimeoutMS": 2500,
"proposeVoteTimeoutMS": 4000,
"rootChain": [
{
"chainId": 1,
"url": "http://node-1:50002"
}
],
"roundInterruptTimeoutMS": 2000,
"maxTotalBytes": 1000000,
"maxTransactionCount": 5000,
"individualMaxTxSize": 4000,
"dropPercentage": 35,
"metricsEnabled": true,
"prometheusAddress": "0.0.0.0:9090"
"rpcPort": "50002",
"rpcURL": "http://node-1:50002",
"runVDF": true,
"sleepUntil": 0,
"timeoutS": 3,
"trustedPeerIDs": null,
"walletPort": "50000"
}
Loading
Loading