Skip to content

Commit 67690fe

Browse files
authored
[Performance] Updating dependencies to support crypto libraries with CGO enabled (#458)
- https://github.com/buildwithgrove/path/actions/runs/18061606609 - See this ticket for the full list of changes: pokt-network/poktroll#1793 - Improving docs, tooling, builds, etc to make this work - Adding some benchmarks as well ```bash Shannon SDK Signing Performance Comparison =========================================== Benchmark Decred Ethereum Speedup ---------------------------------------- ------------ ------------ ---------- KeyOperations 12.1μs 11.5μs 1.05x SigningDirect 1.83ms 1.02ms 1.80x CompleteSigningPipeline 1.97ms 784.1μs 2.51x ```
1 parent e391918 commit 67690fe

30 files changed

+923
-169
lines changed

.dockerignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.git
2+
**/node_modules
3+
bin
4+
*.log
5+
*.tmp
6+
**/.cache

.github/workflows/main-build.yml

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,31 @@ on:
1010
- completed
1111
branches:
1212
- main
13-
workflow_dispatch: # Added to enable manual trigger via GitHub UI
13+
workflow_dispatch: # Manual trigger
1414

1515
jobs:
1616
build-and-push:
17-
runs-on: "ubuntu-22.04"
17+
runs-on: ubuntu-22.04
1818
steps:
1919
- name: Checkout project
2020
uses: actions/checkout@v4
2121

2222
- name: Set up Go
23-
uses: actions/setup-go@v4
23+
uses: actions/setup-go@v5
2424
with:
2525
go-version: "1.24"
2626

27+
# Needed so release_build_cgo can produce arm64 artifacts on amd64 runner
28+
- name: Install cross toolchains for CGO
29+
run: |
30+
sudo apt-get update
31+
sudo apt-get install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross
32+
2733
- name: Build binaries for multiple architectures
2834
run: make release_build_cross
2935

3036
- name: Set up Docker Buildx
31-
uses: docker/setup-buildx-action@v1
37+
uses: docker/setup-buildx-action@v3
3238

3339
- name: Docker Metadata action
3440
id: meta
@@ -45,22 +51,52 @@ jobs:
4551
type=sha,format=short,suffix=-rc
4652
type=ref,event=branch,pattern=latest
4753
54+
- name: Docker Metadata action (cgo)
55+
id: meta_cgo
56+
uses: docker/metadata-action@v5
57+
env:
58+
DOCKER_METADATA_PR_HEAD_SHA: "true"
59+
with:
60+
images: |
61+
ghcr.io/buildwithgrove/path
62+
tags: |
63+
type=semver,pattern={{version}},suffix=-cgo
64+
type=semver,pattern={{major}}.{{minor}},suffix=-cgo
65+
type=ref,event=tag,suffix=-rc-cgo
66+
type=sha,format=short,suffix=-rc-cgo
67+
type=ref,event=branch,pattern=latest,suffix=-cgo
68+
4869
- name: Login to GitHub Container Registry
4970
uses: docker/login-action@v3
5071
with:
5172
registry: ghcr.io
5273
username: ${{ github.actor }}
5374
password: ${{ github.token }}
5475

76+
# Non-CGO image (multi-arch, Alpine runtime)
5577
- name: Build and push Docker image
5678
uses: docker/build-push-action@v5
5779
with:
5880
push: true
5981
tags: ${{ steps.meta.outputs.tags }}
6082
build-args: IMAGE_TAG=${{ steps.meta.outputs.version }}
61-
# Multi-arch support with pre-built binaries
6283
platforms: linux/amd64,linux/arm64
6384
file: Dockerfile.release
6485
cache-from: type=gha
6586
cache-to: type=gha,mode=max
6687
context: .
88+
89+
# CGO image (multi-arch, glibc runtime)
90+
- name: Build and push Docker image (cgo)
91+
uses: docker/build-push-action@v5
92+
with:
93+
push: true
94+
tags: ${{ steps.meta_cgo.outputs.tags }}
95+
build-args: |
96+
IMAGE_TAG=${{ steps.meta.outputs.version }}
97+
BINARY_SUFFIX=_cgo
98+
platforms: linux/amd64,linux/arm64
99+
file: Dockerfile.release.glibc
100+
cache-from: type=gha
101+
cache-to: type=gha,mode=max
102+
context: .

.github/workflows/run-lint-and-test.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,8 @@ jobs:
4343
run: |
4444
git config --global url."https://${{ github.token }}:[email protected]/".insteadOf "https://github.com/"
4545
46-
- name: Run unit tests
46+
- name: Run unit tests without CGO
4747
run: CGO_ENABLED=0 go test ./... -short
48+
49+
- name: Run unit tests with CGO
50+
run: CGO_ENABLED=1 go test -tags "ethereum_secp256k1" ./... -short

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,6 @@ install.log
7979
# Supplier Report JSON File
8080
# Generated by ./e2e/scripts/shannon-preliminary-services-test.sh
8181
supplier_report_*.json
82+
83+
# Benchmark Results
84+
bench_results

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# TODO_TECHDEBT: Consolidate Dockerfile.local and Dockerfile
12
# Builder stage
23
FROM golang:1.24-alpine3.20 AS builder
34

Dockerfile.local

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# TODO_TECHDEBT: Consolidate Dockerfile.local and Dockerfile
2+
ARG GO_VERSION=1.24-alpine
3+
4+
FROM golang:${GO_VERSION} AS builder
5+
WORKDIR /src
6+
RUN apk add --no-cache build-base git
7+
# Default: CGO enabled (musl) for Alpine runtime
8+
ENV CGO_ENABLED=1 GOOS=linux \
9+
CGO_CFLAGS="-Wno-implicit-function-declaration -Wno-error=implicit-function-declaration"
10+
11+
# Better layer caching
12+
COPY go.mod go.sum ./
13+
RUN go mod download
14+
COPY . .
15+
16+
# Build with tags (CGO enabled)
17+
RUN go build -tags "ethereum_secp256k1" -buildvcs=false -o /out/path ./cmd
18+
19+
# Optional no-CGO build (commented by default)
20+
# RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -buildvcs=false -o /out/path_nocgo ./cmd
21+
22+
FROM alpine:3.19
23+
RUN apk add --no-cache ca-certificates tzdata
24+
WORKDIR /app
25+
# Default artifact: CGO-enabled
26+
COPY --from=builder /out/path /app/path
27+
# Swap to no-CGO by uncommenting this and commenting the line above:
28+
# COPY --from=builder /out/path_nocgo /app/path
29+
ENTRYPOINT ["/app/path"]

Dockerfile.release

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
# Multi-architecture Dockerfile that uses pre-built binaries
1+
# Multi-architecture Dockerfile that uses pre-built binaries.
2+
23
# This Dockerfile expects binaries to be built beforehand using:
3-
# make release_build_cross
4+
# $ make release_build_cross
45

56
FROM alpine:3.19 AS final
67

@@ -18,9 +19,14 @@ RUN apk add --no-cache ca-certificates tzdata && \
1819
ARG IMAGE_TAG
1920
ENV IMAGE_TAG=${IMAGE_TAG}
2021

22+
# Optional suffix for selecting the CGO-enabled binary variant
23+
# Empty by default (uses CGO-disabled binary). For CGO builds, pass: _cgo
24+
# Fore more details, see .github/workflows/main-build.yml
25+
ARG BINARY_SUFFIX=""
26+
2127
# Determine the architecture and copy the appropriate binary
2228
ARG TARGETARCH
23-
COPY release/path-linux-${TARGETARCH} /app/path
29+
COPY release/path-linux-${TARGETARCH}${BINARY_SUFFIX} /app/path
2430

2531
# Set the binary as executable
2632
RUN chmod +x /app/path
@@ -29,4 +35,4 @@ RUN chmod +x /app/path
2935
USER appuser
3036

3137
# Command to run
32-
CMD ["./path"]
38+
CMD ["./path"]

Dockerfile.release.glibc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Dockerfile.release.glibc — CGO runtime (glibc)
2+
# Expects prebuilt CGO binaries at: release/path-linux-${TARGETARCH}_cgo
3+
4+
FROM gcr.io/distroless/cc-debian12 AS final
5+
WORKDIR /app
6+
7+
ARG IMAGE_TAG
8+
ENV IMAGE_TAG=${IMAGE_TAG}
9+
10+
# CGO build uses the _cgo suffix
11+
ARG TARGETARCH
12+
COPY release/path-linux-${TARGETARCH}_cgo /app/path
13+
14+
# Non-root user (distroless uses 65532 by convention)
15+
USER 65532:65532
16+
17+
CMD ["/app/path"]

Makefile

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,60 @@
44

55
# TODO(@olshansk): Remove "Shannon" and just use "Pocket".
66

7-
.PHONY: list
8-
list: ## List all make targets
9-
@${MAKE} -pRrn : -f $(MAKEFILE_LIST) 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | sort
10-
117
.PHONY: help
128
.DEFAULT_GOAL := help
139
help: ## Prints all the targets in all the Makefiles
14-
@grep -h -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-60s\033[0m %s\n", $$1, $$2}'
10+
@echo ""
11+
@echo "$(BOLD)$(CYAN)🌐 PATH (Path API & Toolkit Harness) Makefile Targets$(RESET)"
12+
@echo ""
13+
@echo "$(BOLD)=== 📋 Information & Discovery ===$(RESET)"
14+
@grep -h -E '^help:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
15+
@echo ""
16+
@echo "$(BOLD)=== 🔨 Build & Run ===$(RESET)"
17+
@grep -h -E '^path_(build|run):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
18+
@echo ""
19+
@echo "$(BOLD)=== ⚙️ Configuration ===$(RESET)"
20+
@grep -h -E '^config.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
21+
@echo ""
22+
@echo "$(BOLD)=== 🛠️ Development Environment ===$(RESET)"
23+
@grep -h -E '^(path_up|path_down|install_tools.*|localnet_.*):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
24+
@echo ""
25+
@echo "$(BOLD)=== 🚀 Load Testing ===$(RESET)"
26+
@grep -h -E '^load_test.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
27+
@echo ""
28+
@echo "$(BOLD)=== 🧪 Testing ===$(RESET)"
29+
@grep -h -E '^(test_unit|test_all|go_lint):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
30+
@grep -h -E '^e2e_test.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
31+
@echo ""
32+
@echo "$(BOLD)=== ⚡ Benchmarking ===$(RESET)"
33+
@grep -h -E '^bench.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
34+
@echo ""
35+
@echo "$(BOLD)=== ✋ Manual Testing ===$(RESET)"
36+
@grep -h -E '^(get_disqualified_endpoints|grove_get_disqualified_endpoints|shannon_preliminary_services_test_help|shannon_preliminary_services_test|source_shannon_preliminary_services_helpers):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
37+
@echo ""
38+
@echo "$(BOLD)=== 🗄️ Portal Database ===$(RESET)"
39+
@grep -h -E '^portal_db.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
40+
@echo ""
41+
@echo "$(BOLD)=== 📦 Protocol Buffers ===$(RESET)"
42+
@grep -h -E '^proto.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
43+
@echo ""
44+
@echo "$(BOLD)=== 🚢 Release Management ===$(RESET)"
45+
@grep -h -E '^release_.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
46+
@echo ""
47+
@echo "$(BOLD)=== 🔧 Utilities ===$(RESET)"
48+
@echo ""
49+
@echo "$(BOLD)=== 📚 Documentation ===$(RESET)"
50+
@grep -h -E '^(go_docs|docusaurus.*|gen_.*_docs):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
51+
@echo ""
52+
@echo "$(BOLD)=== 🔍 Request Testing ===$(RESET)"
53+
@grep -h -E '^test_(request|healthz|disqualified|load).*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
54+
@echo ""
55+
@echo "$(BOLD)=== ⚡ Benchmarking ===$(RESET)"
56+
@grep -h -E '^bench_.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
57+
@echo ""
58+
@echo "$(BOLD)=== 🤖 AI ===$(RESET)"
59+
@grep -h -E '^claudesync.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
60+
@echo ""
1561

1662
#############################
1763
#### PATH Build Targets ###
@@ -60,10 +106,11 @@ include ./makefiles/docs.mk
60106
include ./makefiles/localnet.mk
61107
include ./makefiles/portal-db.mk
62108
include ./makefiles/test.mk
109+
include ./makefiles/bench.mk
63110
include ./makefiles/test_requests.mk
64111
include ./makefiles/test_load.mk
65112
include ./makefiles/proto.mk
66113
include ./makefiles/debug.mk
67114
include ./makefiles/claude.mk
68115
include ./makefiles/release.mk
69-
include ./makefiles/helpers.mk
116+
include ./makefiles/helpers.mk

Tiltfile

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,20 @@ hot_reload_dirs = [
1717
"./local/observability",
1818
"./cmd",
1919
"./config",
20+
"./data",
2021
"./gateway",
2122
"./health",
23+
"./log",
2224
"./message",
25+
"./metrics",
26+
"./network",
27+
"./observation",
28+
"./protocol",
29+
"./proto",
2330
"./qos",
2431
"./relayer",
2532
"./request",
2633
"./router",
27-
"./protocol",
28-
"./metrics",
29-
"./observation",
30-
"./proto",
3134
"./websockets",
3235
]
3336

@@ -133,50 +136,15 @@ local_resource(
133136
# 3. WATCH (Workload Analytics and Telemetry for Comprehensive Health): Observability #
134137
# ----------------------------------------------------------------------------------- #
135138

136-
# TODO_TECHDEBT(@adshmh): use secrets for sensitive data with the following steps:
137-
# 1. Add place-holder files for sensitive data
138-
# 2. Add a secret per sensitive data item (e.g. gateway's private key)
139-
# 3. Load the secrets into environment variables of an init container
140-
# 4. Use an init container to run the scripts for updating config from environment variables.
141-
# This can leverage the scripts under `e2e` package to be consistent with the CI workflow.
142-
143-
# Compile the binary inside the container
144-
local_resource(
145-
'path-binary',
146-
'''
147-
echo "Building Go binary..."
148-
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -buildvcs=false -o bin/path ./cmd
149-
''',
150-
deps=hot_reload_dirs,
151-
ignore=['**/node_modules', '.git'],
152-
labels=["hot-reloading"],
153-
)
154-
155-
# Build a minimal Docker image with just the binary
156-
docker_build_with_restart(
139+
# TODO_TECHDEBT: Consolidate Dockerfile.local and Dockerfile
140+
# Build the PATH image using Dockerfile.local (which handles CGO_ENABLED=1)
141+
# Include go.mod and go.sum in the build context along with hot_reload_dirs
142+
build_context_files = hot_reload_dirs + ["./go.mod", "./go.sum", "./Dockerfile.local"]
143+
docker_build(
157144
"path-image",
158145
context=".",
159-
dockerfile_contents="""FROM alpine:3.19
160-
RUN apk add --no-cache ca-certificates tzdata
161-
WORKDIR /app
162-
COPY bin/path /app/path
163-
RUN chmod +x /app/path
164-
""",
165-
only=["bin/path"],
166-
entrypoint=["/app/path"],
167-
live_update=[
168-
sync("bin/path", "/app/path"),
169-
],
170-
)
171-
172-
# Ensure the binary is built before the image
173-
local_resource(
174-
"path-trigger",
175-
"touch bin/path",
176-
resource_deps=["path-binary"],
177-
auto_init=False,
178-
trigger_mode=TRIGGER_MODE_AUTO,
179-
labels=["hot-reloading"],
146+
dockerfile="Dockerfile.local",
147+
only=build_context_files, # Only rebuild the image when these files/directories change
180148
)
181149

182150
# Tilt will run the Helm Chart with the following flags by default.

0 commit comments

Comments
 (0)