-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdocker-entrypoint.sh
More file actions
343 lines (312 loc) · 12.3 KB
/
docker-entrypoint.sh
File metadata and controls
343 lines (312 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
#!/bin/bash
set -e
# OttoChain Full Stack Entrypoint
# All 5 layers in one image for guaranteed compatibility.
# LAYER env var selects which to run: gl0, gl1, ml0, cl1, dl1
#
# Smart run mode detection by layer type:
#
# L0 layers (GL0, ML0):
# - run-genesis: First-time genesis node (no ordinal data, genesis file provided)
# - run-rollback: Restarting genesis node (ordinal data exists)
# - run-validator: Joining an existing L0 cluster
#
# L1 layers (GL1, CL1, DL1):
# - run-initial-validator: First validator to start L1 cluster (no ordinal data, IS_INITIAL=true)
# - run-validator: Restarting OR joining an existing L1 cluster
case "${LAYER,,}" in
gl0)
JAR="/ottochain/jars/gl0.jar"
PORT="${GL0_PORT:-9000}"
P2P_PORT="${GL0_P2P_PORT:-9001}"
CLI_PORT="${GL0_CLI_PORT:-9002}"
DATA_DIR="/ottochain/data"
LAYER_TYPE="l0"
echo "Starting GL0 (Global L0) on port ${PORT}..."
;;
gl1)
JAR="/ottochain/jars/gl1.jar"
PORT="${GL1_PORT:-9100}"
P2P_PORT="${GL1_P2P_PORT:-9101}"
CLI_PORT="${GL1_CLI_PORT:-9102}"
DATA_DIR="/ottochain/data"
LAYER_TYPE="l1"
echo "Starting GL1 (Global L1 / DAG L1) on port ${PORT}..."
;;
ml0)
JAR="/ottochain/jars/ml0.jar"
PORT="${ML0_PORT:-9200}"
P2P_PORT="${ML0_P2P_PORT:-9201}"
CLI_PORT="${ML0_CLI_PORT:-9202}"
DATA_DIR="/ottochain/data"
LAYER_TYPE="l0"
echo "Starting ML0 (Metagraph L0) on port ${PORT}..."
;;
cl1)
JAR="/ottochain/jars/cl1.jar"
PORT="${CL1_PORT:-9300}"
P2P_PORT="${CL1_P2P_PORT:-9301}"
CLI_PORT="${CL1_CLI_PORT:-9302}"
DATA_DIR="/ottochain/data"
LAYER_TYPE="l1"
echo "Starting CL1 (Currency L1) on port ${PORT}..."
;;
dl1)
JAR="/ottochain/jars/dl1.jar"
PORT="${DL1_PORT:-9400}"
P2P_PORT="${DL1_P2P_PORT:-9401}"
CLI_PORT="${DL1_CLI_PORT:-9402}"
DATA_DIR="/ottochain/data"
LAYER_TYPE="l1"
echo "Starting DL1 (Data L1) on port ${PORT}..."
;;
*)
echo "Error: LAYER must be one of: gl0, gl1, ml0, cl1, dl1"
echo "Got: ${LAYER:-<not set>}"
exit 1
;;
esac
if [ ! -f "$JAR" ]; then
echo "Error: JAR not found at $JAR"
ls -la /ottochain/jars/
exit 1
fi
# ============================================================
# Smart Run Mode Detection
# ============================================================
# Check for existing ordinal data (indicates restart vs fresh start)
# ============================================================
# Tessellation stores ordinals in incremental_snapshot/ordinal (current).
# Legacy: snapshot/ordinal (deprecated but may exist in older data).
# Check incremental_snapshot first, fall back to snapshot for compatibility.
HAS_ORDINAL_DATA=false
ORDINAL_DIR=""
for CHECK_DIR in "${DATA_DIR}/incremental_snapshot/ordinal" "${DATA_DIR}/snapshot/ordinal"; do
if [ -d "${CHECK_DIR}" ] && [ "$(ls -A ${CHECK_DIR} 2>/dev/null)" ]; then
HAS_ORDINAL_DATA=true
ORDINAL_DIR="${CHECK_DIR}"
ORDINAL_COUNT=$(find "${CHECK_DIR}" -type f 2>/dev/null | wc -l)
echo "Found existing ordinal data: ${ORDINAL_COUNT} file(s) in ${ORDINAL_DIR}"
break
fi
done
# IS_INITIAL marks this as the first/genesis node for its layer
# Can be set explicitly, or inferred from RUN_MODE containing "genesis" or "initial"
IS_INITIAL="${IS_INITIAL:-false}"
if [ -n "${RUN_MODE}" ]; then
case "${RUN_MODE}" in
run-genesis|run-initial-validator)
IS_INITIAL=true
;;
esac
fi
# Auto-detect run mode if not explicitly set
if [ -z "${RUN_MODE}" ]; then
if [ "${LAYER_TYPE}" = "l0" ]; then
# GL0 or ML0: genesis / rollback / validator
if [ "${HAS_ORDINAL_DATA}" = "true" ]; then
if [ "${IS_INITIAL}" = "true" ]; then
RUN_MODE="run-rollback"
echo "Auto-detected RUN_MODE=run-rollback (L0 initial node restart, ordinal data exists)"
else
RUN_MODE="run-validator"
echo "Auto-detected RUN_MODE=run-validator (L0 validator restart)"
fi
elif [ "${IS_INITIAL}" = "true" ]; then
RUN_MODE="run-genesis"
echo "Auto-detected RUN_MODE=run-genesis (L0 initial node, no ordinal data)"
else
RUN_MODE="run-validator"
echo "Auto-detected RUN_MODE=run-validator (L0 joining cluster)"
fi
else
# GL1, CL1, DL1: initial-validator / validator
if [ "${HAS_ORDINAL_DATA}" = "true" ]; then
RUN_MODE="run-validator"
echo "Auto-detected RUN_MODE=run-validator (L1 restart, ordinal data exists)"
elif [ "${IS_INITIAL}" = "true" ]; then
RUN_MODE="run-initial-validator"
echo "Auto-detected RUN_MODE=run-initial-validator (L1 initial node, no ordinal data)"
else
RUN_MODE="run-validator"
echo "Auto-detected RUN_MODE=run-validator (L1 joining cluster)"
fi
fi
else
echo "Using explicit RUN_MODE=${RUN_MODE}"
# Safety warnings for potential issues
if [ "${RUN_MODE}" = "run-genesis" ] && [ "${HAS_ORDINAL_DATA}" = "true" ]; then
echo "⚠️ WARNING: run-genesis requested but ordinal data exists!"
echo " This will likely fail with 'Ordinal already exists' error."
echo " Consider using run-rollback or wiping ${ORDINAL_DIR}"
fi
if [ "${RUN_MODE}" = "run-initial-validator" ] && [ "${HAS_ORDINAL_DATA}" = "true" ]; then
echo "⚠️ WARNING: run-initial-validator requested but ordinal data exists!"
echo " This may cause issues. Consider using run-validator for restarts."
fi
fi
echo "Final: LAYER=${LAYER}, LAYER_TYPE=${LAYER_TYPE}, RUN_MODE=${RUN_MODE}, IS_INITIAL=${IS_INITIAL}"
# Build command line args
ARGS=""
# Verify keystore and password are set (passed via env vars to JAR)
if [ -f "${CL_KEYSTORE}" ]; then
if [ -z "${CL_PASSWORD}" ]; then
echo "Error: CL_PASSWORD is required when using a keystore"
exit 1
fi
# Note: CL_KEYSTORE, CL_KEYALIAS, CL_PASSWORD are read directly
# by tessellation from env vars (not CLI flags as of v4.x)
echo "Using keystore: ${CL_KEYSTORE}"
fi
# Add environment
ARGS="${ARGS} --env ${CL_APP_ENV:-testnet}"
# Add ports
ARGS="${ARGS} --public-port ${PORT}"
ARGS="${ARGS} --p2p-port ${P2P_PORT}"
ARGS="${ARGS} --cli-port ${CLI_PORT}"
# Add external IP if provided
if [ -n "${CL_EXTERNAL_IP}" ]; then
ARGS="${ARGS} --ip ${CL_EXTERNAL_IP}"
fi
# Add collateral (default 0 for metagraph)
ARGS="${ARGS} --collateral ${CL_COLLATERAL:-0}"
# Layer-specific peer configuration
case "${LAYER,,}" in
gl1)
# GL1 needs GL0 peer info
if [ -n "${CL_L0_PEER_ID}" ]; then
ARGS="${ARGS} --l0-peer-id ${CL_L0_PEER_ID}"
ARGS="${ARGS} --l0-peer-host ${CL_L0_PEER_HOST:-localhost}"
ARGS="${ARGS} --l0-peer-port ${CL_L0_PEER_PORT:-9000}"
fi
;;
ml0|cl1|dl1)
# Metagraph layers need GL0 peer info
if [ -n "${CL_GLOBAL_L0_PEER_ID}" ]; then
ARGS="${ARGS} --global-l0-peer-id ${CL_GLOBAL_L0_PEER_ID}"
ARGS="${ARGS} --global-l0-peer-host ${CL_GLOBAL_L0_PEER_HOST:-localhost}"
ARGS="${ARGS} --global-l0-peer-port ${CL_GLOBAL_L0_PEER_PORT:-9000}"
fi
# CL1 and DL1 also need ML0 peer info
if [ "${LAYER,,}" = "cl1" ] || [ "${LAYER,,}" = "dl1" ]; then
if [ -n "${CL_L0_PEER_ID}" ]; then
ARGS="${ARGS} --l0-peer-id ${CL_L0_PEER_ID}"
ARGS="${ARGS} --l0-peer-host ${CL_L0_PEER_HOST:-localhost}"
ARGS="${ARGS} --l0-peer-port ${CL_L0_PEER_PORT:-9200}"
fi
fi
# Token ID for metagraph layers
# ML0 run-genesis does NOT accept --l0-token-identifier, but run-validator REQUIRES it.
# CL1/DL1 always need it.
if [ -n "${CL_TOKEN_ID}" ]; then
if [ "${LAYER,,}" = "ml0" ] && [ "${RUN_MODE}" = "run-genesis" ]; then
echo "Skipping --l0-token-identifier for ML0 genesis mode"
else
ARGS="${ARGS} --l0-token-identifier ${CL_TOKEN_ID}"
fi
fi
;;
esac
# Genesis file handling for run-genesis mode (L0 layers only)
GENESIS_ARG=""
if [ "${RUN_MODE}" = "run-genesis" ]; then
# Find genesis file (CSV for GL0, snapshot for ML0)
if [ -n "${GENESIS_FILE}" ] && [ -f "${GENESIS_FILE}" ]; then
GENESIS_PATH="${GENESIS_FILE}"
elif [ "${LAYER,,}" = "gl0" ] && [ -f "/ottochain/genesis/genesis.csv" ]; then
GENESIS_PATH="/ottochain/genesis/genesis.csv"
elif [ "${LAYER,,}" = "gl0" ] && [ -f "/ottochain/genesis/gl0-genesis.csv" ]; then
GENESIS_PATH="/ottochain/genesis/gl0-genesis.csv"
elif [ "${LAYER,,}" = "ml0" ] && [ -f "/ottochain/data/genesis.snapshot" ]; then
GENESIS_PATH="/ottochain/data/genesis.snapshot"
elif [ "${LAYER,,}" = "ml0" ] && [ -f "/ottochain/genesis/genesis.snapshot" ]; then
GENESIS_PATH="/ottochain/genesis/genesis.snapshot"
fi
if [ -n "${GENESIS_PATH}" ]; then
echo "Using genesis file: ${GENESIS_PATH}"
GENESIS_ARG="${GENESIS_PATH}"
else
echo "Error: run-genesis requires a genesis file but none found"
echo "Expected locations:"
echo " GL0: /ottochain/genesis/genesis.csv or /ottochain/genesis/gl0-genesis.csv"
echo " ML0: /ottochain/data/genesis.snapshot or /ottochain/genesis/genesis.snapshot"
echo " Or set GENESIS_FILE env var"
exit 1
fi
fi
# Rollback hash handling for run-rollback mode
#
# IMPORTANT: As of tessellation 4.0.0-rc.10:
# - DAG L0 (GL0): REQUIRES rollback hash as positional argument
# - Currency L0 (ML0/CL0): Does NOT require hash (auto-detects from storage)
# - Data L1: Does NOT require hash
#
# Tessellation storage structure (incremental_snapshot/):
# ordinal/<bucket>/<ordinal_number> - snapshot data, filename is ordinal
# hash/<prefix1>/<prefix2>/<hash> - hardlink to same data, filename is hash
#
# Strategy: Find highest ordinal, then lookup its hash via hardlink inode.
ROLLBACK_ARG=""
if [ "${RUN_MODE}" = "run-rollback" ] && [ "${LAYER,,}" = "gl0" ]; then
# Only GL0 needs the rollback hash argument
# Allow explicit override via ROLLBACK_HASH env var
if [ -n "${ROLLBACK_HASH}" ]; then
ROLLBACK_ARG="${ROLLBACK_HASH}"
echo "Using explicit rollback hash: ${ROLLBACK_ARG}"
else
ORDINAL_BASE="${DATA_DIR}/incremental_snapshot/ordinal"
HASH_BASE="${DATA_DIR}/incremental_snapshot/hash"
# Fall back to deprecated snapshot/ if incremental_snapshot doesn't exist
if [ ! -d "${ORDINAL_BASE}" ]; then
ORDINAL_BASE="${DATA_DIR}/snapshot/ordinal"
HASH_BASE="${DATA_DIR}/snapshot/hash"
fi
if [ -d "${ORDINAL_BASE}" ]; then
# Find highest ordinal number across all buckets
# Ordinal files are named by their ordinal number (1, 2, 3, ...)
HIGHEST_ORDINAL_FILE=$(find "${ORDINAL_BASE}" -type f -name '[0-9]*' 2>/dev/null | \
while read f; do basename "$f"; done | sort -n | tail -1)
if [ -n "${HIGHEST_ORDINAL_FILE}" ]; then
# Find the actual file path
ORDINAL_PATH=$(find "${ORDINAL_BASE}" -type f -name "${HIGHEST_ORDINAL_FILE}" | head -1)
if [ -n "${ORDINAL_PATH}" ] && [ -f "${ORDINAL_PATH}" ]; then
echo "Found highest ordinal: ${HIGHEST_ORDINAL_FILE} at ${ORDINAL_PATH}"
# Get inode and find hardlinked hash file
INODE=$(stat -c %i "${ORDINAL_PATH}" 2>/dev/null)
if [ -n "${INODE}" ] && [ -d "${HASH_BASE}" ]; then
HASH_FILE=$(find "${HASH_BASE}" -inum "${INODE}" 2>/dev/null | head -1)
if [ -n "${HASH_FILE}" ]; then
ROLLBACK_ARG=$(basename "${HASH_FILE}")
echo "Auto-detected rollback hash: ${ROLLBACK_ARG}"
echo " From ordinal: ${HIGHEST_ORDINAL_FILE}"
fi
fi
fi
fi
fi
fi
if [ -z "${ROLLBACK_ARG}" ]; then
echo "Error: GL0 run-rollback requires a snapshot hash but none found"
echo "Expected: ordinals in \${DATA_DIR}/incremental_snapshot/ordinal/"
echo "Or set ROLLBACK_HASH env var explicitly"
exit 1
fi
elif [ "${RUN_MODE}" = "run-rollback" ]; then
# ML0/CL0/DL1: run-rollback auto-detects from storage, no hash needed
echo "Currency/Data L0 run-rollback: using auto-detection (no hash arg)"
fi
# Add any extra args passed to container
ARGS="${ARGS} $@"
# Build final command
# Positional arguments go after options:
# run-genesis <genesis_file>
# run-rollback <rollback_hash>
if [ "${RUN_MODE}" = "run-genesis" ] && [ -n "${GENESIS_ARG}" ]; then
CMD="java ${JAVA_OPTS} -jar \"${JAR}\" ${RUN_MODE} ${ARGS} \"${GENESIS_ARG}\""
elif [ "${RUN_MODE}" = "run-rollback" ] && [ -n "${ROLLBACK_ARG}" ]; then
CMD="java ${JAVA_OPTS} -jar \"${JAR}\" ${RUN_MODE} ${ARGS} \"${ROLLBACK_ARG}\""
else
CMD="java ${JAVA_OPTS} -jar \"${JAR}\" ${RUN_MODE} ${ARGS}"
fi
echo "Running: $CMD"
eval exec $CMD