From 850bf088334553420eaa2d3ccf2d078ecefae5a0 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 7 Jul 2021 16:47:44 -0300 Subject: [PATCH 01/17] First attempt at replacing serve-4bytes with a nginx docker container drop-in --- Dockerfile-4bytes | 3 +++ nginx-4bytes.conf | 50 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 6 ++++-- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 Dockerfile-4bytes create mode 100644 nginx-4bytes.conf diff --git a/Dockerfile-4bytes b/Dockerfile-4bytes new file mode 100644 index 0000000..9d308d9 --- /dev/null +++ b/Dockerfile-4bytes @@ -0,0 +1,3 @@ +FROM nginx:1.21.1-alpine +COPY 4bytes/signatures /usr/share/nginx/html/ +COPY nginx-4bytes.conf /etc/nginx/conf.d/default.conf diff --git a/nginx-4bytes.conf b/nginx-4bytes.conf new file mode 100644 index 0000000..6060f2b --- /dev/null +++ b/nginx-4bytes.conf @@ -0,0 +1,50 @@ +server { + listen 80; + server_name localhost; + + #access_log /var/log/nginx/host.access.log main; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + + # Base on: https://michielkalkman.com/snippets/nginx-cors-open-configuration/ + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + # + # Om nom nom cookies + # + add_header 'Access-Control-Allow-Credentials' 'true'; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS'; + + # + # Custom headers and headers various browsers *should* be OK with but aren't + # + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + + # + # Tell client that this pre-flight info is valid for 20 days + # + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + if ($request_method = 'GET') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Credentials' 'true'; + add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + } + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + +} \ No newline at end of file diff --git a/package.json b/package.json index 841d6f1..7191a55 100644 --- a/package.json +++ b/package.json @@ -42,9 +42,11 @@ "build": "craco build", "test": "craco test", "eject": "react-scripts eject", - "serve-4bytes": "serve -p 3001 -C -c serve-4bytes.json", + "start-4bytes": "docker run --rm -p 3001:80 --name otterscan-4bytes -d otterscan/4bytes", + "stop-4bytes": "docker stop otterscan-4bytes", "serve-trustwallet-assets": "serve -p 3002 -C -c serve-trustwallet-assets.json", - "serve": "serve -s build" + "serve": "serve -s build", + "build-docker-4bytes": "docker build -t otterscan/4bytes -f Dockerfile-4bytes ." }, "eslintConfig": { "extends": [ From 97e542f51e9061f293de633e9a825926623e6f39 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 7 Jul 2021 16:51:52 -0300 Subject: [PATCH 02/17] Change 4bytes subdirectory in preparation for adding trustwallet asset to the same image --- Dockerfile-4bytes | 2 +- src/components/MethodName.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile-4bytes b/Dockerfile-4bytes index 9d308d9..651cb25 100644 --- a/Dockerfile-4bytes +++ b/Dockerfile-4bytes @@ -1,3 +1,3 @@ FROM nginx:1.21.1-alpine -COPY 4bytes/signatures /usr/share/nginx/html/ +COPY 4bytes/signatures /usr/share/nginx/html/signatures/ COPY nginx-4bytes.conf /etc/nginx/conf.d/default.conf diff --git a/src/components/MethodName.tsx b/src/components/MethodName.tsx index 70742e0..27ad8ca 100644 --- a/src/components/MethodName.tsx +++ b/src/components/MethodName.tsx @@ -16,7 +16,7 @@ const MethodName: React.FC = ({ data }) => { // Try to resolve 4bytes name const fourBytes = _name.slice(2); - const signatureURL = `http://localhost:3001/${fourBytes}`; + const signatureURL = `http://localhost:3001/signatures/${fourBytes}`; fetch(signatureURL) .then(async (res) => { if (!res.ok) { From cf581e1ab565eaab438804176f64b86206f437ca Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 7 Jul 2021 16:59:49 -0300 Subject: [PATCH 03/17] Merge trustwallet assets to the same docker image --- Dockerfile | 4 ++++ Dockerfile-4bytes | 3 --- nginx-4bytes.conf => nginx.conf | 0 package.json | 7 +++---- serve-4bytes.json | 15 --------------- serve-trustwallet-assets.json | 15 --------------- src/components/TokenLogo.tsx | 2 +- 7 files changed, 8 insertions(+), 38 deletions(-) create mode 100644 Dockerfile delete mode 100644 Dockerfile-4bytes rename nginx-4bytes.conf => nginx.conf (100%) delete mode 100644 serve-4bytes.json delete mode 100644 serve-trustwallet-assets.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8e0062e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:1.21.1-alpine +COPY 4bytes/signatures /usr/share/nginx/html/signatures/ +COPY trustwallet/blockchains/ethereum/assets /usr/share/nginx/html/assets/ +COPY nginx.conf /etc/nginx/conf.d/default.conf diff --git a/Dockerfile-4bytes b/Dockerfile-4bytes deleted file mode 100644 index 651cb25..0000000 --- a/Dockerfile-4bytes +++ /dev/null @@ -1,3 +0,0 @@ -FROM nginx:1.21.1-alpine -COPY 4bytes/signatures /usr/share/nginx/html/signatures/ -COPY nginx-4bytes.conf /etc/nginx/conf.d/default.conf diff --git a/nginx-4bytes.conf b/nginx.conf similarity index 100% rename from nginx-4bytes.conf rename to nginx.conf diff --git a/package.json b/package.json index 7191a55..8e8031c 100644 --- a/package.json +++ b/package.json @@ -42,11 +42,10 @@ "build": "craco build", "test": "craco test", "eject": "react-scripts eject", - "start-4bytes": "docker run --rm -p 3001:80 --name otterscan-4bytes -d otterscan/4bytes", - "stop-4bytes": "docker stop otterscan-4bytes", - "serve-trustwallet-assets": "serve -p 3002 -C -c serve-trustwallet-assets.json", + "start-docker": "docker run --rm -p 3001:80 --name otterscan -d otterscan", + "stop-docker": "docker stop otterscan", "serve": "serve -s build", - "build-docker-4bytes": "docker build -t otterscan/4bytes -f Dockerfile-4bytes ." + "build-docker": "docker build -t otterscan -f Dockerfile ." }, "eslintConfig": { "extends": [ diff --git a/serve-4bytes.json b/serve-4bytes.json deleted file mode 100644 index 3d0abde..0000000 --- a/serve-4bytes.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "public": "4bytes/signatures", - "headers": [ - { - "source": "**", - "headers": [ - { - "key": "Cache-Control", - "value": "max-age=600" - } - ] - } - ], - "directoryListing": false -} \ No newline at end of file diff --git a/serve-trustwallet-assets.json b/serve-trustwallet-assets.json deleted file mode 100644 index 967698d..0000000 --- a/serve-trustwallet-assets.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "public": "trustwallet/blockchains/ethereum/assets", - "headers": [ - { - "source": "**", - "headers": [ - { - "key": "Cache-Control", - "value": "max-age=600" - } - ] - } - ], - "directoryListing": false -} \ No newline at end of file diff --git a/src/components/TokenLogo.tsx b/src/components/TokenLogo.tsx index 7905185..738de1c 100644 --- a/src/components/TokenLogo.tsx +++ b/src/components/TokenLogo.tsx @@ -15,7 +15,7 @@ const TokenLogo: React.FC = (props) => ( const InternalTokenLogo: React.FC = ({ address, name }) => { const { src } = useImage({ srcList: [ - `http://localhost:3002/${address}/logo.png`, + `http://localhost:3001/assets/${address}/logo.png`, "/eth-diamond-black.png", ], }); From 73779426c508cb2af405825eb0fa79d73f850d5f Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 7 Jul 2021 17:45:37 -0300 Subject: [PATCH 04/17] Merge the entire distribution into one unique docker image --- .dockerignore | 1 + Dockerfile | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +node_modules diff --git a/Dockerfile b/Dockerfile index 8e0062e..b6c325f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,13 @@ +FROM node:12.22.3-alpine AS builder +WORKDIR /otterscan-build +COPY ["package*.json", "tsconfig.json", "craco.config.js", "tailwind.config.js", "/otterscan-build"] +COPY ["src", "/otterscan-build/src"] +COPY ["public", "/otterscan-build/public"] +RUN npm install +RUN npm run build + FROM nginx:1.21.1-alpine COPY 4bytes/signatures /usr/share/nginx/html/signatures/ COPY trustwallet/blockchains/ethereum/assets /usr/share/nginx/html/assets/ COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=builder /otterscan-build/build /usr/share/nginx/html/ From d8c100371ea4f3e476a1794d6f1bf86fecc30d48 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 7 Jul 2021 18:09:22 -0300 Subject: [PATCH 05/17] Change production build run port --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 8e8031c..3c596f7 100644 --- a/package.json +++ b/package.json @@ -42,9 +42,8 @@ "build": "craco build", "test": "craco test", "eject": "react-scripts eject", - "start-docker": "docker run --rm -p 3001:80 --name otterscan -d otterscan", + "start-docker": "docker run --rm -p 5000:80 --name otterscan -d otterscan", "stop-docker": "docker stop otterscan", - "serve": "serve -s build", "build-docker": "docker build -t otterscan -f Dockerfile ." }, "eslintConfig": { From 8b2e8abbf45fc835003a4d63e9091e4d33f7297b Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 7 Jul 2021 18:55:54 -0300 Subject: [PATCH 06/17] Update dockerized instructions --- README.md | 63 +++++++++++++++++++++++++++++++++++++++------------- package.json | 4 +++- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 8852ea2..b049ba5 100644 --- a/README.md +++ b/README.md @@ -107,9 +107,29 @@ Also pay attention to the `--http.corsdomain` parameter, CORS is required for th Now you should have an Erigon node with Otterscan jsonrpc APIs enabled, running in dual mode with CORS enabled. -### Clone Otterscan repository and build the project +### Run Otterscan docker image from Docker Hub -Make sure you have a working node 12/npm installation. +TODO: publish Otterscan official images as soon as it is validated. + +``` +docker run --rm -p 5000:80 --name otterscan -d otterscan/otterscan: +``` + +This will download the Otterscan image from Docker Hub, run it locally using the default parameters, binding it to port 5000 (see the `-p` docker run parameter). + +To stop Otterscan service, run: + +``` +docker stop otterscan +``` + +### (Alternative) Build Otterscan docker image locally and run it + +If you don't want to download from Docker Hub, you can build the docker image from the sources and run it. + +If you just want to build the image locally, there is no need to install the development toolchain, just make sure you have a recent working Docker installation. + +The entire build process will take place inside the docker multi-stage build. Clone Otterscan repo and its submodules. Checkout the tag corresponding to your Erigon + Otterscan patches. It uses the same version tag from Erigon + Otterscan repo, i.e., if you built the `v2021.07.01-otterscan`, you should build the `v2021.07.01-otterscan` of Otterscan. @@ -117,19 +137,19 @@ Clone Otterscan repo and its submodules. Checkout the tag corresponding to your git clone --recurse-submodules git@github.com:wmitsuda/otterscan.git cd otterscan git checkout -npm install -npm run build +docker build -t otterscan -f Dockerfile . ``` -By default, it assumes your Erigon `rpcdaemon` processs is serving requests at http://127.0.0.1:8545. You can customize this URL by specifying the `REACT_APP_ERIGON_URL` environment variable at build time (it needs to be done at build time because the build process generates a static website). +This will run the entire build process inside a build container, merge the production build of the React app with the 4bytes and trustwallet assets into the same image format it is published in Docker Hub, but locally under the name `otterscan`. -To do that, export the variable before running `npm run build`: +Then you can start/stop it using the commands: ``` -export REACT_APP_ERIGON_URL= +docker run --rm -p 5000:80 --name otterscan -d otterscan +docker stop otterscan ``` -### Run it from the source +### Run a development build from the source First, a brief explanation about the app: @@ -141,25 +161,38 @@ First, a brief explanation about the app: These instructions are subjected to changes in future for the sake of simplification. -Open a new terminal and start the 4bytes method decoding service: +Make sure you have a working node 12/npm installation. + +By default, it assumes your Erigon `rpcdaemon` processs is serving requests at http://127.0.0.1:8545. You can customize this URL by specifying the `REACT_APP_ERIGON_URL` environment variable at build time (it needs to be done at build time because the build process generates a static website). + +To do that, export the variable before running `npm run build`: ``` -npm run serve-4bytes +export REACT_APP_ERIGON_URL= ``` -Open another terminal and start the trustwallet assets service: +Start serving 4bytes and trustwallet assets at `localhost:3001` using a dockerized nginx: ``` -npm run serve-trustwallet-assets +npm run start-assets ``` -In another terminal start the Otterscan app: +To stop it, run: ``` -npm run serve +npm run stop-assets ``` -Otterscan should now be running at http://localhost:5000/. +To run Otterscan development build: + +``` +npm install +npm start +``` + +Otterscan should now be running at http://localhost:3000/. + +## Validating the installation (all methods) **You can make sure it is working correctly if the homepage is able to show the latest block/timestamp your Erigon node is at just bellow the search button.** diff --git a/package.json b/package.json index 3c596f7..80a67b1 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,9 @@ "eject": "react-scripts eject", "start-docker": "docker run --rm -p 5000:80 --name otterscan -d otterscan", "stop-docker": "docker stop otterscan", - "build-docker": "docker build -t otterscan -f Dockerfile ." + "build-docker": "docker build -t otterscan -f Dockerfile .", + "start-assets": "docker run --rm -p 3001:80 --name otterscan-assets -d -v$(pwd)/4bytes/signatures:/usr/share/nginx/html/signatures/ -v$(pwd)/trustwallet/blockchains/ethereum/assets:/usr/share/nginx/html/assets nginx:1.21.1-alpine", + "stop-assets": "docker stop otterscan-assets" }, "eslintConfig": { "extends": [ From 7eb91be28676d868647b8dd2241ea507696178b4 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 7 Jul 2021 19:44:17 -0300 Subject: [PATCH 07/17] Small doc fixes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b049ba5..3fcf9e2 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ To stop Otterscan service, run: docker stop otterscan ``` -### (Alternative) Build Otterscan docker image locally and run it +### (Alternative 1) Build Otterscan docker image locally and run it If you don't want to download from Docker Hub, you can build the docker image from the sources and run it. @@ -149,7 +149,7 @@ docker run --rm -p 5000:80 --name otterscan -d otterscan docker stop otterscan ``` -### Run a development build from the source +### (Alternative 2) Run a development build from the source First, a brief explanation about the app: From d5d5407eee14b1df8d2a07a0d030297a762a7cfe Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Wed, 7 Jul 2021 21:57:03 -0300 Subject: [PATCH 08/17] Add hack to write params on container start --- .dockerignore | 2 ++ Dockerfile | 7 ++++++- run-nginx.sh | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100755 run-nginx.sh diff --git a/.dockerignore b/.dockerignore index 3c3629e..996deec 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,3 @@ node_modules +trustwallet +!trustwallet/blockchains/ethereum/assets diff --git a/Dockerfile b/Dockerfile index b6c325f..5062957 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,18 @@ FROM node:12.22.3-alpine AS builder WORKDIR /otterscan-build -COPY ["package*.json", "tsconfig.json", "craco.config.js", "tailwind.config.js", "/otterscan-build"] +COPY ["run-nginx.sh", "package*.json", "tsconfig.json", "craco.config.js", "tailwind.config.js", "/otterscan-build"] COPY ["src", "/otterscan-build/src"] COPY ["public", "/otterscan-build/public"] RUN npm install RUN npm run build FROM nginx:1.21.1-alpine +RUN apk add jq COPY 4bytes/signatures /usr/share/nginx/html/signatures/ COPY trustwallet/blockchains/ethereum/assets /usr/share/nginx/html/assets/ COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --from=builder /otterscan-build/build /usr/share/nginx/html/ +COPY --from=builder /otterscan-build/run-nginx.sh / +WORKDIR / + +CMD ["/run-nginx.sh"] diff --git a/run-nginx.sh b/run-nginx.sh new file mode 100755 index 0000000..57cf41d --- /dev/null +++ b/run-nginx.sh @@ -0,0 +1,4 @@ +#!/bin/sh +PARAMS=`echo "{\"erigonURL\": \"$ERIGON_URL\"}" | jq -aRs .` +echo $PARAMS > /usr/share/nginx/html/config.json +nginx -g "daemon off;" From 8b373d3718e3a92bd2a21fca7d46ff1d653c83f2 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 8 Jul 2021 00:46:34 -0300 Subject: [PATCH 09/17] Updated 4bytes repo --- 4bytes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/4bytes b/4bytes index bea447b..3fde3a1 160000 --- a/4bytes +++ b/4bytes @@ -1 +1 @@ -Subproject commit bea447b61551c329215bf11dcf4c57b62210de8a +Subproject commit 3fde3a1b2e002736e9a5e0c35df5bbe386a18d55 From 3d4f743e4d3d82b117b1763b9a80787d4890374f Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 8 Jul 2021 01:02:16 -0300 Subject: [PATCH 10/17] Reorder scripts --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 80a67b1..78a0af0 100644 --- a/package.json +++ b/package.json @@ -42,11 +42,11 @@ "build": "craco build", "test": "craco test", "eject": "react-scripts eject", - "start-docker": "docker run --rm -p 5000:80 --name otterscan -d otterscan", - "stop-docker": "docker stop otterscan", - "build-docker": "docker build -t otterscan -f Dockerfile .", "start-assets": "docker run --rm -p 3001:80 --name otterscan-assets -d -v$(pwd)/4bytes/signatures:/usr/share/nginx/html/signatures/ -v$(pwd)/trustwallet/blockchains/ethereum/assets:/usr/share/nginx/html/assets nginx:1.21.1-alpine", - "stop-assets": "docker stop otterscan-assets" + "stop-assets": "docker stop otterscan-assets", + "build-docker": "docker build -t otterscan -f Dockerfile .", + "start-docker": "docker run --rm -p 5000:80 --name otterscan -d otterscan", + "stop-docker": "docker stop otterscan" }, "eslintConfig": { "extends": [ From f905561dc4fc93b8ee195d5352c31156414cd163 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 8 Jul 2021 01:50:39 -0300 Subject: [PATCH 11/17] Ignore more patterns --- .dockerignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.dockerignore b/.dockerignore index 996deec..df120e1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,6 @@ +.git node_modules +4bytes +!4bytes/signatures trustwallet !trustwallet/blockchains/ethereum/assets From 1a14f4fc9d6f51a08e18f3edcaf2e0110f8c0bf7 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 8 Jul 2021 01:50:55 -0300 Subject: [PATCH 12/17] Deprecate backticks --- run-nginx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run-nginx.sh b/run-nginx.sh index 57cf41d..9cb8352 100755 --- a/run-nginx.sh +++ b/run-nginx.sh @@ -1,4 +1,4 @@ #!/bin/sh -PARAMS=`echo "{\"erigonURL\": \"$ERIGON_URL\"}" | jq -aRs .` +PARAMS=$(echo "{\"erigonURL\": \"$ERIGON_URL\"}" | jq -aRs .) echo $PARAMS > /usr/share/nginx/html/config.json nginx -g "daemon off;" From 3a185057538a14850bd94fbdbab5a7c187f28750 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 8 Jul 2021 02:14:33 -0300 Subject: [PATCH 13/17] Reorder commands to better exploit docker build cache --- Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5062957..eecfd43 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,10 @@ FROM node:12.22.3-alpine AS builder WORKDIR /otterscan-build -COPY ["run-nginx.sh", "package*.json", "tsconfig.json", "craco.config.js", "tailwind.config.js", "/otterscan-build"] -COPY ["src", "/otterscan-build/src"] -COPY ["public", "/otterscan-build/public"] +COPY ["package.json", "package-lock.json", "/otterscan-build"] RUN npm install +COPY ["run-nginx.sh", "tsconfig.json", "craco.config.js", "tailwind.config.js", "/otterscan-build"] +COPY ["public", "/otterscan-build/public"] +COPY ["src", "/otterscan-build/src"] RUN npm run build FROM nginx:1.21.1-alpine From 3e58030a43560f93d22190010dd3f0400f358eca Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 8 Jul 2021 15:05:56 -0300 Subject: [PATCH 14/17] Fix cors for local run --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 78a0af0..e069e95 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "build": "craco build", "test": "craco test", "eject": "react-scripts eject", - "start-assets": "docker run --rm -p 3001:80 --name otterscan-assets -d -v$(pwd)/4bytes/signatures:/usr/share/nginx/html/signatures/ -v$(pwd)/trustwallet/blockchains/ethereum/assets:/usr/share/nginx/html/assets nginx:1.21.1-alpine", + "start-assets": "docker run --rm -p 3001:80 --name otterscan-assets -d -v$(pwd)/4bytes/signatures:/usr/share/nginx/html/signatures/ -v$(pwd)/trustwallet/blockchains/ethereum/assets:/usr/share/nginx/html/assets -v$(pwd)/nginx.conf:/etc/nginx/conf.d/default.conf nginx:1.21.1-alpine", "stop-assets": "docker stop otterscan-assets", "build-docker": "docker build -t otterscan -f Dockerfile .", "start-docker": "docker run --rm -p 5000:80 --name otterscan -d otterscan", From da16ce8ad69312db8f3cc34a3cd8e3ab8c9f18b6 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda Date: Thu, 8 Jul 2021 16:02:42 -0300 Subject: [PATCH 15/17] Parameterize erigon node url --- public/config.json | 3 ++ src/AddressTransactions.tsx | 37 +++++++++++++++------ src/App.tsx | 65 ++++++++++++++++++++----------------- src/Block.tsx | 13 +++++--- src/BlockTransactions.tsx | 13 +++++--- src/Home.tsx | 13 +++++--- src/Transaction.tsx | 21 +++++++++--- src/ethersconfig.ts | 9 ----- src/search/search.ts | 47 ++++++++++++++++++++------- src/useErigon.ts | 25 ++++++++++++++ src/useLatestBlock.ts | 19 ++++++++--- src/useProvider.ts | 26 +++++++++++++++ src/useReverseCache.ts | 11 ++++--- 13 files changed, 216 insertions(+), 86 deletions(-) create mode 100644 public/config.json delete mode 100644 src/ethersconfig.ts create mode 100644 src/useErigon.ts create mode 100644 src/useProvider.ts diff --git a/public/config.json b/public/config.json new file mode 100644 index 0000000..d602ced --- /dev/null +++ b/public/config.json @@ -0,0 +1,3 @@ +{ + "erigonURL": "http://localhost:8545" +} \ No newline at end of file diff --git a/src/AddressTransactions.tsx b/src/AddressTransactions.tsx index 03011cf..f080b96 100644 --- a/src/AddressTransactions.tsx +++ b/src/AddressTransactions.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useMemo } from "react"; +import React, { useState, useEffect, useMemo, useContext } from "react"; import { useParams, useLocation, useHistory } from "react-router-dom"; import { ethers } from "ethers"; import queryString from "query-string"; @@ -12,9 +12,9 @@ import ResultHeader from "./search/ResultHeader"; import PendingResults from "./search/PendingResults"; import TransactionItem from "./search/TransactionItem"; import { SearchController } from "./search/search"; +import { ProviderContext } from "./useProvider"; import { useENSCache } from "./useReverseCache"; import { useFeeToggler } from "./search/useFeeToggler"; -import { provider } from "./ethersconfig"; type BlockParams = { addressOrName: string; @@ -26,6 +26,7 @@ type PageParams = { }; const AddressTransactions: React.FC = () => { + const provider = useContext(ProviderContext); const params = useParams(); const location = useLocation(); const history = useHistory(); @@ -59,6 +60,9 @@ const AddressTransactions: React.FC = () => { return; } + if (!provider) { + return; + } const resolveName = async () => { const resolvedAddress = await provider.resolveName(params.addressOrName); if (resolvedAddress !== null) { @@ -72,20 +76,30 @@ const AddressTransactions: React.FC = () => { } }; resolveName(); - }, [params.addressOrName, history, params.direction, location.search]); + }, [ + provider, + params.addressOrName, + history, + params.direction, + location.search, + ]); const [controller, setController] = useState(); useEffect(() => { - if (!checksummedAddress) { + if (!provider || !checksummedAddress) { return; } const readFirstPage = async () => { - const _controller = await SearchController.firstPage(checksummedAddress); + const _controller = await SearchController.firstPage( + provider, + checksummedAddress + ); setController(_controller); }; const readMiddlePage = async (next: boolean) => { const _controller = await SearchController.middlePage( + provider, checksummedAddress, hash!, next @@ -93,15 +107,18 @@ const AddressTransactions: React.FC = () => { setController(_controller); }; const readLastPage = async () => { - const _controller = await SearchController.lastPage(checksummedAddress); + const _controller = await SearchController.lastPage( + provider, + checksummedAddress + ); setController(_controller); }; const prevPage = async () => { - const _controller = await controller!.prevPage(hash!); + const _controller = await controller!.prevPage(provider, hash!); setController(_controller); }; const nextPage = async () => { - const _controller = await controller!.nextPage(hash!); + const _controller = await controller!.nextPage(provider, hash!); setController(_controller); }; @@ -127,10 +144,10 @@ const AddressTransactions: React.FC = () => { readLastPage(); } } - }, [checksummedAddress, params.direction, hash, controller]); + }, [provider, checksummedAddress, params.direction, hash, controller]); const page = useMemo(() => controller?.getPage(), [controller]); - const reverseCache = useENSCache(page); + const reverseCache = useENSCache(provider, page); document.title = `Address ${params.addressOrName} | Otterscan`; diff --git a/src/App.tsx b/src/App.tsx index 9082f6f..122081c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,40 +3,47 @@ import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import Home from "./Home"; import Search from "./Search"; import Title from "./Title"; +import { useProvider, ProviderContext } from "./useProvider"; const Block = React.lazy(() => import("./Block")); const BlockTransactions = React.lazy(() => import("./BlockTransactions")); const AddressTransactions = React.lazy(() => import("./AddressTransactions")); const Transaction = React.lazy(() => import("./Transaction")); -const App = () => ( - LOADING}> - - - - - - - - - - - <Route path="/block/:blockNumberOrHash" exact> - <Block /> - </Route> - <Route path="/block/:blockNumber/txs" exact> - <BlockTransactions /> - </Route> - <Route path="/tx/:txhash"> - <Transaction /> - </Route> - <Route path="/address/:addressOrName/:direction?"> - <AddressTransactions /> - </Route> - </Route> - </Switch> - </Router> - </Suspense> -); +const App = () => { + const provider = useProvider(); + + return ( + <Suspense fallback={<>LOADING</>}> + <ProviderContext.Provider value={provider}> + <Router> + <Switch> + <Route path="/" exact> + <Home /> + </Route> + <Route path="/search" exact> + <Search /> + </Route> + <Route> + <Title /> + <Route path="/block/:blockNumberOrHash" exact> + <Block /> + </Route> + <Route path="/block/:blockNumber/txs" exact> + <BlockTransactions /> + </Route> + <Route path="/tx/:txhash"> + <Transaction /> + </Route> + <Route path="/address/:addressOrName/:direction?"> + <AddressTransactions /> + </Route> + </Route> + </Switch> + </Router> + </ProviderContext.Provider> + </Suspense> + ); +}; export default React.memo(App); diff --git a/src/Block.tsx b/src/Block.tsx index 9fd6e25..6f9ab22 100644 --- a/src/Block.tsx +++ b/src/Block.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useMemo } from "react"; +import React, { useEffect, useState, useMemo, useContext } from "react"; import { useParams, NavLink } from "react-router-dom"; import { ethers, BigNumber } from "ethers"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -6,7 +6,6 @@ import { faChevronLeft, faChevronRight, } from "@fortawesome/free-solid-svg-icons"; -import { provider } from "./ethersconfig"; import StandardFrame from "./StandardFrame"; import StandardSubtitle from "./StandardSubtitle"; import ContentFrame from "./ContentFrame"; @@ -17,6 +16,7 @@ import BlockLink from "./components/BlockLink"; import AddressOrENSName from "./components/AddressOrENSName"; import TransactionValue from "./components/TransactionValue"; import HexValue from "./components/HexValue"; +import { ProviderContext } from "./useProvider"; import { useLatestBlockNumber } from "./useLatestBlock"; type BlockParams = { @@ -34,10 +34,15 @@ interface ExtendedBlock extends ethers.providers.Block { } const Block: React.FC = () => { + const provider = useContext(ProviderContext); const params = useParams<BlockParams>(); const [block, setBlock] = useState<ExtendedBlock>(); useEffect(() => { + if (!provider) { + return; + } + const readBlock = async () => { let blockPromise: Promise<any>; if (ethers.utils.isHexString(params.blockNumberOrHash, 32)) { @@ -80,7 +85,7 @@ const Block: React.FC = () => { setBlock(extBlock); }; readBlock(); - }, [params.blockNumberOrHash]); + }, [provider, params.blockNumberOrHash]); useEffect(() => { if (block) { @@ -97,7 +102,7 @@ const Block: React.FC = () => { } }, [block]); - const latestBlockNumber = useLatestBlockNumber(); + const latestBlockNumber = useLatestBlockNumber(provider); return ( <StandardFrame> diff --git a/src/BlockTransactions.tsx b/src/BlockTransactions.tsx index e5712c0..5e6d4ad 100644 --- a/src/BlockTransactions.tsx +++ b/src/BlockTransactions.tsx @@ -1,8 +1,7 @@ -import React, { useEffect, useState, useMemo } from "react"; +import React, { useEffect, useState, useMemo, useContext } from "react"; import { useParams, useLocation } from "react-router"; import { ethers } from "ethers"; import queryString from "query-string"; -import { provider } from "./ethersconfig"; import StandardFrame from "./StandardFrame"; import StandardSubtitle from "./StandardSubtitle"; import ContentFrame from "./ContentFrame"; @@ -14,6 +13,7 @@ import BlockLink from "./components/BlockLink"; import { ProcessedTransaction } from "./types"; import { PAGE_SIZE } from "./params"; import { useFeeToggler } from "./search/useFeeToggler"; +import { ProviderContext } from "./useProvider"; import { useENSCache } from "./useReverseCache"; type BlockParams = { @@ -25,6 +25,7 @@ type PageParams = { }; const BlockTransactions: React.FC = () => { + const provider = useContext(ProviderContext); const params = useParams<BlockParams>(); const location = useLocation<PageParams>(); const qs = queryString.parse(location.search); @@ -42,6 +43,10 @@ const BlockTransactions: React.FC = () => { const [txs, setTxs] = useState<ProcessedTransaction[]>(); useEffect(() => { + if (!provider) { + return; + } + const readBlock = async () => { const [_block, _receipts] = await Promise.all([ provider.getBlockWithTransactions(blockNumber.toNumber()), @@ -94,7 +99,7 @@ const BlockTransactions: React.FC = () => { setTxs(processedResponses); }; readBlock(); - }, [blockNumber]); + }, [provider, blockNumber]); const page = useMemo(() => { if (!txs) { @@ -105,7 +110,7 @@ const BlockTransactions: React.FC = () => { }, [txs, pageNumber]); const total = useMemo(() => txs?.length ?? 0, [txs]); - const reverseCache = useENSCache(page); + const reverseCache = useENSCache(provider, page); document.title = `Block #${blockNumber} Txns | Otterscan`; diff --git a/src/Home.tsx b/src/Home.tsx index 82c3cdb..9cc40fc 100644 --- a/src/Home.tsx +++ b/src/Home.tsx @@ -1,12 +1,13 @@ -import React, { useState } from "react"; +import React, { useState, useContext } from "react"; import { NavLink, useHistory } from "react-router-dom"; import { ethers } from "ethers"; import Logo from "./Logo"; import Timestamp from "./components/Timestamp"; +import { ProviderContext } from "./useProvider"; import { useLatestBlock } from "./useLatestBlock"; -import { ERIGON_NODE } from "./ethersconfig"; const Home: React.FC = () => { + const provider = useContext(ProviderContext); const [search, setSearch] = useState<string>(); const [canSubmit, setCanSubmit] = useState<boolean>(false); const history = useHistory(); @@ -25,7 +26,7 @@ const Home: React.FC = () => { history.push(`/search?q=${search}`); }; - const latestBlock = useLatestBlock(); + const latestBlock = useLatestBlock(provider); document.title = "Home | Otterscan"; @@ -65,7 +66,11 @@ const Home: React.FC = () => { </NavLink> )} <span className="mx-auto mt-5 text-xs text-gray-500"> - Using Erigon node at {ERIGON_NODE} + {provider ? ( + <>Using Erigon node at {provider.connection.url}</> + ) : ( + <>Waiting for the provider...</> + )} </span> </form> </div> diff --git a/src/Transaction.tsx b/src/Transaction.tsx index a461501..724fb31 100644 --- a/src/Transaction.tsx +++ b/src/Transaction.tsx @@ -1,4 +1,10 @@ -import React, { useState, useEffect, useCallback, useMemo } from "react"; +import React, { + useState, + useEffect, + useCallback, + useMemo, + useContext, +} from "react"; import { Route, Switch, useParams } from "react-router-dom"; import { BigNumber, ethers } from "ethers"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -6,7 +12,6 @@ import { faCheckCircle, faTimesCircle, } from "@fortawesome/free-solid-svg-icons"; -import { provider } from "./ethersconfig"; import StandardFrame from "./StandardFrame"; import StandardSubtitle from "./StandardSubtitle"; import Tab from "./components/Tab"; @@ -22,6 +27,7 @@ import FormattedBalance from "./components/FormattedBalance"; import TokenTransferItem from "./TokenTransferItem"; import erc20 from "./erc20.json"; import { TokenMetas, TokenTransfer, TransactionData, Transfer } from "./types"; +import { ProviderContext } from "./useProvider"; const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; @@ -31,11 +37,16 @@ type TransactionParams = { }; const Transaction: React.FC = () => { + const provider = useContext(ProviderContext); const params = useParams<TransactionParams>(); const { txhash } = params; const [txData, setTxData] = useState<TransactionData>(); useEffect(() => { + if (!provider) { + return; + } + const readBlock = async () => { const [_response, _receipt] = await Promise.all([ provider.getTransaction(txhash), @@ -109,7 +120,7 @@ const Transaction: React.FC = () => { }); }; readBlock(); - }, [txhash]); + }, [provider, txhash]); const [transfers, setTransfers] = useState<Transfer[]>(); const sendsEthToMiner = useMemo(() => { @@ -126,7 +137,7 @@ const Transaction: React.FC = () => { }, [txData, transfers]); const traceTransfersUsingOtsTrace = useCallback(async () => { - if (!txData) { + if (!provider || !txData) { return; } @@ -143,7 +154,7 @@ const Transaction: React.FC = () => { } setTransfers(_transfers); - }, [txData]); + }, [provider, txData]); useEffect(() => { traceTransfersUsingOtsTrace(); }, [traceTransfersUsingOtsTrace]); diff --git a/src/ethersconfig.ts b/src/ethersconfig.ts deleted file mode 100644 index a7a98a1..0000000 --- a/src/ethersconfig.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ethers } from "ethers"; - -export const ERIGON_NODE = - process.env.REACT_APP_ERIGON_URL || "http://127.0.0.1:8545"; - -export const provider = new ethers.providers.JsonRpcProvider( - ERIGON_NODE, - "mainnet" -); diff --git a/src/search/search.ts b/src/search/search.ts index 3fbcb3e..a78eb81 100644 --- a/src/search/search.ts +++ b/src/search/search.ts @@ -1,5 +1,4 @@ import { ethers } from "ethers"; -import { provider } from "../ethersconfig"; import { PAGE_SIZE } from "../params"; import { ProcessedTransaction, TransactionChunk } from "../types"; @@ -27,7 +26,10 @@ export class SearchController { } } - private static rawToProcessed = (_rawRes: any) => { + private static rawToProcessed = ( + provider: ethers.providers.JsonRpcProvider, + _rawRes: any + ) => { const _res: ethers.providers.TransactionResponse[] = _rawRes.txs.map( (t: any) => provider.formatter.transactionResponse(t) ); @@ -56,6 +58,7 @@ export class SearchController { }; private static async readBackPage( + provider: ethers.providers.JsonRpcProvider, address: string, baseBlock: number ): Promise<TransactionChunk> { @@ -64,10 +67,11 @@ export class SearchController { baseBlock, PAGE_SIZE, ]); - return this.rawToProcessed(_rawRes); + return this.rawToProcessed(provider, _rawRes); } private static async readForwardPage( + provider: ethers.providers.JsonRpcProvider, address: string, baseBlock: number ): Promise<TransactionChunk> { @@ -76,11 +80,14 @@ export class SearchController { baseBlock, PAGE_SIZE, ]); - return this.rawToProcessed(_rawRes); + return this.rawToProcessed(provider, _rawRes); } - static async firstPage(address: string): Promise<SearchController> { - const newTxs = await SearchController.readBackPage(address, 0); + static async firstPage( + provider: ethers.providers.JsonRpcProvider, + address: string + ): Promise<SearchController> { + const newTxs = await SearchController.readBackPage(provider, address, 0); return new SearchController( address, newTxs.txs, @@ -91,14 +98,19 @@ export class SearchController { } static async middlePage( + provider: ethers.providers.JsonRpcProvider, address: string, hash: string, next: boolean ): Promise<SearchController> { const tx = await provider.getTransaction(hash); const newTxs = next - ? await SearchController.readBackPage(address, tx.blockNumber!) - : await SearchController.readForwardPage(address, tx.blockNumber!); + ? await SearchController.readBackPage(provider, address, tx.blockNumber!) + : await SearchController.readForwardPage( + provider, + address, + tx.blockNumber! + ); return new SearchController( address, newTxs.txs, @@ -108,8 +120,11 @@ export class SearchController { ); } - static async lastPage(address: string): Promise<SearchController> { - const newTxs = await SearchController.readForwardPage(address, 0); + static async lastPage( + provider: ethers.providers.JsonRpcProvider, + address: string + ): Promise<SearchController> { + const newTxs = await SearchController.readForwardPage(provider, address, 0); return new SearchController( address, newTxs.txs, @@ -123,7 +138,10 @@ export class SearchController { return this.txs.slice(this.pageStart, this.pageEnd); } - async prevPage(hash: string): Promise<SearchController> { + async prevPage( + provider: ethers.providers.JsonRpcProvider, + hash: string + ): Promise<SearchController> { // Already on this page if (this.txs[this.pageEnd - 1].hash === hash) { return this; @@ -133,6 +151,7 @@ export class SearchController { const overflowPage = this.txs.slice(0, this.pageStart); const baseBlock = this.txs[0].blockNumber; const prevPage = await SearchController.readForwardPage( + provider, this.address, baseBlock ); @@ -148,7 +167,10 @@ export class SearchController { return this; } - async nextPage(hash: string): Promise<SearchController> { + async nextPage( + provider: ethers.providers.JsonRpcProvider, + hash: string + ): Promise<SearchController> { // Already on this page if (this.txs[this.pageStart].hash === hash) { return this; @@ -158,6 +180,7 @@ export class SearchController { const overflowPage = this.txs.slice(this.pageEnd); const baseBlock = this.txs[this.txs.length - 1].blockNumber; const nextPage = await SearchController.readBackPage( + provider, this.address, baseBlock ); diff --git a/src/useErigon.ts b/src/useErigon.ts new file mode 100644 index 0000000..bd64364 --- /dev/null +++ b/src/useErigon.ts @@ -0,0 +1,25 @@ +import { useState, useEffect } from "react"; + +export type OtterscanConfig = { + erigonURL: string; +}; + +export const useErigon = (): [boolean?, OtterscanConfig?] => { + const [configOK, setConfigOK] = useState<boolean>(); + const [config, setConfig] = useState<OtterscanConfig>(); + + useEffect(() => { + const readConfig = async () => { + const res = await fetch("/config.json"); + + if (res.ok) { + const _config: OtterscanConfig = await res.json(); + setConfig(_config); + setConfigOK(res.ok); + } + }; + readConfig(); + }, []); + + return [configOK, config]; +}; diff --git a/src/useLatestBlock.ts b/src/useLatestBlock.ts index fba4011..5ed444b 100644 --- a/src/useLatestBlock.ts +++ b/src/useLatestBlock.ts @@ -1,11 +1,14 @@ import { useState, useEffect } from "react"; import { ethers } from "ethers"; -import { provider } from "./ethersconfig"; -export const useLatestBlock = () => { +export const useLatestBlock = (provider?: ethers.providers.JsonRpcProvider) => { const [latestBlock, setLatestBlock] = useState<ethers.providers.Block>(); useEffect(() => { + if (!provider) { + return; + } + const readLatestBlock = async () => { const blockNum = await provider.getBlockNumber(); const _raw = await provider.send("erigon_getHeaderByNumber", [blockNum]); @@ -26,15 +29,21 @@ export const useLatestBlock = () => { return () => { provider.removeListener("block", listener); }; - }, []); + }, [provider]); return latestBlock; }; -export const useLatestBlockNumber = () => { +export const useLatestBlockNumber = ( + provider?: ethers.providers.JsonRpcProvider +) => { const [latestBlock, setLatestBlock] = useState<number>(); useEffect(() => { + if (!provider) { + return; + } + const readLatestBlock = async () => { const blockNum = await provider.getBlockNumber(); setLatestBlock(blockNum); @@ -49,7 +58,7 @@ export const useLatestBlockNumber = () => { return () => { provider.removeListener("block", listener); }; - }, []); + }, [provider]); return latestBlock; }; diff --git a/src/useProvider.ts b/src/useProvider.ts new file mode 100644 index 0000000..895c16d --- /dev/null +++ b/src/useProvider.ts @@ -0,0 +1,26 @@ +import React from "react"; +import { ethers } from "ethers"; +import { useErigon } from "./useErigon"; + +export const DEFAULT_ERIGON_URL = "http://127.0.0.1:8545"; + +export const useProvider = (): ethers.providers.JsonRpcProvider | undefined => { + const [configOK, config] = useErigon(); + if (!configOK) { + return undefined; + } + + let erigonURL = config?.erigonURL; + if (erigonURL === "") { + console.info(`Using default erigon URL: ${DEFAULT_ERIGON_URL}`); + erigonURL = DEFAULT_ERIGON_URL; + } else { + console.log(`Using configured erigon URL: ${erigonURL}`); + } + + return new ethers.providers.JsonRpcProvider(erigonURL, "mainnet"); +}; + +export const ProviderContext = React.createContext< + ethers.providers.JsonRpcProvider | undefined +>(undefined); diff --git a/src/useReverseCache.ts b/src/useReverseCache.ts index 9451d88..4188904 100644 --- a/src/useReverseCache.ts +++ b/src/useReverseCache.ts @@ -1,12 +1,15 @@ import { useState, useEffect } from "react"; +import { ethers } from "ethers"; import { ENSReverseCache, ProcessedTransaction } from "./types"; -import { provider } from "./ethersconfig"; -export const useENSCache = (page?: ProcessedTransaction[]) => { +export const useENSCache = ( + provider?: ethers.providers.JsonRpcProvider, + page?: ProcessedTransaction[] +) => { const [reverseCache, setReverseCache] = useState<ENSReverseCache>(); useEffect(() => { - if (!page) { + if (!provider || !page) { return; } @@ -38,7 +41,7 @@ export const useENSCache = (page?: ProcessedTransaction[]) => { setReverseCache(cache); }; reverseResolve(); - }, [page]); + }, [provider, page]); return reverseCache; }; From b6b33812c99a0bc5e5e8cb3b9a661587f8a62eab Mon Sep 17 00:00:00 2001 From: Willian Mitsuda <wmitsuda@gmail.com> Date: Thu, 8 Jul 2021 16:20:22 -0300 Subject: [PATCH 16/17] Fix dynamic config generation --- run-nginx.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run-nginx.sh b/run-nginx.sh index 9cb8352..7d83028 100755 --- a/run-nginx.sh +++ b/run-nginx.sh @@ -1,4 +1,4 @@ #!/bin/sh -PARAMS=$(echo "{\"erigonURL\": \"$ERIGON_URL\"}" | jq -aRs .) +PARAMS="{\"erigonURL\": $(echo $ERIGON_URL | jq -aR .)}" echo $PARAMS > /usr/share/nginx/html/config.json nginx -g "daemon off;" From f8cc3fee6d3b019109ee200946c5702bdf4290f0 Mon Sep 17 00:00:00 2001 From: Willian Mitsuda <wmitsuda@gmail.com> Date: Thu, 8 Jul 2021 16:26:09 -0300 Subject: [PATCH 17/17] Add instructions to run otterscan with a custom erigon url --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3fcf9e2..8de2e32 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,12 @@ To stop Otterscan service, run: docker stop otterscan ``` +By default it assumes your Erigon node is at http://127.0.0.1:8545. You can override the URL by setting the `ERIGON_URL` env variable on `docker run`: + +``` +docker run --rm -p 5000:80 --name otterscan -d --env ERIGON_URL="<your-erigon-node-url>" otterscan/otterscan:<versiontag> +``` + ### (Alternative 1) Build Otterscan docker image locally and run it If you don't want to download from Docker Hub, you can build the docker image from the sources and run it.