Skip to content

Commit 9c8bc35

Browse files
authored
feat: add Fhenix FHE devcontainers with embedded LocalFhenix (#15)
Add multi-stage Dockerfiles that extract and flatten LocalFhenix components from ghcr.io/fhenixprotocol/fhenix-devnet:0.1.6 into our foundry base image. No Docker-in-Docker required. Components extracted: - evmosd: FHE-enabled Evmos daemon (EVM node) - zbc-oracle-db: FHE Oracle database - zbc-fhe-tool: FHE tooling - faucet.js: Faucet server (port 6000) - encryption_server.py: Python encryption service Two variants: - fhenix-hardhat: Hardhat + Fhenix plugins + embedded LocalFhenix - fhenix-foundry: Foundry + cofhe-foundry-mocks + embedded LocalFhenix
1 parent 5dc28e6 commit 9c8bc35

2 files changed

Lines changed: 339 additions & 0 deletions

File tree

infra/fhenix-foundry.Dockerfile

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# Fhenix Foundry Development Container
2+
# Multi-stage build: extracts LocalFhenix components and combines with Foundry tooling
3+
4+
# Stage 1: Extract components from Fhenix devnet image
5+
FROM ghcr.io/fhenixprotocol/fhenix-devnet:0.1.6 AS fhenix-source
6+
7+
# Stage 2: Build on foundry base with all Fhenix components
8+
FROM foundry:latest
9+
10+
ENV FHENIX_HOME=/opt/fhenix \
11+
EVMOSD_HOME=/root/.evmosd \
12+
FHENIX_RPC_PORT=8545 \
13+
FHENIX_FAUCET_PORT=6000 \
14+
FHENIX_CHAIN_ID=evmos_5432-1 \
15+
FHENIX_HELIUM_RPC=https://api.helium.fhenix.zone \
16+
PATH=/opt/fhenix/bin:$PATH
17+
18+
USER root
19+
20+
# Install runtime dependencies for Fhenix services
21+
RUN apt-get update && \
22+
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
23+
python3 python3-pip jq && \
24+
rm -rf /var/lib/apt/lists/*
25+
26+
# Create directory structure
27+
RUN mkdir -p /opt/fhenix/bin /opt/fhenix/config /opt/fhenix/scripts /res/ct
28+
29+
# Copy Fhenix binaries from source image
30+
COPY --from=fhenix-source /usr/bin/evmosd /opt/fhenix/bin/evmosd
31+
COPY --from=fhenix-source /zbc-fhe-tool /opt/fhenix/bin/zbc-fhe-tool
32+
COPY --from=fhenix-source /zbc-oracle-db /opt/fhenix/bin/zbc-oracle-db
33+
34+
# Copy Fhenix scripts and configs
35+
COPY --from=fhenix-source /run.sh /opt/fhenix/scripts/run-localfhenix.sh
36+
COPY --from=fhenix-source /faucet.js /opt/fhenix/scripts/faucet.js
37+
COPY --from=fhenix-source /encryption_server.py /opt/fhenix/scripts/encryption_server.py
38+
COPY --from=fhenix-source /requirements.txt /opt/fhenix/requirements.txt
39+
COPY --from=fhenix-source /Rocket.toml /opt/fhenix/Rocket.toml
40+
COPY --from=fhenix-source /config/ /opt/fhenix/config/
41+
42+
# Copy pre-configured evmosd home directory
43+
COPY --from=fhenix-source /root/.evmosd /root/.evmosd
44+
45+
# Install Python dependencies for encryption server
46+
RUN pip3 install --no-cache-dir --break-system-packages -r /opt/fhenix/requirements.txt || \
47+
pip3 install --no-cache-dir --break-system-packages flask || true
48+
49+
# Create unified startup script
50+
RUN echo '#!/bin/bash\n\
51+
set -e\n\
52+
CHAIN_ID=${FHENIX_CHAIN_ID:-"evmos_5432-1"}\n\
53+
\n\
54+
echo "=== Starting LocalFhenix ===" \n\
55+
echo "Chain ID: $CHAIN_ID"\n\
56+
echo "RPC Port: $FHENIX_RPC_PORT"\n\
57+
echo "Faucet Port: $FHENIX_FAUCET_PORT"\n\
58+
echo ""\n\
59+
\n\
60+
mkdir -p /res/ct\n\
61+
\n\
62+
# Start FHE Oracle DB\n\
63+
echo "Starting FHE Oracle DB..."\n\
64+
/opt/fhenix/bin/zbc-oracle-db &\n\
65+
\n\
66+
# Start Faucet\n\
67+
echo "Starting Faucet on port $FHENIX_FAUCET_PORT..."\n\
68+
cd /opt/fhenix/scripts && node faucet.js &\n\
69+
\n\
70+
# Start Encryption Server\n\
71+
echo "Starting Encryption Server..."\n\
72+
cd /opt/fhenix/scripts && python3 encryption_server.py &\n\
73+
\n\
74+
# Configure evmosd\n\
75+
/opt/fhenix/bin/evmosd config output json\n\
76+
/opt/fhenix/bin/evmosd config chain-id $CHAIN_ID\n\
77+
\n\
78+
# Start evmosd\n\
79+
echo "Starting Evmos daemon with FHE support..."\n\
80+
/opt/fhenix/bin/evmosd start \\\n\
81+
--chain-id $CHAIN_ID \\\n\
82+
--home /root/.evmosd \\\n\
83+
--minimum-gas-prices=0.000000000000000001aevmos \\\n\
84+
--json-rpc.gas-cap=9999999999999999 \\\n\
85+
--gas-prices=0.00000000000000000000000000000000001aevmos \\\n\
86+
--json-rpc.api eth,txpool,personal,net,debug,web3\n\
87+
' > /opt/fhenix/scripts/start-localfhenix.sh && chmod +x /opt/fhenix/scripts/start-localfhenix.sh
88+
89+
# Create project initialization and info scripts
90+
RUN mkdir -p /home/project/.fhenix-foundry/scripts && \
91+
echo '#!/bin/bash\n\
92+
echo "=== Fhenix Foundry Project Setup ==="\n\
93+
echo ""\n\
94+
if [ -f foundry.toml ]; then\n\
95+
echo "Foundry project already initialized"\n\
96+
else\n\
97+
forge init . --no-commit\n\
98+
echo "Foundry project created"\n\
99+
fi\n\
100+
echo ""\n\
101+
echo "Installing Fhenix dependencies..."\n\
102+
forge install fhenixprotocol/fhenix-contracts --no-commit 2>/dev/null || echo "fhenix-contracts may already be installed"\n\
103+
forge install fhenixprotocol/cofhe-foundry-mocks --no-commit 2>/dev/null || echo "cofhe-foundry-mocks may already be installed"\n\
104+
forge install openzeppelin/openzeppelin-contracts --no-commit 2>/dev/null || echo "openzeppelin already installed"\n\
105+
echo ""\n\
106+
echo "Add these remappings to remappings.txt:"\n\
107+
echo "@fhenixprotocol/contracts/=lib/fhenix-contracts/contracts/"\n\
108+
echo "@fhenixprotocol/cofhe-foundry-mocks/=lib/cofhe-foundry-mocks/src/"\n\
109+
echo "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/"\n\
110+
echo ""\n\
111+
echo "Done! See /home/project/.fhenix-foundry/scripts/show-info.sh for FHE development tips"\n\
112+
' > /home/project/.fhenix-foundry/init-project.sh && \
113+
echo '#!/bin/bash\n\
114+
echo "=== Fhenix Foundry Development Environment ==="\n\
115+
echo ""\n\
116+
echo "LocalFhenix is bundled in this container - no Docker-in-Docker required!"\n\
117+
echo ""\n\
118+
echo "=== Start LocalFhenix ==="\n\
119+
echo " /opt/fhenix/scripts/start-localfhenix.sh"\n\
120+
echo ""\n\
121+
echo "=== Endpoints (after starting) ==="\n\
122+
echo " RPC: http://127.0.0.1:8545"\n\
123+
echo " Faucet: curl http://127.0.0.1:6000/faucet?address=YOUR_ADDRESS"\n\
124+
echo ""\n\
125+
echo "=== Testing FHE Contracts ==="\n\
126+
echo "The cofhe-foundry-mocks package provides mock FHE operations"\n\
127+
echo "that simulate encryption without actual FHE computation."\n\
128+
echo ""\n\
129+
echo "Example test contract:"\n\
130+
echo ""\n\
131+
echo " import {CoFheTest} from \"@fhenixprotocol/cofhe-foundry-mocks/CoFheTest.sol\";"\n\
132+
echo " import {FHE, euint32} from \"@fhenixprotocol/contracts/FHE.sol\";"\n\
133+
echo ""\n\
134+
echo " contract MyTest is CoFheTest {"\n\
135+
echo " function testEncryptedAdd() public {"\n\
136+
echo " euint32 a = FHE.asEuint32(10);"\n\
137+
echo " euint32 b = FHE.asEuint32(20);"\n\
138+
echo " euint32 result = FHE.add(a, b);"\n\
139+
echo " assertEq(FHE.decrypt(result), 30);"\n\
140+
echo " }"\n\
141+
echo " }"\n\
142+
echo ""\n\
143+
echo "=== Encrypted Types ==="\n\
144+
echo " euint8, euint16, euint32, euint64, euint128, euint256"\n\
145+
echo " ebool, eaddress"\n\
146+
echo ""\n\
147+
echo "=== FHE Operations ==="\n\
148+
echo " FHE.asEuint*() - Encrypt plaintext values"\n\
149+
echo " FHE.add(), FHE.sub(), FHE.mul() - Arithmetic"\n\
150+
echo " FHE.and(), FHE.or(), FHE.xor() - Bitwise"\n\
151+
echo " FHE.eq(), FHE.ne(), FHE.lt(), FHE.gt() - Comparisons"\n\
152+
echo " FHE.select() - Conditional selection"\n\
153+
echo " FHE.decrypt() - Reveal encrypted value"\n\
154+
echo ""\n\
155+
echo "=== Deployment ==="\n\
156+
echo " Local: forge script script/Deploy.s.sol --rpc-url http://127.0.0.1:8545 --broadcast"\n\
157+
echo " Testnet: forge script script/Deploy.s.sol --rpc-url \$FHENIX_HELIUM_RPC --broadcast"\n\
158+
echo ""\n\
159+
echo "=== Notes ==="\n\
160+
echo " 1. Mock operations do NOT reflect real FHE gas costs"\n\
161+
echo " 2. Security zones are not enforced in mocks"\n\
162+
echo " 3. Use LocalFhenix for integration testing with real FHE"\n\
163+
echo ""\n\
164+
echo "=== Docs ==="\n\
165+
echo " https://docs.fhenix.zone"\n\
166+
echo " https://github.com/FhenixProtocol/fhenix-foundry-template"\n\
167+
echo " https://github.com/FhenixProtocol/cofhe-foundry-mocks"\n\
168+
' > /home/project/.fhenix-foundry/scripts/show-info.sh && \
169+
chmod +x /home/project/.fhenix-foundry/*.sh /home/project/.fhenix-foundry/scripts/*.sh && \
170+
ln -s /opt/fhenix/scripts/start-localfhenix.sh /home/project/.fhenix-foundry/start-localfhenix.sh && \
171+
chown -R project:project /home/project/.fhenix-foundry
172+
173+
# Install minimal npm packages for Fhenix JS SDK
174+
RUN npm install -g fhenixjs ethers viem
175+
176+
# Pre-warm npm cache
177+
RUN npm cache add fhenixjs@latest @openzeppelin/contracts@latest
178+
179+
USER project
180+
181+
LABEL description="Fhenix Foundry development with embedded LocalFhenix (no Docker-in-Docker required)"

infra/fhenix-hardhat.Dockerfile

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Fhenix Hardhat Development Container
2+
# Multi-stage build: extracts LocalFhenix components and combines with Foundry + Hardhat tooling
3+
4+
# Stage 1: Extract components from Fhenix devnet image
5+
FROM ghcr.io/fhenixprotocol/fhenix-devnet:0.1.6 AS fhenix-source
6+
7+
# Stage 2: Build on foundry base with all Fhenix components
8+
FROM foundry:latest
9+
10+
ENV FHENIX_HOME=/opt/fhenix \
11+
EVMOSD_HOME=/root/.evmosd \
12+
FHENIX_RPC_PORT=8545 \
13+
FHENIX_FAUCET_PORT=6000 \
14+
FHENIX_CHAIN_ID=evmos_5432-1 \
15+
FHENIX_HELIUM_RPC=https://api.helium.fhenix.zone \
16+
PATH=/opt/fhenix/bin:$PATH
17+
18+
USER root
19+
20+
# Install runtime dependencies for Fhenix services
21+
RUN apt-get update && \
22+
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
23+
python3 python3-pip jq && \
24+
rm -rf /var/lib/apt/lists/*
25+
26+
# Create directory structure
27+
RUN mkdir -p /opt/fhenix/bin /opt/fhenix/config /opt/fhenix/scripts /res/ct
28+
29+
# Copy Fhenix binaries from source image
30+
COPY --from=fhenix-source /usr/bin/evmosd /opt/fhenix/bin/evmosd
31+
COPY --from=fhenix-source /zbc-fhe-tool /opt/fhenix/bin/zbc-fhe-tool
32+
COPY --from=fhenix-source /zbc-oracle-db /opt/fhenix/bin/zbc-oracle-db
33+
34+
# Copy Fhenix scripts and configs
35+
COPY --from=fhenix-source /run.sh /opt/fhenix/scripts/run-localfhenix.sh
36+
COPY --from=fhenix-source /faucet.js /opt/fhenix/scripts/faucet.js
37+
COPY --from=fhenix-source /encryption_server.py /opt/fhenix/scripts/encryption_server.py
38+
COPY --from=fhenix-source /requirements.txt /opt/fhenix/requirements.txt
39+
COPY --from=fhenix-source /Rocket.toml /opt/fhenix/Rocket.toml
40+
COPY --from=fhenix-source /config/ /opt/fhenix/config/
41+
42+
# Copy pre-configured evmosd home directory
43+
COPY --from=fhenix-source /root/.evmosd /root/.evmosd
44+
45+
# Install Python dependencies for encryption server
46+
RUN pip3 install --no-cache-dir --break-system-packages -r /opt/fhenix/requirements.txt || \
47+
pip3 install --no-cache-dir --break-system-packages flask || true
48+
49+
# Create unified startup script
50+
RUN echo '#!/bin/bash\n\
51+
set -e\n\
52+
CHAIN_ID=${FHENIX_CHAIN_ID:-"evmos_5432-1"}\n\
53+
\n\
54+
echo "=== Starting LocalFhenix ===" \n\
55+
echo "Chain ID: $CHAIN_ID"\n\
56+
echo "RPC Port: $FHENIX_RPC_PORT"\n\
57+
echo "Faucet Port: $FHENIX_FAUCET_PORT"\n\
58+
echo ""\n\
59+
\n\
60+
mkdir -p /res/ct\n\
61+
\n\
62+
# Start FHE Oracle DB\n\
63+
echo "Starting FHE Oracle DB..."\n\
64+
/opt/fhenix/bin/zbc-oracle-db &\n\
65+
\n\
66+
# Start Faucet\n\
67+
echo "Starting Faucet on port $FHENIX_FAUCET_PORT..."\n\
68+
cd /opt/fhenix/scripts && node faucet.js &\n\
69+
\n\
70+
# Start Encryption Server\n\
71+
echo "Starting Encryption Server..."\n\
72+
cd /opt/fhenix/scripts && python3 encryption_server.py &\n\
73+
\n\
74+
# Configure evmosd\n\
75+
/opt/fhenix/bin/evmosd config output json\n\
76+
/opt/fhenix/bin/evmosd config chain-id $CHAIN_ID\n\
77+
\n\
78+
# Start evmosd\n\
79+
echo "Starting Evmos daemon with FHE support..."\n\
80+
/opt/fhenix/bin/evmosd start \\\n\
81+
--chain-id $CHAIN_ID \\\n\
82+
--home /root/.evmosd \\\n\
83+
--minimum-gas-prices=0.000000000000000001aevmos \\\n\
84+
--json-rpc.gas-cap=9999999999999999 \\\n\
85+
--gas-prices=0.00000000000000000000000000000000001aevmos \\\n\
86+
--json-rpc.api eth,txpool,personal,net,debug,web3\n\
87+
' > /opt/fhenix/scripts/start-localfhenix.sh && chmod +x /opt/fhenix/scripts/start-localfhenix.sh
88+
89+
# Create info script
90+
RUN mkdir -p /home/project/.fhenix-dev/scripts && \
91+
echo '#!/bin/bash\n\
92+
echo "=== Fhenix FHE Development Environment ==="\n\
93+
echo ""\n\
94+
echo "LocalFhenix is bundled in this container - no Docker-in-Docker required!"\n\
95+
echo ""\n\
96+
echo "=== Start LocalFhenix ==="\n\
97+
echo " /opt/fhenix/scripts/start-localfhenix.sh"\n\
98+
echo ""\n\
99+
echo "=== Endpoints (after starting) ==="\n\
100+
echo " RPC: http://127.0.0.1:8545"\n\
101+
echo " Faucet: curl http://127.0.0.1:6000/faucet?address=YOUR_ADDRESS"\n\
102+
echo ""\n\
103+
echo "=== Networks ==="\n\
104+
echo " LocalFhenix: http://127.0.0.1:8545"\n\
105+
echo " Helium Testnet: https://api.helium.fhenix.zone"\n\
106+
echo ""\n\
107+
echo "=== Encrypted Types ==="\n\
108+
echo " euint8, euint16, euint32, euint64, euint128, euint256"\n\
109+
echo " ebool, eaddress"\n\
110+
echo ""\n\
111+
echo "=== FHE Operations ==="\n\
112+
echo " FHE.asEuint*() - Encrypt plaintext values"\n\
113+
echo " FHE.add(), FHE.sub(), FHE.mul() - Arithmetic on encrypted data"\n\
114+
echo " FHE.and(), FHE.or(), FHE.xor() - Bitwise operations"\n\
115+
echo " FHE.eq(), FHE.ne(), FHE.lt(), FHE.gt() - Comparisons"\n\
116+
echo " FHE.select() - Conditional selection"\n\
117+
echo " FHE.decrypt() - Reveal encrypted value (requires permission)"\n\
118+
echo ""\n\
119+
echo "=== Quick Start ==="\n\
120+
echo " 1. Import: import { FHE, euint32 } from \"@fhenixprotocol/contracts\";"\n\
121+
echo " 2. Encrypt: euint32 secret = FHE.asEuint32(value);"\n\
122+
echo " 3. Compute: euint32 result = FHE.add(secret, FHE.asEuint32(10));"\n\
123+
echo ""\n\
124+
echo "=== Docs ==="\n\
125+
echo " https://docs.fhenix.zone"\n\
126+
' > /home/project/.fhenix-dev/scripts/show-info.sh && \
127+
chmod +x /home/project/.fhenix-dev/scripts/show-info.sh && \
128+
ln -s /opt/fhenix/scripts/start-localfhenix.sh /home/project/.fhenix-dev/start-localfhenix.sh && \
129+
chown -R project:project /home/project/.fhenix-dev
130+
131+
# Install Hardhat and Fhenix npm packages
132+
RUN npm install -g \
133+
hardhat \
134+
@nomicfoundation/hardhat-toolbox \
135+
@nomicfoundation/hardhat-ethers \
136+
hardhat-deploy \
137+
hardhat-deploy-ethers \
138+
fhenix-hardhat-plugin \
139+
fhenix-hardhat-network \
140+
fhenixjs \
141+
@fhenixprotocol/contracts \
142+
ethers \
143+
viem \
144+
@openzeppelin/contracts \
145+
typechain \
146+
@typechain/hardhat \
147+
@typechain/ethers-v6
148+
149+
# Pre-warm npm cache
150+
RUN npm cache add \
151+
fhenix-hardhat-plugin@latest \
152+
fhenixjs@latest \
153+
@fhenixprotocol/contracts@latest \
154+
@openzeppelin/contracts@latest
155+
156+
USER project
157+
158+
LABEL description="Fhenix Hardhat development with embedded LocalFhenix (no Docker-in-Docker required)"

0 commit comments

Comments
 (0)