-
Notifications
You must be signed in to change notification settings - Fork 126
/
Copy pathentrypoint.sh
executable file
·363 lines (322 loc) · 15.2 KB
/
entrypoint.sh
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
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
#!/usr/bin/env bash
# This script serves as the entrypoint for the Zebra Docker container.
#
# Description:
# This script serves as the primary entrypoint for the Docker container. Its main responsibilities include:
# 1. Environment Setup: Prepares the environment by setting various flags and parameters.
# 2. Configuration Management: Dynamically generates the `zebrad.toml` configuration file based on environment variables, ensuring the node starts with the desired settings.
# 3. Test Execution: Can run a series of tests to validate functionality based on specified environment variables.
# 4. Node Startup: Starts the node, allowing it to begin its operations.
#
# Exit if a command fails
set -e
# Exit if any command in a pipeline fails
set -o pipefail
####
# General Variables
# These variables are used to run the Zebra node.
####
# Path and name of the config file. These two have defaults set in the Dockerfile.
: "${ZEBRA_CONF_DIR:=}"
: "${ZEBRA_CONF_FILE:=}"
# [network]
: "${NETWORK:=Mainnet}"
: "${ZEBRA_LISTEN_ADDR:=0.0.0.0}"
# [consensus]
: "${ZEBRA_CHECKPOINT_SYNC:=true}"
# [state]
# Set this to change the default cached state directory
: "${ZEBRA_CACHED_STATE_DIR:=/var/cache/zebrad-cache}"
: "${LIGHTWALLETD_DATA_DIR:=/var/cache/lwd-cache}"
# [metrics]
: "${METRICS_ENDPOINT_ADDR:=0.0.0.0}"
: "${METRICS_ENDPOINT_PORT:=9999}"
# [tracing]
: "${LOG_COLOR:=false}"
: "${TRACING_ENDPOINT_ADDR:=0.0.0.0}"
: "${TRACING_ENDPOINT_PORT:=3000}"
# [rpc]
: "${RPC_LISTEN_ADDR:=0.0.0.0}"
# if ${RPC_PORT} is not set, use the default value for the current network
if [[ -z "${RPC_PORT}" ]]; then
if [[ "${NETWORK}" = "Mainnet" ]]; then
: "${RPC_PORT:=8232}"
elif [[ "${NETWORK}" = "Testnet" ]]; then
: "${RPC_PORT:=18232}"
fi
fi
####
# Test Variables
# These variables are used to run tests in the Dockerfile.
####
: "${RUN_ALL_TESTS:=}"
: "${RUN_ALL_EXPERIMENTAL_TESTS:=}"
: "${TEST_FAKE_ACTIVATION_HEIGHTS:=}"
: "${TEST_ZEBRA_EMPTY_SYNC:=}"
: "${TEST_LWD_INTEGRATION:=}"
: "${FULL_SYNC_MAINNET_TIMEOUT_MINUTES:=}"
: "${FULL_SYNC_TESTNET_TIMEOUT_MINUTES:=}"
: "${TEST_DISK_REBUILD:=}"
: "${TEST_UPDATE_SYNC:=}"
: "${TEST_CHECKPOINT_SYNC:=}"
: "${GENERATE_CHECKPOINTS_MAINNET:=}"
: "${GENERATE_CHECKPOINTS_TESTNET:=}"
: "${TEST_LWD_RPC_CALL:=}"
: "${TEST_LWD_FULL_SYNC:=}"
: "${TEST_LWD_UPDATE_SYNC:=}"
: "${TEST_LWD_GRPC:=}"
: "${TEST_LWD_TRANSACTIONS:=}"
: "${TEST_GET_BLOCK_TEMPLATE:=}"
: "${TEST_SUBMIT_BLOCK:=}"
: "${ENTRYPOINT_FEATURES:=}"
: "${TEST_SCAN_TASK_COMMANDS:=}"
# Configuration file path
if [[ -n "${ZEBRA_CONF_DIR}" ]] && [[ -n "${ZEBRA_CONF_FILE}" ]] && [[ -z "${ZEBRA_CONF_PATH}" ]]; then
ZEBRA_CONF_PATH="${ZEBRA_CONF_DIR}/${ZEBRA_CONF_FILE}"
fi
# Populate `zebrad.toml` before starting zebrad, using the environmental
# variables set by the Dockerfile or the user. If the user has already created a config, don't replace it.
#
# We disable most ports by default, so the default config is secure.
# Users have to opt-in to additional functionality by setting environmental variables.
if [[ -n "${ZEBRA_CONF_PATH}" ]] && [[ ! -f "${ZEBRA_CONF_PATH}" ]] && [[ -z "${ENTRYPOINT_FEATURES}" ]]; then
# Create the conf path and file
(mkdir -p "$(dirname "${ZEBRA_CONF_PATH}")" && touch "${ZEBRA_CONF_PATH}") || { echo "Error creating file ${ZEBRA_CONF_PATH}"; exit 1; }
# Populate the conf file
cat <<EOF > "${ZEBRA_CONF_PATH}"
[network]
network = "${NETWORK}"
listen_addr = "${ZEBRA_LISTEN_ADDR}"
[state]
cache_dir = "${ZEBRA_CACHED_STATE_DIR}"
EOF
if [[ " ${FEATURES} " =~ " prometheus " ]]; then # spaces are important here to avoid partial matches
cat <<EOF >> "${ZEBRA_CONF_PATH}"
[metrics]
endpoint_addr = "${METRICS_ENDPOINT_ADDR}:${METRICS_ENDPOINT_PORT}"
EOF
fi
if [[ -n "${RPC_PORT}" ]]; then
cat <<EOF >> "${ZEBRA_CONF_PATH}"
[rpc]
listen_addr = "${RPC_LISTEN_ADDR}:${RPC_PORT}"
EOF
fi
if [[ -n "${LOG_FILE}" ]] || [[ -n "${LOG_COLOR}" ]] || [[ -n "${TRACING_ENDPOINT_ADDR}" ]]; then
cat <<EOF >> "${ZEBRA_CONF_PATH}"
[tracing]
EOF
if [[ " ${FEATURES} " =~ " filter-reload " ]]; then # spaces are important here to avoid partial matches
cat <<EOF >> "${ZEBRA_CONF_PATH}"
endpoint_addr = "${TRACING_ENDPOINT_ADDR}:${TRACING_ENDPOINT_PORT}"
EOF
fi
# Set this to log to a file, if not set, logs to standard output
if [[ -n "${LOG_FILE}" ]]; then
mkdir -p "$(dirname "${LOG_FILE}")"
cat <<EOF >> "${ZEBRA_CONF_PATH}"
log_file = "${LOG_FILE}"
EOF
fi
# Zebra automatically detects if it is attached to a terminal, and uses colored output.
# Set this to 'true' to force using color even if the output is not a terminal.
# Set this to 'false' to disable using color even if the output is a terminal.
if [[ "${LOG_COLOR}" = "true" ]]; then
cat <<EOF >> "${ZEBRA_CONF_PATH}"
force_use_color = true
EOF
elif [[ "${LOG_COLOR}" = "false" ]]; then
cat <<EOF >> "${ZEBRA_CONF_PATH}"
use_color = false
EOF
fi
fi
if [[ -n "${MINER_ADDRESS}" ]]; then
cat <<EOF >> "${ZEBRA_CONF_PATH}"
[mining]
miner_address = "${MINER_ADDRESS}"
EOF
fi
fi
if [[ -n "${ZEBRA_CONF_PATH}" ]] && [[ -z "${ENTRYPOINT_FEATURES}" ]]; then
# Print the config file
echo "Using zebrad.toml:"
cat "${ZEBRA_CONF_PATH}"
fi
# Function to list directory
check_directory_files() {
local dir="$1"
# Check if the directory exists
if [[ -d "${dir}" ]]; then
# Check if there are any subdirectories
if find "${dir}" -mindepth 1 -type d | read -r; then
# Subdirectories exist, so we continue
:
else
# No subdirectories, print message and exit with status 1
echo "No subdirectories found in ${dir}."
exit 1
fi
else
# Directory doesn't exist, print message and exit with status 1
echo "Directory ${dir} does not exist."
exit 1
fi
}
# Function to run cargo test with an arbitrary number of arguments
run_cargo_test() {
# Start constructing the command, ensuring that $1 is enclosed in single quotes as it's a feature list
local cmd="exec cargo test --locked --release --features '$1' --package zebrad --test acceptance -- --nocapture --include-ignored"
# Shift the first argument, as it's already included in the cmd
shift
# Loop through the remaining arguments
for arg in "$@"; do
if [[ -n ${arg} ]]; then
# If the argument is non-empty, add it to the command
cmd+=" ${arg}"
fi
done
# Run the command using eval, this will replace the current process with the cargo command
eval "${cmd}" || { echo "Cargo test failed"; exit 1; }
}
# Main Execution Logic:
# This script orchestrates the execution flow based on the provided arguments and environment variables.
# - If "$1" is '--', '-', or 'zebrad', the script processes the subsequent arguments for the 'zebrad' command.
# - If ENTRYPOINT_FEATURES is unset, it checks for ZEBRA_CONF_PATH. If set, 'zebrad' runs with this custom configuration; otherwise, it runs with the provided arguments.
# - If "$1" is an empty string and ENTRYPOINT_FEATURES is set, the script enters the testing phase, checking various environment variables to determine the specific tests to run.
# - Different tests or operations are triggered based on the respective conditions being met.
# - If "$1" doesn't match any of the above, it's assumed to be a command, which is executed directly.
# This structure ensures a flexible execution strategy, accommodating various scenarios such as custom configurations, different testing phases, or direct command execution.
case "$1" in
--* | -* | zebrad)
shift
if [[ -n "${ZEBRA_CONF_PATH}" ]]; then
exec zebrad -c "${ZEBRA_CONF_PATH}" "$@" || { echo "Execution with custom configuration failed"; exit 1; }
else
exec zebrad "$@" || { echo "Execution failed"; exit 1; }
fi
;;
"")
if [[ -n "${ENTRYPOINT_FEATURES}" ]]; then
# Validate the test variables
# For these tests, we activate the test features to avoid recompiling `zebrad`,
# but we don't actually run any gRPC tests.
if [[ "${RUN_ALL_TESTS}" -eq "1" ]]; then
# Run unit, basic acceptance tests, and ignored tests, only showing command output if the test fails.
# If the lightwalletd environmental variables are set, we will also run those tests.
exec cargo test --locked --release --features "${ENTRYPOINT_FEATURES}" --workspace -- --nocapture --include-ignored --skip check_no_git_refs_in_cargo_lock
elif [[ "${RUN_ALL_EXPERIMENTAL_TESTS}" -eq "1" ]]; then
# Run unit, basic acceptance tests, and ignored tests with experimental features.
# If the lightwalletd environmental variables are set, we will also run those tests.
exec cargo test --locked --release --features "${ENTRYPOINT_FEATURES} ${EXPERIMENTAL_FEATURES}" --workspace -- --nocapture --include-ignored --skip check_no_git_refs_in_cargo_lock
elif [[ "${RUN_CHECK_NO_GIT_REFS}" -eq "1" ]]; then
# Run the check_no_git_refs_in_cargo_lock test.
exec cargo test --locked --release --features "${ENTRYPOINT_FEATURES}" --workspace -- --nocapture --include-ignored check_no_git_refs_in_cargo_lock
elif [[ "${TEST_FAKE_ACTIVATION_HEIGHTS}" -eq "1" ]]; then
# Run state tests with fake activation heights.
exec cargo test --locked --release --features "zebra-test" --package zebra-state --lib -- --nocapture --include-ignored with_fake_activation_heights
elif [[ "${TEST_ZEBRA_EMPTY_SYNC}" -eq "1" ]]; then
# Test that Zebra syncs and checkpoints a few thousand blocks from an empty state.
run_cargo_test "${ENTRYPOINT_FEATURES}" "sync_large_checkpoints_"
elif [[ -n "${FULL_SYNC_MAINNET_TIMEOUT_MINUTES}" ]]; then
# Run a Zebra full sync test on mainnet.
run_cargo_test "${ENTRYPOINT_FEATURES}" "full_sync_mainnet"
# List directory generated by test
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
elif [[ -n "${FULL_SYNC_TESTNET_TIMEOUT_MINUTES}" ]]; then
# Run a Zebra full sync test on testnet.
run_cargo_test "${ENTRYPOINT_FEATURES}" "full_sync_testnet"
# List directory generated by test
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
elif [[ "${TEST_DISK_REBUILD}" -eq "1" ]]; then
# Run a Zebra sync up to the mandatory checkpoint.
#
# TODO: use environmental variables instead of Rust features (part of #2995)
run_cargo_test "test_sync_to_mandatory_checkpoint_${NETWORK,,},${ENTRYPOINT_FEATURES}" "sync_to_mandatory_checkpoint_${NETWORK,,}"
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
elif [[ "${TEST_UPDATE_SYNC}" -eq "1" ]]; then
# Run a Zebra sync starting at the cached tip, and syncing to the latest tip.
#
# List directory used by test
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
run_cargo_test "${ENTRYPOINT_FEATURES}" "zebrad_update_sync"
elif [[ "${TEST_CHECKPOINT_SYNC}" -eq "1" ]]; then
# Run a Zebra sync starting at the cached mandatory checkpoint, and syncing past it.
#
# List directory used by test
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
# TODO: use environmental variables instead of Rust features (part of #2995)
run_cargo_test "test_sync_past_mandatory_checkpoint_${NETWORK,,},${ENTRYPOINT_FEATURES}" "sync_past_mandatory_checkpoint_${NETWORK,,}"
elif [[ "${GENERATE_CHECKPOINTS_MAINNET}" -eq "1" ]]; then
# Generate checkpoints after syncing Zebra from a cached state on mainnet.
#
# TODO: disable or filter out logs like:
# test generate_checkpoints_mainnet has been running for over 60 seconds
#
# List directory used by test
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
run_cargo_test "${ENTRYPOINT_FEATURES}" "generate_checkpoints_mainnet"
elif [[ "${GENERATE_CHECKPOINTS_TESTNET}" -eq "1" ]]; then
# Generate checkpoints after syncing Zebra on testnet.
#
# This test might fail if testnet is unstable.
#
# List directory used by test
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
run_cargo_test "${ENTRYPOINT_FEATURES}" "generate_checkpoints_testnet"
elif [[ "${TEST_LWD_RPC_CALL}" -eq "1" ]]; then
# Starting at a cached Zebra tip, test a JSON-RPC call to Zebra.
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
# Run both the fully synced RPC test and the subtree snapshot test, one test at a time.
# Since these tests use the same cached state, a state problem in the first test can fail the second test.
run_cargo_test "${ENTRYPOINT_FEATURES}" "--test-threads" "1" "fully_synced_rpc_"
elif [[ "${TEST_LWD_INTEGRATION}" -eq "1" ]]; then
# Test launching lightwalletd with an empty lightwalletd and Zebra state.
run_cargo_test "${ENTRYPOINT_FEATURES}" "lightwalletd_integration"
elif [[ "${TEST_LWD_FULL_SYNC}" -eq "1" ]]; then
# Starting at a cached Zebra tip, run a lightwalletd sync to tip.
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
run_cargo_test "${ENTRYPOINT_FEATURES}" "lightwalletd_full_sync"
check_directory_files "${LIGHTWALLETD_DATA_DIR}/db"
elif [[ "${TEST_LWD_UPDATE_SYNC}" -eq "1" ]]; then
# Starting with a cached Zebra and lightwalletd tip, run a quick update sync.
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
check_directory_files "${LIGHTWALLETD_DATA_DIR}/db"
run_cargo_test "${ENTRYPOINT_FEATURES}" "lightwalletd_update_sync"
# These tests actually use gRPC.
elif [[ "${TEST_LWD_GRPC}" -eq "1" ]]; then
# Starting with a cached Zebra and lightwalletd tip, test all gRPC calls to lightwalletd, which calls Zebra.
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
check_directory_files "${LIGHTWALLETD_DATA_DIR}/db"
run_cargo_test "${ENTRYPOINT_FEATURES}" "lightwalletd_wallet_grpc_tests"
elif [[ "${TEST_LWD_TRANSACTIONS}" -eq "1" ]]; then
# Starting with a cached Zebra and lightwalletd tip, test sending transactions gRPC call to lightwalletd, which calls Zebra.
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
check_directory_files "${LIGHTWALLETD_DATA_DIR}/db"
run_cargo_test "${ENTRYPOINT_FEATURES}" "sending_transactions_using_lightwalletd"
# These tests use mining code, but don't use gRPC.
elif [[ "${TEST_GET_BLOCK_TEMPLATE}" -eq "1" ]]; then
# Starting with a cached Zebra tip, test getting a block template from Zebra's RPC server.
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
run_cargo_test "${ENTRYPOINT_FEATURES}" "get_block_template"
elif [[ "${TEST_SUBMIT_BLOCK}" -eq "1" ]]; then
# Starting with a cached Zebra tip, test sending a block to Zebra's RPC port.
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
run_cargo_test "${ENTRYPOINT_FEATURES}" "submit_block"
elif [[ "${TEST_SCAN_TASK_COMMANDS}" -eq "1" ]]; then
# Test that the scan task commands are working.
check_directory_files "${ZEBRA_CACHED_STATE_DIR}"
exec cargo test --locked --release --features "zebra-test" --package zebra-scan -- --nocapture --include-ignored scan_task_commands
else
exec "$@"
fi
fi
;;
*)
if command -v gosu >/dev/null 2>&1; then
exec gosu "$USER" "$@"
else
exec "$@"
fi
;;
esac