This repository has been archived by the owner on Jul 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 66
/
Makefile
439 lines (401 loc) · 18.2 KB
/
Makefile
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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
RUST_LOG ?= info
# you can use devnet | testnet | mainnet
chain ?= devnet
# set the data path when the claster run
data_path ?= /tmp/data
# you can add a prefix such as node0 | node1 to create mulpile clusters on one host
prefix ?=
sgx_mode ?= HW
build_mode ?= debug
TX_QUERY_HOSTNAME ?=
MAKE_CMD = make
DEV_CONF ?= dev-utils/example-dev-conf.json
ifeq ($(build_mode), release)
CARGO_BUILD_CMD = cargo build --release
SGX_MODE = "SGX_ARGS=0"
else
SGX_ARGS =
CARGO_BUILD_CMD = cargo build
endif
chain_abci_features ?= ${CHAIN_ABCI_FEATURES}
client_features ?= ${CLIENT_FEATURES}
ifeq ($(chain_abci_features)x, x)
CARGO_BUILD_CMD_ABCI = $(CARGO_BUILD_CMD)
else
CARGO_BUILD_CMD_ABCI = $(CARGO_BUILD_CMD) --features "$(chain_abci_features)"
endif
ifeq ($(client_features)x, x)
CARGO_BUILD_CMD_CLI = $(CARGO_BUILD_CMD) --features mock-hardware-wallet
CARGO_BUILD_CMD_RPC = $(CARGO_BUILD_CMD)
else
CARGO_BUILD_CMD_CLI = $(CARGO_BUILD_CMD) --features "$(client_features)"
CARGO_BUILD_CMD_RPC = $(CARGO_BUILD_CMD) --features "$(client_features)"
endif
base_port ?= 26650
TX_QUERY_PORT = $(shell expr $(base_port) + 1)
TENDERMINT_P2P_PORT = $(shell expr $(base_port) + 6)
TENDERMINT_RPC_PORT = $(shell expr $(base_port) + 7)
CLIENT_RPC_PORT = $(shell expr $(base_port) + 9)
TENDERMINT_PMS_PORT = $(shell expr $(base_port) + 10)
# the chain version, such as v0.1.0, v0.2.0.
tag ?=
# if the tag not set, it will use current tag, if current code is not checkouted to a tag, it will use `develop`
ifeq ($(tag)x, x)
TAG = $(shell git describe --exact-match --tags $(git log -n1 --pretty='%h') 2>/dev/null || echo develop)
else
TAG = $(tag)
endif
# docker's network
NETWORK = crypto-chain
# if the TAG like v0.1.0, v0.2.0, we download the binary file from github
ifeq ($(TAG), develop)
DOWNLAD_URL=
else
DOWNLOAD_URL=$(shell curl -s https://api.github.com/repos/crypto-com/chain/releases \
| grep browser_download_url \
| grep download/$(tag)/ \
| cut -d '"' -f 4 || echo "")
endif
APP_HASH := $(shell cat docker/config/$(chain)/tendermint/genesis.json | python -c "import json,sys;obj=json.load(sys.stdin);print(obj['app_hash'])")
ifeq ($(chain), devnet)
CHAIN_ID = test-chain-y3m1e6-AB
NETWORK_ID = AB
SGX_MODE = $(sgx_mode)
else ifeq ($(chain), testnet)
CHAIN_ID = testnet-thaler-crypto-com-chain-42
NETWORK_ID = 42
SGX_MODE = HW
# TODO: change it with version update
CRYPTO_GENESIS_FINGERPRINT = DC05002AAEAB58DA40701073A76A018C9AB02C87BD89ADCB6EE7FE5B419526C8
else ifeq ($(chain), mainnet)
CHAIN_ID = thaler-crypto-com-chain-42
NETWORK_ID = 42
SGX_MODE = HW
# TODO: use mainnet's genesis app hash
CRYPTO_GENESIS_FINGERPRINT = F62DDB49D7EB8ED0883C735A0FB7DE7F2A3FA322FCD2AA832F452A62B38607D5
endif
IMAGE = crypto-chain
IMAGE_RUST = cryptocom/chain
IMAGE_TENDERMINT = tendermint/tendermint:v0.33.7
DOCKER_FILE = docker/Dockerfile
DOCKER_FILE_RELEASE = docker/Dockerfile.release
ITEMS_START = chain-abci tendermint client-rpc
ITEMS_STOP = client-rpc tendermint chain-abci
create-path:
mkdir -p ${HOME}/.cargo/{git,registry}
bash -c "mkdir -p $(data_path)/tendermint/{config,data}"
bash -c "mkdir -p $(data_path)/{wallet,chain-storage,enclave-storage}"
chown-path:
bash -c "chown -R $(user):$(group) $(data_path)/{tendermint,wallet,chain-storage,enclave-storage}"
init-tendermint:
ifeq ($(chain), devnet)
@echo "\033[32mcopy devnet tendermint config\033[0m"
cp docker/config/devnet/tendermint/config.toml $(data_path)/tendermint/config/
cp docker/config/devnet/tendermint/genesis.json $(data_path)/tendermint/config/
cp docker/config/devnet/tendermint/priv_validator_key.json $(data_path)/tendermint/config/
cp docker/config/devnet/tendermint/priv_validator_state.json $(data_path)/tendermint/data/
else ifeq ($(chain), testnet)
@echo "\033[32mcopy testnet tendermint config\033[0m"
bash -c "cp docker/config/testnet/tendermint/{config.toml,genesis.json} $(data_path)/tendermint/config/"
else ifeq ($(chain), mainnet)
@echo "\033[32mcopy mainnet tendermint config\033[0m"
bash -c "cp docker/config/mainnet/tendermint/{config.toml,genesis.json} $(data_path)/tendermint/config/"
endif
check-sgx-device:
# SGX_DEVICE should be /dev/isgx as latest dcap driver /dev/sgx higher than v1.31 is not supported by fortanix
ifeq ($(SGX_MODE), HW)
ifeq ($(shell test -e /dev/isgx && echo -n yes),yes)
$(eval SGX_DEVICE=/dev/isgx)
@echo "\033[32mSet SGX_DEVICE=/dev/isgx\033[0m"
else ifeq ($(shell test -e /dev/sgx && VERSION=$$(dmesg | grep "Intel SGX DCAP Driver v" | awk '{ print $$NF }' | tr -d "v" | awk -F. '{ printf("%d%03d", $$1,$$2) }') && if [ $$VERSION -gt 1031 ]; then echo "yes";fi;),yes)
$(error /dev/sgx higher than v1.31 is not supported. Please remove dcap sgx driver by "make rm-dcap-sgx-driver" and install intel sgx driver by "make install-isgx-driver")
else ifeq ($(shell test -e /dev/sgx && echo "yes"),yes)
$(eval SGX_DEVICE=/dev/sgx)
@echo "\033[32mSet SGX_DEVICE=/dev/sgx\033[0m"
else
$(error No sgx device detected! Please install intel sgx driver by "make install-isgx-driver")
endif
else
@echo "\033[32mSGX_MODE is SW, skip to check sgx driver\033[0m"
endif
source=https://download.01.org/intel-sgx/sgx-linux/2.9.1/distro/ubuntu18.04-server/sgx_linux_x64_driver_2.6.0_95eaa6f.bin
install-isgx-driver:
ifeq ($(SGX_MODE), HW)
@if [ -e "/dev/isgx" ]; then \
echo "\033[32misgx driver already installed\033[0m"; \
else \
echo "\033[32minstall isgx driver\033[0m"; \
sudo systemctl stop aesmd || echo "aesmd does not exist"; \
sudo apt update && \
sudo apt -y install dkms && \
curl --proto '=https' -sSf $(source) > /tmp/driver.bin && \
chmod +x /tmp/driver.bin && \
sudo /tmp/driver.bin && \
rm /tmp/driver.bin && \
echo "\033[32mReboot may be required!\033[0m"; \
fi
else
@echo "\033[32mSGX_MODE is SW, no need to install sgx driver\033[0m"
endif
rm-dcap-sgx-driver:
@if [ -e "/dev/sgx" ]; then \
echo "\033[32mRemove open enclave sgx DCAP driver\033[0m"; \
sudo systemctl stop aesmd || echo "aesmd does not exist"; \
sudo rm -f $$(find /lib/modules -name intel_sgx.ko) && \
sudo /sbin/depmod && \
sudo sed -i '/^intel_sgx$$/d' /etc/modules && \
sudo rm -f /etc/sysconfig/modules/intel_sgx.modules && \
sudo rm -f /etc/modules-load.d/intel_sgx.conf && \
sudo rm -rf /dev/sgx; \
else \
echo "\033[32mOpen enclave sgx DCAP driver already removed\033[0m"; \
fi;
# build the sgx image
image:
ifeq ($(DOWNLOAD_URL)X, X)
@echo "\033[32mbuild docker image with local binary\033[0m";
chmod +x ci-scripts/*.sh;
docker build -t $(IMAGE):$(TAG) -f $(DOCKER_FILE) --build-arg BUILD_MODE=$(build_mode) .
else
@echo "\033[32mdownload binary and build docker image\033[0m";
chmod +x docker/*.sh;
docker build -t $(IMAGE):$(TAG) -f $(DOCKER_FILE_RELEASE) --build-arg DOWNLOAD_URL=$(DOWNLOAD_URL) .
endif
# build the chain binary in docker
build-chain: build-sgx-query-validation-next
@if [ -e "./target/$(build_mode)/client-cli" -a -e "./target/$(build_mode)/chain-abci" -a -e "./target/$(build_mode)/client-rpc" ]; then \
echo "\033[32mchain binary already exist or delete binary by 'make clean' to force new build for chain\033[0m"; \
else \
echo "\033[32mbuilding binary\033[0m"; \
docker run -i --rm \
-v ${HOME}/.cargo/git:/root/.cargo/git \
-v ${HOME}/.cargo/registry:/root/.cargo/registry \
-v `pwd`:/chain \
--env RUSTFLAGS=-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3 \
--env NETWORK_ID=$(NETWORK_ID) \
--workdir=/chain \
$(IMAGE_RUST):latest \
bash -c '. /root/.docker_bashrc && \
echo "======== parse tx-query sig struct =========" && \
export TQE_SIGSTRUCT=./target/$(build_mode)/tx-query2-enclave-app.sig && \
export TQE_MRENCLAVE=`od -A none -t x1 --read-bytes=32 -j 960 -w32 $$TQE_SIGSTRUCT | tr -d " "` && \
export MRSIGNER=`dd if=$$TQE_SIGSTRUCT bs=1 skip=128 count=384 status=none | sha256sum | cut -d" " -f1` && \
echo "======== build chain-abci =========" && \
cd chain-abci && $(CARGO_BUILD_CMD_ABCI) && \
echo "======== build client-cli =========" && \
cd ../client-cli && $(CARGO_BUILD_CMD_CLI)&& \
echo "======== build client-rpc =========" && \
cd ../client-rpc/server && $(CARGO_BUILD_CMD_RPC)'; \
fi
# build the enclave queury-next and tx-validation-next binary and sig
build-sgx-query-validation-next:
@if [ -e "./target/$(build_mode)/tx-query2-enclave-app.sig" -a -e "./target/$(build_mode)/tx-query2-enclave-app.sgxs" \
-a -e "./target/$(build_mode)/tx-validation-next.sig" -a -e "./target/${build_mode}/tx-validation-next.sgxs" \
-a -e "./target/$(build_mode)/ra-sp-server" -a -e "./target/$(build_mode)/dev-utils" ]; \
then \
echo "\033[32msgx binary already exist or delete binary by 'make clean' to force new build for chain\033[0m"; \
else \
echo "\033[32mcompile sgx query-next and tx-validation-next\033[0m"; \
docker pull $(IMAGE_RUST):latest; \
docker run -i --rm \
-v ${HOME}/.cargo/git:/root/.cargo/git \
-v ${HOME}/.cargo/registry:/root/.cargo/registry \
-v `pwd`:/chain \
--env SGX_MODE=$(SGX_MODE) \
--env CFLAGS=-gz=none \
--env RUSTFLAGS=-Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3,+pclmul,+sha \
--env NETWORK_ID=$(NETWORK_ID) \
--workdir=/chain \
$(IMAGE_RUST):latest \
bash -c '. /root/.docker_bashrc && \
echo "======== openssl gen privatekey =========" && \
openssl genrsa -3 3072 > sgx.pem && \
rustup target add x86_64-fortanix-unknown-sgx && \
echo "======== build tx-query2-enclave-app =========" && \
$(CARGO_BUILD_CMD) --target=x86_64-fortanix-unknown-sgx -p tx-query2-enclave-app && \
ftxsgx-elf2sgxs ./target/x86_64-fortanix-unknown-sgx/$(build_mode)/tx-query2-enclave-app --output ./target/$(build_mode)/tx-query2-enclave-app.sgxs --heap-size 0x2000000 --stack-size 0x80000 --threads 6 --debug && \
sgxs-sign --key ./sgx.pem ./target/$(build_mode)/tx-query2-enclave-app.sgxs ./target/$(build_mode)/tx-query2-enclave-app.sig -d --xfrm 7/0 --isvprodid $$(( 16#$(NETWORK_ID) )) --isvsvn 0 && \
export TQE_SIGSTRUCT=./target/$(build_mode)/tx-query2-enclave-app.sig && \
export TQE_MRENCLAVE=`od -A none -t x1 --read-bytes=32 -j 960 -w32 $$TQE_SIGSTRUCT | tr -d " "` && \
export MRSIGNER=`dd if=$$TQE_SIGSTRUCT bs=1 skip=128 count=384 status=none | sha256sum | cut -d" " -f1` && \
echo "======== build dev-utils =========" && \
${CARGO_BUILD_CMD} --bin dev-utils && \
./target/$(build_mode)/dev-utils genesis light --genesis_dev_config_path $(DEV_CONF) > chain-tx-enclave-next/tdbe/enclave-app/src/light_genesis.json && \
echo "======== build tdb-enclave-app =========" && \
$(CARGO_BUILD_CMD) --target x86_64-fortanix-unknown-sgx --package tdb-enclave-app && \
ftxsgx-elf2sgxs ./target/x86_64-fortanix-unknown-sgx/$(build_mode)/tdb-enclave-app --output ./target/$(build_mode)/tdb-enclave-app.sgxs --heap-size 0x2000000 --stack-size 0x80000 --threads 6 --debug && \
sgxs-sign --key ./sgx.pem ./target/$(build_mode)/tdb-enclave-app.sgxs ./target/$(build_mode)/tdb-enclave-app.sig -d --xfrm 7/0 --isvprodid $$(( 16#$(NETWORK_ID) )) --isvsvn 0 && \
export TDBE_SIGSTRUCT=./target/$(build_mode)/tdb-enclave-app.sig && \
dd if=$$TDBE_SIGSTRUCT bs=960 skip=1 | dd bs=32 count=1 > ./chain-tx-enclave-next/tx-validation-next/src/tdbe.mrenclave && \
echo "======== build ra-sp-server =========" && \
$(CARGO_BUILD_CMD) -p ra-sp-server && \
echo "======== build tx-validation-next =========" && \
$(CARGO_BUILD_CMD) --target x86_64-fortanix-unknown-sgx -p tx-validation-next && \
echo "======== run ftxsgx-elf2sgxs =========" && \
ftxsgx-elf2sgxs ./target/x86_64-fortanix-unknown-sgx/$(build_mode)/tx-validation-next --output ./target/$(build_mode)/tx-validation-next.sgxs --heap-size 0x20000000 --stack-size 0x40000 --threads 2 --debug && \
echo "======== run sgxs-sign tx-validation-next =========" && \
sgxs-sign --key ./sgx.pem ./target/$(build_mode)/tx-validation-next.sgxs ./target/$(build_mode)/tx-validation-next.sig -d --xfrm 7/0 --isvprodid $$(( 16#$(NETWORK_ID) )) --isvsvn 0'; \
fi
create-network:
@if [ `docker network ls -f NAME=$(NETWORK) | wc -l ` -eq 2 ]; then \
echo "network already exist"; \
else \
docker network create $(NETWORK); \
fi
rm-network:
@echo "\033\[32mremove network ${NETWORK}\033[0m"
docker network rm $(NETWORK)
run-abci: check-sgx-device
@if [ "${SPID}x" = "x" ] || [ "${IAS_API_KEY}x" = "x" ]; then \
echo "environment SPID and IAS_API_KEY should be set"; \
else \
echo "\033[32mrun docker chain-abci\033[0m"; \
docker run -d \
--net $(NETWORK) \
--restart=always \
-e RUST_LOG=$(RUST_LOG) \
-e SGX_MODE=$(SGX_MODE) \
-e NETWORK_ID=$(NETWORK_ID) \
-e CHAIN_ID=$(CHAIN_ID) \
-e PREFIX=$(prefix) \
-e TX_QUERY_HOSTNAME=$(TX_QUERY_HOSTNAME) \
-e APP_HASH=$(APP_HASH) \
-e SPID=${SPID} \
-e IAS_KEY=${IAS_API_KEY} \
--name $(prefix)chain-abci \
-v $(data_path):/crypto-chain \
--device $(SGX_DEVICE) \
-p $(TX_QUERY_PORT):26651 \
--workdir=/usr/local/bin \
$(IMAGE):$(TAG) \
bash ./run_chain_abci.sh; \
fi
run-tendermint:
@echo "\033[32mrun docker tendermint\033[0m"; \
docker run -d \
--net $(NETWORK) \
--restart=always \
--name $(prefix)tendermint \
--user root \
-v $(data_path)/tendermint:/tendermint \
-p $(TENDERMINT_P2P_PORT):26656 \
-p $(TENDERMINT_RPC_PORT):26657 \
-p $(TENDERMINT_PMS_PORT):26660 \
$(IMAGE_TENDERMINT) \
node --proxy_app=$(prefix)chain-abci:26658 \
--rpc.laddr=tcp://0.0.0.0:26657 \
--consensus.create_empty_blocks=true
run-client-rpc: set-genesis-fingerprint
@echo "\033[32mrun docker client-rpc\033[0m"; \
docker run -d \
--net $(NETWORK) \
--restart=always \
-e RUST_LOG=$(RUST_LOG) \
-e CRYPTO_GENESIS_FINGERPRINT=$(CRYPTO_GENESIS_FINGERPRINT) \
--name $(prefix)client-rpc \
-v $(data_path)/wallet:/crypto-chain/wallet \
-p $(CLIENT_RPC_PORT):26659 \
$(IMAGE):$(TAG) \
client-rpc \
--port=26659 \
--chain-id=$(CHAIN_ID) \
--storage-dir=/crypto-chain/wallet \
--disable-light-client \
--websocket-url=ws://$(prefix)tendermint:26657/websocket
set-genesis-fingerprint:
ifeq ($(chain), devnet)
@if [ $$(dpkg-query -W -f='$${Status}' libudev-dev 2>/dev/null | grep -c "ok installed") -eq 0 ]; \
then \
sudo apt update && \
sudo apt install libudev-dev -y; \
fi;
$(eval CRYPTO_GENESIS_FINGERPRINT=$(shell ./target/$(build_mode)/dev-utils genesis fingerprint -t ./docker/config/devnet/tendermint/genesis.json))
endif
@echo "CRYPTO_GENESIS_FINGERPRINT = \033[32m$(CRYPTO_GENESIS_FINGERPRINT)\033[0m";
.PHONY: chain-abci tendermint client-rpc
START = $(patsubst %, start-%, $(ITEMS_START))
RESTART = $(patsubst %, restart-%, $(ITEMS_START))
STOP = $(patsubst %, stop-%, $(ITEMS_STOP))
REMOVE = $(patsubst %, rm-%, $(ITEMS_STOP))
start-%: %
@echo "\033[32mstart $(prefix)$<...\033[0m" && docker start $(prefix)$< || echo "start $< failed";
stop-%: %
@echo "\033[32mstop $(prefix)$<...\033[0m" && docker stop $(prefix)$< || echo "$< does not exist";
restart-%: %
@echo "\033[32mrestart $(prefix)$<...\033[0m" && docker restart $(prefix)$< || echo "$< does not exist";
rm-%: %
@echo "\033[32mrm $(prefix)$<...\033[0m" && docker rm -f $(prefix)$< || echo "";
start-all: $(START)
stop-all: $(STOP)
rm-all: $(REMOVE)
restart-all: $(RESTART)
stop-chain:
@echo "\033[32mstop $(prefix)chient-rpc...\033[0m" && docker stop $(prefix)client-rpc || echo "client-rpc does not exist";
@echo "\033[32mstop $(prefix)tendermint...\033[0m" && docker stop $(prefix)tendermint || echo "tendermint does not exist";
@echo "\033[32mstop $(prefix)chain-abci...\033[0m" && docker stop $(prefix)chain-abci || echo "chain-abci does not exist";
clean-data:
docker run -i --rm \
-v $(data_path):/data \
--user root \
$(IMAGE):$(TAG) \
bash -c "rm -rf /data/{enclave-storage/*,chain-storage/*,wallet/*}"
docker run -i --rm \
-v $(data_path)/tendermint:/tendermint \
--user root \
$(IMAGE_TENDERMINT) unsafe_reset_all
rmi:
docker rmi $(prefix)crypto-sgx:$(TAG) $(prefix)crypto-chain:$(TAG)
clean:
@echo "\033[32mclean chain\033[0m";
docker run -i --rm \
-v `pwd`:/chain \
--workdir=/chain \
${IMAGE_RUST}:latest \
bash -c ". /root/.docker_bashrc && cargo clean"
prepare: create-path install-isgx-driver init-tendermint
build-sgx: build-sgx-query-validation-next build-chain
build: build-sgx build-chain
run-chain: create-network run-tendermint run-abci run-client-rpc
run: run-chain
.DEFAULT_GOAL :=
default: help
help:
@echo "A makefile based tool to prepare the environment, build binaries, launch a chain cluster \n\
\n\
USAGE:\n\
make [OPTIONS] <SUBCOMMAND>\n\
\n\
OPTIONS:\n\
data_path=<DATA_PATH> where the chain data storage, default is /tmp/data\n\
base_port=<BASE_PORT> set the base port so that the middleware's port can be \n\
set based on the port, default is 26650\n\
RUST_LOG=<LOG_LEVEL> debug | info | warn | error, the log level, default is debug\n\
chain=<CHAIN_TYPE> devnet | testnet | mainnet, default is devnet\n\
prefix=<PREFIX> default is empty, when create a docker, you can add a prefix on the docker name,\n\
it's useful when you want to create a multiple chain node on one host\n\
sgx_mode=<MODE> HW | SW, default is HW\n\
tag=<TAG> the chain version used in docker image, if not set, it will use\n\
the current git tag or develop if no tag found\n\
build_mode=<BUILD_MODE> debug | release, default is debug\n\
\n\
SUBCOMMAND:\n\
prepare prepare the environment\n\
image build the docker image\n\
build just build the chain and enclave binaery in docker\n\
run-chain docker run chain-abci, tendermint and client-rpc container\n\
stop-all docker stop all the container\n\
start-all docker start all the container\n\
restart-all docker restart all the container\n\
rm-all remove all the docker container\n\
clean clean all the temporary files while compiling\n\
clean-data remove all the data in data_path\n\
rm-dcap-sgx-driver remove dcap sgx driver if it is pre-installed in azure sgx machine\n\
\n\
EXAMPLE:\n\
\n\
make data_path=~/data chain_type=devnet prepare\n\
make tag=v0.2.0 image\n\
make data_path=~/data prefix=node0- base_port=16650 run-chain\n\
make prefix=node0- rm-all\n\
make data_path=~/data clean-code\n\
"