Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fcfc468
Ethereum Oracle
ezeike Jul 23, 2025
52bb640
Increased max net address length
ezeike Dec 13, 2025
20c85e7
🐛 fix: add embed directives and respect wss scheme for secure connect…
ezeike Dec 17, 2025
0b0b965
🔊 feat: format oracle log output with hex-encoded byte fields
ezeike Dec 17, 2025
002c8c6
Optimized Dockerfile
ezeike Dec 17, 2025
7ab9629
🔊 feat: add logging for websocket connection lifecycle events
ezeike Dec 19, 2025
7b6de96
📈 feat: add comprehensive oracle metrics for observability
ezeike Dec 19, 2025
4daed67
📈 feat: add comprehensive Eth block provider metrics
ezeike Dec 19, 2025
294c34f
📈 feat: add block height metrics to eth block provider
ezeike Dec 19, 2025
1c88a00
📝 docs: add comprehensive oracle metrics documentation
ezeike Dec 19, 2025
5e62965
🎨 style: fix formatting and trailing newlines
ezeike Dec 19, 2025
9d1385b
Oracle nil fix
ezeike Dec 22, 2025
0e107d5
log updates
ezeike Dec 22, 2025
dacf6c8
🔊 feat: promote safe height check log to info level
ezeike Dec 22, 2025
5edc4f5
Logging updates
ezeike Dec 23, 2025
7b70e16
log updates
ezeike Dec 23, 2025
ac8f7cf
🔊 feat: improve order hold logging with specific reasons at info level
ezeike Dec 23, 2025
13f0204
git diff cleanup
andrewnguyen22 Dec 25, 2025
a0640fd
patch for warning
andrewnguyen22 Dec 25, 2025
ac6a5d5
🚚 refactor: rename CanopyOrders endpoint to OracleOrders
ezeike Jan 3, 2026
a149dcc
Merge branch 'main' into eth-oracle
andrewnguyen22 Feb 8, 2026
1c507c0
Merge pull request #298 from canopy-network/main
andrewnguyen22 Feb 9, 2026
28ad8b7
fix: set missing sell order fields in MultiTokenSupport test
andrewnguyen22 Feb 10, 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,49 +1,61 @@
{
"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",
"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",
"gossipThreshold": 0,
"headless": false,
"inMemory": false,
"networkID": 1,
"individualMaxTxSize": 4000,
"listenAddress": "0.0.0.0:9001",
"externalAddress": "node-1",
"logLevel": "debug",
"maxInbound": 21,
"maxOutbound": 7,
"trustedPeerIDs": null,
"dialPeers": [],
"bannedPeerIDs": null,
"bannedIPs": null,
"gossipThreshold": 0,
"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