Browse Source

Merge branch 'feature/add-ci-support' into 'develop'

Feature/add ci support

See merge request ecentrics/concordia!17
develop
Apostolos Fanakis 4 years ago
parent
commit
6a9ad87720
  1. 2
      .dockerignore
  2. 6
      .gitignore
  3. 69
      docker/Makefile
  4. 45
      docker/concordia-app/Dockerfile
  5. 14
      docker/concordia-app/create-environment.sh
  6. 3
      docker/concordia-app/run.sh
  7. 2
      docker/concordia-app/test-app.sh
  8. 36
      docker/concordia-contracts-provider/Dockerfile
  9. 8
      docker/concordia-contracts/Dockerfile
  10. 4
      docker/concordia-contracts/migrate.sh
  11. 6
      docker/concordia-contracts/test-contracts.sh
  12. 4
      docker/concordia-pinner/Dockerfile
  13. 13
      docker/docker-compose.yml
  14. 7
      docker/env/concordia.docker.env
  15. 4
      docker/env/concordia.env
  16. 20
      docker/env/concordia.example.env
  17. 1
      docker/env/contracts-provider.env
  18. 14
      docker/env/contracts.docker.env
  19. 10
      docker/env/contracts.env
  20. 7
      docker/env/contracts.example.env
  21. 0
      docker/env/ganache.env
  22. 0
      docker/env/ganache.test.env
  23. 9
      docker/env/pinner.env
  24. 2
      docker/ganache/Dockerfile
  25. 8
      docker/ganache/start-blockchain.sh
  26. 759
      jenkins/Jenkinsfile
  27. 24
      jenkins/check_package_changed.sh
  28. 16
      jenkins/env/concordia.production.jenkins.env
  29. 16
      jenkins/env/concordia.staging.jenkins.env
  30. 8
      jenkins/env/contracts.production.jenkins.env
  31. 8
      jenkins/env/contracts.provider.production.env
  32. 8
      jenkins/env/contracts.provider.staging.env
  33. 8
      jenkins/env/contracts.staging.jenkins.env
  34. 4
      jenkins/env/contracts.test.jenkins.env
  35. 10
      jenkins/env/ganache.production.jenkins.env
  36. 10
      jenkins/env/ganache.staging.jenkins.env
  37. 6
      jenkins/env/ganache.test.jenkins.env
  38. 20
      jenkins/env/pinner.production.jenkins.env
  39. 20
      jenkins/env/pinner.staging.jenkins.env
  40. 18
      jenkins/hash_build_properties.sh
  41. 5
      jenkins/map_to_thousand.sh
  42. 4
      packages/concordia-app/public/index.html
  43. 4
      packages/concordia-app/src/options/drizzleOptions.js
  44. 4
      packages/concordia-app/src/redux/store.js
  45. 8
      packages/concordia-app/src/utils/drizzleUtils.js
  46. 2
      packages/concordia-contracts-provider/package.json
  47. 43
      packages/concordia-contracts-provider/src/controllers/download.js
  48. 45
      packages/concordia-contracts-provider/src/controllers/upload.js
  49. 2
      packages/concordia-contracts-provider/src/index.js
  50. 4
      packages/concordia-contracts-provider/src/middleware/upload.js
  51. 5
      packages/concordia-contracts-provider/src/routes/web.js
  52. 3
      packages/concordia-contracts/package.json
  53. 11
      packages/concordia-contracts/test/TestForum.sol
  54. 11
      packages/concordia-contracts/test/forum.js
  55. 16
      packages/concordia-pinner/src/app.js
  56. 5
      packages/concordia-pinner/src/constants.js
  57. 5
      packages/concordia-pinner/src/index.js
  58. 13
      packages/concordia-pinner/src/options/ipfsOptions.js
  59. 5
      packages/concordia-pinner/src/options/libp2pBundle.js
  60. 11
      packages/concordia-pinner/src/utils/ipfsUtils.js
  61. 2
      packages/concordia-pinner/src/utils/orbitUtils.js
  62. 6
      packages/concordia-shared/src/environment/contractsProviderEnv.js
  63. 11
      packages/concordia-shared/src/environment/pinnerEnv.js
  64. 11
      packages/concordia-shared/src/environment/rendezvousEnv.js
  65. 7
      packages/concordia-shared/src/environment/web3Env.js
  66. 10
      yarn.lock

2
.dockerignore

@ -8,6 +8,8 @@ docker/
!docker/concordia-contracts/test-contracts.sh
!docker/concordia-app/test-app.sh
!docker/concordia-app/nginx.conf
!docker/concordia-app/create-environment.sh
!docker/concordia-app/run.sh
!docker/ganache/start-blockchain.sh
packages/*/node_modules

6
.gitignore

@ -22,12 +22,10 @@ yarn-error.log*
# Docker volumes
docker/volumes
docker/ganache/volumes
docker/concordia-contracts-provider/volumes
docker/concordia-pinner/volumes
docker/reports
# Env var files
docker/env/concordia.env
docker/env/contracts.env
# Misc
.env.local
.env.development.local

69
docker/Makefile

@ -1,10 +1,15 @@
.EXPORT_ALL_VARIABLES:
PACKAGES := $(abspath ${CURDIR}/../packages)
REPORTS := $(abspath ${CURDIR}/reports)
GANACHE_VOLUMES := $(abspath ${CURDIR}/ganache/volumes)
PINNER_VOLUMES := $(abspath ${CURDIR}/pinner/volumes)
CONTRACTS_PROVIDER_VOLUMES := $(abspath ${CURDIR}/concordia-contracts-provider/volumes)
PINNER_VOLUMES := $(abspath ${CURDIR}/concordia-pinner/volumes)
DOCKER_BUILDKIT = 1
run: compose-run build-contracts-migrate run-contracts-migrate build-app run-app
run: compose-run build-contracts-provider run-contracts-provider build-contracts-migrate run-contracts-migrate build-pinner run-pinner build-app run-app
@echo "Concordia is up and running, head over to http://localhost:7777."
run-staging: compose-run build-contracts-provider run-contracts-provider-staging build-contracts-migrate run-contracts-migrate build-pinner run-pinner-staging build-app-staging run-app-staging
@echo "Concordia is up and running, head over to http://localhost:7000."
# Targets for building/running/stopping the blockchain and rendezvous server (using the docker-compose file)
compose-build:
@ -18,62 +23,70 @@ compose-stop-clean-data:
# Ganache targets
build-ganache:
@docker build ../ -f ./ganache/Dockerfile -t concordia-ganache
@docker build ../ -f ./ganache/Dockerfile -t ecentrics/concordia-ganache
run-ganache:
@docker network create --driver bridge concordia_ganache_network || true &&\
docker run -d -v ${GANACHE_VOLUMES}/ganache_keys:/home/ganache_keys -p 8545:8545 --env-file=./env/ganache.docker.env --name concordia-ganache --net=concordia_ganache_network concordia-ganache:latest
@docker run -d -v ${GANACHE_VOLUMES}/ganache_keys:/mnt/concordia/ganache_keys -p 8545:8545 --env-file=./env/ganache.env --name concordia-ganache --net=concordia_concordia_network ecentrics/concordia-ganache:latest
run-ganache-test:
@docker network create --driver bridge concordia_ganache_test_network || true &&\
docker run --rm -d -p 8546:8546 --env-file=./env/ganache.test.docker.env --name concordia-ganache-test --net=concordia_ganache_test_network concordia-ganache:latest
@docker run --rm -d -p 8546:8546 --env-file=./env/ganache.test.env --name concordia-ganache-test --net=concordia_concordia_network ecentrics/concordia-ganache:latest
# Rendezvous targets
run-rendezvous:
@docker network create --driver bridge concordia_rendezvous_network || true &&\
docker run -d -p 9090:9090 --name concordia-rendezvous libp2p/js-libp2p-webrtc-star:version-0.20.5
@docker network create --driver bridge concordia_concordia_network || true &&\
docker run -d -p 9090:9090 --name concordia-rendezvous --net=concordia_concordia_network libp2p/js-libp2p-webrtc-star:version-0.20.5
# Contracts targets
build-contracts:
@docker build ../ -f ./concordia-contracts/Dockerfile --target compile -t concordia-contracts --build-arg TZ=Europe/Athens
@docker build ../ -f ./concordia-contracts/Dockerfile --target compile -t ecentrics/concordia-contracts --build-arg TZ=Europe/Athens
build-contracts-migrate:
@docker build ../ -f ./concordia-contracts/Dockerfile -t concordia-contracts-migrate --build-arg TZ=Europe/Athens
@docker build ../ -f ./concordia-contracts/Dockerfile -t ecentrics/concordia-contracts-migrate --build-arg TZ=Europe/Athens
build-contracts-tests:
@docker build ../ -f ./concordia-contracts/Dockerfile --target test -t concordia-contracts-tests --build-arg TZ=Europe/Athens
@docker build ../ -f ./concordia-contracts/Dockerfile --target test -t ecentrics/concordia-contracts-tests --build-arg TZ=Europe/Athens
run-contracts-tests:
@docker run --rm -v ${REPORTS}/contracts/:/usr/test-reports/ --env-file=./env/contracts.docker.env --net=concordia_ganache_test_network concordia-contracts-tests:latest
@docker run --rm -v ${REPORTS}/contracts/:/mnt/concordia/test-reports/ --env-file=./env/contracts.env --net=concordia_concordia_network ecentrics/concordia-contracts-tests:latest
run-contracts-tests-host-chain:
@docker run --rm -v ${REPORTS}/contracts/:/usr/test-reports/ --env-file=./env/contracts.env --net=host concordia-contracts-tests:latest
@docker run --rm -v ${REPORTS}/contracts/:/mnt/concordia/test-reports/ --env-file=./env/contracts.env --net=host ecentrics/concordia-contracts-tests:latest
run-contracts-migrate:
@docker run --rm -v ${PACKAGES}/concordia-contracts/build/:/usr/src/concordia/packages/concordia-contracts/build/ --env-file=./env/contracts.docker.env --net=concordia_ganache_network concordia-contracts-migrate:latest
@docker run --rm -v ${PACKAGES}/concordia-contracts/build/:/usr/src/concordia/packages/concordia-contracts/build/ --env-file=./env/contracts.env --net=concordia_concordia_network ecentrics/concordia-contracts-migrate:latest
run-contracts-migrate-host-chain:
@docker run --rm -v ${PACKAGES}/concordia-contracts/build/:/usr/src/concordia/packages/concordia-contracts/build/ --env-file=./env/contracts.env --net=host concordia-contracts-migrate:latest
@docker run --rm -v ${PACKAGES}/concordia-contracts/build/:/usr/src/concordia/packages/concordia-contracts/build/ --env-file=./env/contracts.env --net=host ecentrics/concordia-contracts-migrate:latest
get-contracts:
@docker run --rm -v ${PACKAGES}/concordia-contracts/build/:/build --entrypoint=sh concordia-contracts:latest -c 'cp /usr/src/concordia/packages/concordia-contracts/build/* /build'
@docker run --rm -v ${PACKAGES}/concordia-contracts/build/:/mnt/concordia/build --entrypoint=sh ecentrics/concordia-contracts:latest -c 'cp /usr/src/concordia/packages/concordia-contracts/build/* /mnt/concordia/build'
# App targets
build-app:
@docker build ../ -f ./concordia-app/Dockerfile -t concordia-app --build-arg TZ=Europe/Athens
@docker build ../ -f ./concordia-app/Dockerfile -t ecentrics/concordia-app --build-arg TZ=Europe/Athens
build-app-staging:
@docker build ../ -f ./concordia-app/Dockerfile --target staging -t ecentrics/concordia-app-staging --build-arg TZ=Europe/Athens
build-app-tests:
@docker build ../ -f ./concordia-app/Dockerfile --target test -t concordia-app-tests --build-arg TZ=Europe/Athens
@docker build ../ -f ./concordia-app/Dockerfile --target test -t ecentrics/concordia-app-tests --build-arg TZ=Europe/Athens
run-app-tests:
@docker run --rm -v ${REPORTS}/app/:/usr/test-reports/ --env-file=./env/concordia.docker.env concordia-app-tests:latest
@docker run --rm -v ${REPORTS}/app/:/mnt/concordia/test-reports/ --env-file=./env/concordia.env ecentrics/concordia-app-tests:latest
run-app:
@docker create --env-file=./env/concordia.docker.env -p 7777:80 --name concordia-app --net=concordia_ganache_network concordia-app:latest &&\
docker network connect concordia_rendezvous_network concordia-app &&\
docker start concordia-app
@docker run -d --env-file=./env/concordia.env -p 7777:80 --name concordia-app ecentrics/concordia-app:latest
run-app-staging:
@docker run -itd --env-file=./env/concordia.env -p 7000:3000 --name concordia-app-staging ecentrics/concordia-app-staging:latest
run-app-host-chain:
@docker run -d --env-file=./env/concordia.env --name concordia-app --net=host concordia-app:latest
@docker run -d --env-file=./env/concordia.env --name concordia-app --net=host ecentrics/concordia-app:latest
# Contracts provider targets
build-contracts-provider:
@docker build ../ -f ./concordia-contracts-provider/Dockerfile -t ecentrics/concordia-contracts-provider --build-arg TZ=Europe/Athens
run-contracts-provider-staging:
@docker run -d -v ${CONTRACTS_PROVIDER_VOLUMES}/contracts:/mnt/concordia/contracts --env-file=./env/contracts-provider.env -p 8400:8400 --name concordia-contracts-provider --net=concordia_concordia_network ecentrics/concordia-contracts-provider:latest
run-contracts-provider:
@docker run -d -v ${CONTRACTS_PROVIDER_VOLUMES}/contracts:/mnt/concordia/contracts --env-file=./env/contracts-provider.env -e NODE_ENV=production -p 8400:8400 --name concordia-contracts-provider --net=concordia_concordia_network ecentrics/concordia-contracts-provider:latest
# Pinner targets
build-pinner:
@docker build ../ -f ./concordia-pinner/Dockerfile -t ecentrics/concordia-pinner --build-arg TZ=Europe/Athens
run-pinner-staging:
@docker run -d -v ${PINNER_VOLUMES}/orbitdb:/data/orbitdb --env-file=./env/pinner.env -e NODE_ENV=production -p 4444:4444 --name concordia-pinner ecentrics/concordia-pinner:latest
@docker run -d -v ${PINNER_VOLUMES}/orbitdb:/mnt/concordia/orbitdb --env-file=./env/pinner.env -p 4444:4444 --name concordia-pinner --net=concordia_concordia_network ecentrics/concordia-pinner:latest
run-pinner:
@docker run -d -v ${PINNER_VOLUMES}/orbitdb:/data/orbitdb --env-file=./env/pinner.env -p 4444:4444 --name concordia-pinner ecentrics/concordia-pinner:latest
@docker run -d -v ${PINNER_VOLUMES}/orbitdb:/mnt/concordia/orbitdb --env-file=./env/pinner.env -e NODE_ENV=production -p 4444:4444 --name concordia-pinner --net=concordia_concordia_network ecentrics/concordia-pinner:latest
run-pinner-staging-host:
@docker run -d -v ${PINNER_VOLUMES}/orbitdb:/data/orbitdb --env-file=./env/pinner.env -e NODE_ENV=production --net=host --name concordia-pinner ecentrics/concordia-pinner:latest
@docker run -d -v ${PINNER_VOLUMES}/orbitdb:/mnt/concordia/orbitdb --env-file=./env/pinner.env --net=host --name concordia-pinner ecentrics/concordia-pinner:latest
run-pinner-host:
@docker run -d -v ${PINNER_VOLUMES}/orbitdb:/data/orbitdb --env-file=./env/pinner.env --net=host --name concordia-pinner ecentrics/concordia-pinner:latest
@docker run -d -v ${PINNER_VOLUMES}/orbitdb:/mnt/concordia/orbitdb --env-file=./env/pinner.env -e NODE_ENV=production --net=host --name concordia-pinner ecentrics/concordia-pinner:latest
# Other
clean-images:

45
docker/concordia-app/Dockerfile

@ -1,7 +1,7 @@
# --------------------------------------------------
# Stage 1 (Init application build base)
# --------------------------------------------------
FROM node:14-buster as base
FROM node:14-alpine@sha256:51e341881c2b77e52778921c685e711a186a71b8c6f62ff2edfc6b6950225a2f as base
LABEL maintainers.1="Apostolos Fanakis <apostolof@auth.gr>"
LABEL maintainers.2="Panagiotis Nikolaidis <ezerous@gmail.com>"
LABEL gr.thmmy.ecentrics.concordia-image.name="app"
@ -12,32 +12,39 @@ WORKDIR /usr/src/concordia
COPY ./package.json .
COPY ./yarn.lock .
# Copy package.json files from contracts and app, then install base modules
# Copy package.json files from contracts, shared and app, then install modules
COPY ./packages/concordia-contracts/package.json ./packages/concordia-contracts/package.json
COPY ./packages/concordia-shared/package.json ./packages/concordia-shared/package.json
COPY ./packages/concordia-app/package.json ./packages/concordia-app/
# Install required packages
RUN apk update && apk --no-cache add g++ make python
RUN yarn install --frozen-lockfile
# Gets the rest of the source code
COPY ./packages/concordia-contracts ./packages/concordia-contracts
COPY ./packages/concordia-shared ./packages/concordia-shared
COPY ./packages/concordia-app ./packages/concordia-app
# Fix timezome
ARG TZ
ENV TZ=${TZ}
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# --------------------------------------------------
# Stage 2 (Test)
# --------------------------------------------------
FROM base as test
# Fix timezome (needed for timestamps on report files)
ARG TZ
ENV TZ=${TZ}
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /opt/concordia-app
COPY ./docker/concordia-app/test-app.sh .
WORKDIR /usr/src/concordia/packages/concordia-app
RUN ["chmod", "+x", "/opt/concordia-app/test-app.sh"]
ENTRYPOINT ["/opt/concordia-app/test-app.sh"]
# --------------------------------------------------
@ -50,9 +57,18 @@ WORKDIR /usr/src/concordia/packages/concordia-app
RUN yarn build
# --------------------------------------------------
# Stage 4 (Runtime)
# Stage 4 (Staging runtime)
# --------------------------------------------------
FROM nginx:1.17-alpine as runtime
FROM base as staging
WORKDIR /usr/src/concordia/packages/concordia-app
ENTRYPOINT ["yarn", "start"]
# --------------------------------------------------
# Stage 4 (Production runtime)
# --------------------------------------------------
FROM nginx:1.17-alpine@sha256:01747306a7247dbe928db991eab42e4002118bf636dd85b4ffea05dd907e5b66 as production
LABEL maintainers.1="Apostolos Fanakis <apostolof@auth.gr>"
LABEL maintainers.2="Panagiotis Nikolaidis <ezerous@gmail.com"
LABEL gr.thmmy.ecentrics.concordia-image.name="app"
@ -66,7 +82,16 @@ RUN apk add -U tzdata \
&& apk del tzdata \
&& rm -rf /var/cache/apk/*
WORKDIR "/var/www/concordia-app"
COPY ./docker/concordia-app/create-environment.sh /opt/concordia/create-environment.sh
COPY ./docker/concordia-app/run.sh /opt/concordia/run.sh
RUN ["chmod", "+x", "/opt/concordia/create-environment.sh"]
RUN ["chmod", "+x", "/opt/concordia/run.sh"]
COPY ./docker/concordia-app/nginx.conf /etc/nginx/conf.d/default.conf
WORKDIR "/var/www/concordia-app"
COPY --chown=nginx:nginx --from=build /usr/src/concordia/packages/concordia-app/build .
CMD ["/opt/concordia/run.sh"]

14
docker/concordia-app/create-environment.sh

@ -0,0 +1,14 @@
#!/bin/sh
echo "window.runtimeEnv = { \
REACT_APP_CONCORDIA_HOST: \"${REACT_APP_CONCORDIA_HOST}\", \
REACT_APP_CONCORDIA_PORT: \"${REACT_APP_CONCORDIA_PORT}\", \
REACT_APP_WEB3_HOST: \"${REACT_APP_WEB3_HOST}\", \
REACT_APP_WEB3_PORT: \"${REACT_APP_WEB3_PORT}\", \
REACT_APP_RENDEZVOUS_HOST: \"${REACT_APP_RENDEZVOUS_HOST}\", \
REACT_APP_RENDEZVOUS_PORT: \"${REACT_APP_RENDEZVOUS_PORT}\", \
REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER: \"${REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER}\", \
REACT_APP_CONTRACTS_PROVIDER_HOST: \"${REACT_APP_CONTRACTS_PROVIDER_HOST}\", \
REACT_APP_CONTRACTS_PROVIDER_PORT: \"${REACT_APP_CONTRACTS_PROVIDER_PORT}\", \
REACT_APP_CONTRACTS_VERSION_HASH: \"${REACT_APP_CONTRACTS_VERSION_HASH}\", \
}" >/var/www/concordia-app/environment.js

3
docker/concordia-app/run.sh

@ -0,0 +1,3 @@
sh /opt/concordia/create-environment.sh
exec "$(which nginx)" -g "daemon off;"

2
docker/concordia-app/test-app.sh

@ -1,6 +1,6 @@
#!/bin/sh
yarn lint -f html -o /usr/test-reports/concordia-app-eslint.html --no-color
yarn lint -f html -o /mnt/concordia/test-reports/concordia-app-eslint.html --no-color
if [ $? -eq 0 ]; then
echo "TESTS RAN SUCCESSFULLY!"

36
docker/concordia-contracts-provider/Dockerfile

@ -0,0 +1,36 @@
# --------------------------------------------------
# Stage 1 (Runtime)
# --------------------------------------------------
FROM node:14-alpine@sha256:51e341881c2b77e52778921c685e711a186a71b8c6f62ff2edfc6b6950225a2f as runtime
LABEL maintainers.1="Apostolos Fanakis <apostolof@auth.gr>"
LABEL maintainers.2="Panagiotis Nikolaidis <ezerous@gmail.com>"
LABEL gr.thmmy.ecentrics.concordia-image.name="contracts-provider"
# Fix timezome (needed for timestamps on report files)
ARG TZ
RUN apk add -U tzdata \
&& cp /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& apk del tzdata \
&& rm -rf /var/cache/apk/*
WORKDIR /usr/src/concordia
# Copy the root package.json and yarn.lock
COPY ./package.json .
COPY ./yarn.lock .
# Copy package.json files from shared and contracts provider, then install modules
COPY ./packages/concordia-shared/package.json ./packages/concordia-shared/
COPY ./packages/concordia-contracts-provider/package.json ./packages/concordia-contracts-provider/
RUN yarn install --frozen-lockfile --network-timeout 100000
# Gets the rest of the source code
COPY ./packages/concordia-shared ./packages/concordia-shared
COPY ./packages/concordia-contracts-provider ./packages/concordia-contracts-provider
WORKDIR /usr/src/concordia/packages/concordia-contracts-provider
ENTRYPOINT ["yarn", "start"]

8
docker/concordia-contracts/Dockerfile

@ -1,7 +1,7 @@
# --------------------------------------------------
# Stage 1 (Init contracts build base)
# --------------------------------------------------
FROM node:14-alpine as base
FROM node:14-alpine@sha256:51e341881c2b77e52778921c685e711a186a71b8c6f62ff2edfc6b6950225a2f as base
LABEL maintainers.1="Apostolos Fanakis <apostolof@auth.gr>"
LABEL maintainers.2="Panagiotis Nikolaidis <ezerous@gmail.com>"
LABEL gr.thmmy.ecentrics.concordia-image.name="contracts"
@ -21,12 +21,14 @@ WORKDIR /usr/src/concordia
COPY ./package.json .
COPY ./yarn.lock .
# Copy the contracts package.json, then install modules
# Copy package.json files from shared and contracts, then install modules
COPY ./packages/concordia-shared/package.json ./packages/concordia-shared/
COPY ./packages/concordia-contracts/package.json ./packages/concordia-contracts/
RUN yarn install --frozen-lockfile --network-timeout 100000
# Gets the rest of the source code
COPY ./packages/concordia-shared ./packages/concordia-shared
COPY ./packages/concordia-contracts ./packages/concordia-contracts
# --------------------------------------------------
@ -48,6 +50,8 @@ COPY ./docker/concordia-contracts/test-contracts.sh .
WORKDIR /usr/src/concordia/packages/concordia-contracts
RUN ["chmod", "+x", "/opt/concordia-contracts/test-contracts.sh"]
ENTRYPOINT ["/opt/concordia-contracts/test-contracts.sh"]
# --------------------------------------------------

4
docker/concordia-contracts/migrate.sh

@ -3,4 +3,6 @@
export CHAIN_HOST="$DEPLOY_CHAIN_HOST"
export CHAIN_PORT="$DEPLOY_CHAIN_PORT"
cd /usr/src/concordia/packages/concordia-contracts && yarn _migrate --network "${MIGRATE_NETWORK}" --reset
cd /usr/src/concordia/packages/concordia-contracts &&
yarn _migrate --network "${MIGRATE_NETWORK}" --reset &&
yarn _upload ${CONTRACTS_VERSION_HASH} ${CONTRACTS_VERSION_TAG}

6
docker/concordia-contracts/test-contracts.sh

@ -3,9 +3,9 @@
export CHAIN_HOST="$TEST_CHAIN_HOST"
export CHAIN_PORT="$TEST_CHAIN_PORT"
yarn _eslint -f html -o /usr/test-reports/concordia-contracts-eslint.html --no-color &&
(yarn _solhint >/usr/test-reports/concordia-contracts-solhint.report) &&
(yarn test --network env >/usr/test-reports/concordia-contracts-truffle-tests.report)
yarn _eslint -f html -o /mnt/concordia/test-reports/concordia-contracts-eslint.html --no-color &&
(yarn _solhint >/mnt/concordia/test-reports/concordia-contracts-solhint.report) &&
(yarn test --network env >/mnt/concordia/test-reports/concordia-contracts-truffle-tests.report)
if [ $? -eq 0 ]; then
echo "TESTS RAN SUCCESSFULLY!"

4
docker/concordia-pinner/Dockerfile

@ -1,7 +1,7 @@
# --------------------------------------------------
# Stage 1 (Runtime)
# --------------------------------------------------
FROM node:14-buster as runtime
FROM node:14-buster@sha256:32362e2ea89c62d77c86c8f26ad936dbbdc170cd6c06c4d7ff7a809012bb0c32 as runtime
LABEL maintainers.1="Apostolos Fanakis <apostolof@auth.gr>"
LABEL maintainers.2="Panagiotis Nikolaidis <ezerous@gmail.com>"
LABEL gr.thmmy.ecentrics.concordia-image.name="pinner"
@ -17,7 +17,7 @@ WORKDIR /usr/src/concordia
COPY ./package.json .
COPY ./yarn.lock .
# Copy the pinner, contracts and shared package.json files, then install modules
# Copy package.json files from contracts, shared and pinner, then install modules
COPY ./packages/concordia-pinner/package.json ./packages/concordia-pinner/
COPY ./packages/concordia-contracts/package.json ./packages/concordia-contracts/
COPY ./packages/concordia-shared/package.json ./packages/concordia-shared/

13
docker/docker-compose.yml

@ -5,30 +5,29 @@ services:
build:
context: ../
dockerfile: ./docker/ganache/Dockerfile
image: concordia-ganache
image: ecentrics/concordia-ganache
container_name: concordia-ganache
env_file:
- env/ganache.docker.env
- env/ganache.env
expose:
- 8545
ports:
- 8545:8545
user: root
volumes:
- ./ganache/volumes/ganache_keys:/home/ganache_keys
- ./ganache/volumes/ganache_keys:/mnt/concordia/ganache_keys
networks:
ganache_network:
concordia_network:
restart: always
rendezvous:
image: libp2p/js-libp2p-webrtc-star:version-0.20.5
container_name: concordia-rendezvous
networks:
rendezvous_network:
concordia_network:
ports:
- 9090:9090
restart: always
networks:
ganache_network:
rendezvous_network:
concordia_network:

7
docker/env/concordia.docker.env

@ -1,7 +0,0 @@
# Variables needed in runtime (in browser)
REACT_APP_RENDEZVOUS_HOST=rendezvous
REACT_APP_RENDEZVOUS_PORT=9090
# If the rendezvous server is running on host use these instead
#REACT_APP_RENDEZVOUS_HOST=127.0.0.1
#REACT_APP_RENDEZVOUS_PORT=9090

4
docker/env/concordia.env

@ -0,0 +1,4 @@
# Variables needed in runtime (in browser)
REACT_APP_RENDEZVOUS_HOST=127.0.0.1
REACT_APP_RENDEZVOUS_PORT=9090
USE_EXTERNAL_CONTRACTS_PROVIDER=true

20
docker/env/concordia.example.env

@ -1,20 +0,0 @@
# Set to "CI" if in CI environment, anything else (including unset) will be ignored
BUILD_ENV={CI}
# Docker compose variables
VIRTUAL_HOST=example.com
VIRTUAL_PORT=3000
# If you uncomment the lines below, Concordia will become available through https BUT the rendezvous
# server will stop working and IPFS initialization won't complete
#LETSENCRYPT_HOST=example.com
#LETSENCRYPT_EMAIL=someemail.email.com
# Variables needed in runtime
# TO-NEVER-DO: change CONCORDIA_HOST to localhost
CONCORDIA_HOST=0.0.0.0
CONCORDIA_PORT=3000
# Variables needed in runtime (in browser)
REACT_APP_RENDEZVOUS_HOST=xx.xxx.xxx.xxx
REACT_APP_RENDEZVOUS_PORT=9090

1
docker/env/contracts-provider.env

@ -0,0 +1 @@
UPLOAD_CONTRACTS_DIRECTORY=/mnt/concordia/contracts/

14
docker/env/contracts.docker.env

@ -1,14 +0,0 @@
# Variables needed in runtime
MIGRATE_NETWORK=env
DEPLOY_CHAIN_HOST=concordia-ganache
DEPLOY_CHAIN_PORT=8545
TEST_CHAIN_HOST=concordia-ganache-test
TEST_CHAIN_PORT=8546
# If the blockchain is running on host use these instead
#DEPLOY_CHAIN_HOST=127.0.0.1
#DEPLOY_CHAIN_PORT=8545
#TEST_CHAIN_HOST=127.0.0.1
#TEST_CHAIN_PORT=8546

10
docker/env/contracts.env

@ -0,0 +1,10 @@
# Variables needed in runtime
MIGRATE_NETWORK=env
WEB3_HOST=concordia-ganache
WEB3_PORT=8545
CONTRACTS_PROVIDER_HOST=concordia-contracts-provider
CONTRACTS_PROVIDER_PORT=8400
TEST_CHAIN_HOST=concordia-ganache-test
TEST_CHAIN_PORT=8546

7
docker/env/contracts.example.env

@ -1,7 +0,0 @@
# Variables needed in runtime
MIGRATE_NETWORK=env
DEPLOY_CHAIN_HOST=xx.xxx.xxx.xxx
DEPLOY_CHAIN_PORT=8545
TEST_CHAIN_HOST=xx.xxx.xxx.xxx
TEST_CHAIN_PORT=8545

0
docker/env/ganache.docker.env → docker/env/ganache.env

0
docker/env/ganache.test.docker.env → docker/env/ganache.test.env

9
docker/env/pinner.env

@ -1,16 +1,15 @@
USE_EXTERNAL_CONTRACTS_PROVIDER=true
ORBIT_DIRECTORY=/data/orbitdb
ORBIT_DIRECTORY=/mnt/concordia/orbitdb
#CONTRACTS_PROVIDER_HOST=contracts-provider
CONTRACTS_PROVIDER_HOST=127.0.0.1
CONTRACTS_PROVIDER_HOST=concordia-contracts-provider
CONTRACTS_PROVIDER_PORT=8400
CONTRACTS_VERSION_HASH=latest
PINNER_API_HOST=127.0.0.1
PINNER_API_PORT=4444
RENDEZVOUS_HOST=127.0.0.1
RENDEZVOUS_HOST=concordia-rendezvous
RENDEZVOUS_PORT=9090
WEB3_HOST=127.0.0.1
WEB3_HOST=concordia-ganache
WEB3_PORT=8545

2
docker/ganache/Dockerfile

@ -1,4 +1,4 @@
FROM trufflesuite/ganache-cli:latest
FROM trufflesuite/ganache-cli:v6.12.2@sha256:c062707f17f355872d703cde3de6a12fc45a027ed42857c72514171a5f466ab7
RUN mkdir /home/ganache_db /home/ganache_keys

8
docker/ganache/start-blockchain.sh

@ -14,8 +14,8 @@ if [ -z "${MNEMONIC}" ]; then
--host "$HOST" \
--port "$PORT" \
--networkId "$ID" \
--account_keys_path "/home/ganache_keys/keys.json" \
--db "/home/ganache_db/" \
--account_keys_path "/mnt/concordia/ganache_keys/keys.json" \
--db "/mnt/concordia/ganache_db/" \
--allowUnlimitedContractSize \
--noVMErrorsOnRPCResponse \
--verbose
@ -28,8 +28,8 @@ else
--host "$HOST" \
--port "$PORT" \
--networkId "$ID" \
--account_keys_path "/home/ganache_keys/keys.json" \
--db "/home/ganache_db/" \
--account_keys_path "/mnt/concordia/ganache_keys/keys.json" \
--db "/mnt/concordia/ganache_db/" \
--allowUnlimitedContractSize \
--noVMErrorsOnRPCResponse \
--deterministic \

759
jenkins/Jenkinsfile

@ -0,0 +1,759 @@
#!groovy
def cleanSlateEnabled
// Package change state
def appPackageChanged
def contractsPackageChanged
def contractsProviderPackageChanged
def pinnerPackageChanged
def sharedPackageChanged
// Package versions
def appPackageVersion
def contractsPackageVersion
def contractsProviderPackageVersion
def pinnerPackageVersion
def sharedPackageVersion
// Docker images
def appImage
def appTestsImage
def contractsImage
def contractsTestsImage
def contractsProviderImage
def pinnerImage
def freshGanacheStagingRunning
def freshGanacheProductionRunning
def successResultGif = "https://media.giphy.com/media/o75ajIFH0QnQC3nCeD/giphy.gif"
def failResultGif = "https://media.giphy.com/media/ljtfkyTD3PIUZaKWRi/giphy.gif"
def abortResultGif = "https://media.giphy.com/media/IzXmRTmKd0if6/giphy.gif"
pipeline {
agent any
post {
failure {
updateGitlabCommitStatus name: 'build', state: 'failed'
discordSend footer: "Visit Jenkins for more information", result: currentBuild.currentResult, link: env.BUILD_URL, description: """Jenkins Pipeline Build
Last commit included is [${GIT_COMMIT[0..7]}](https://gitlab.com/ecentrics/concordia/-/commit/$GIT_COMMIT)
Build status: ${currentBuild.currentResult}
""", image: failResultGif, thumbnail: "$CONCORDIA_LOGO_URL", title: JOB_NAME, webhookURL: "${DISCORD_WEBHOOK_URL}"
}
success {
updateGitlabCommitStatus name: 'build', state: 'success'
discordSend footer: "Visit Jenkins for more information", result: currentBuild.currentResult, link: env.BUILD_URL, description: """Jenkins Pipeline Build
Last commit included is [${GIT_COMMIT[0..7]}](https://gitlab.com/ecentrics/concordia/-/commit/$GIT_COMMIT)
Build status: ${currentBuild.currentResult}
""", image: successResultGif, thumbnail: "$CONCORDIA_LOGO_URL", title: JOB_NAME, webhookURL: "${DISCORD_WEBHOOK_URL}"
}
aborted {
discordSend footer: "Visit Jenkins for more information", result: currentBuild.currentResult, link: env.BUILD_URL, description: """Jenkins Pipeline Build
Last commit included is [${GIT_COMMIT[0..7]}](https://gitlab.com/ecentrics/concordia/-/commit/$GIT_COMMIT)
Build status: ${currentBuild.currentResult}
""", image: abortResultGif, thumbnail: "$CONCORDIA_LOGO_URL", title: JOB_NAME, webhookURL: "${DISCORD_WEBHOOK_URL}"
}
always {
archiveArtifacts artifacts: "reports/${BUILD_NUMBER}/**/* , build/**/*, ganache/*", fingerprint: true, allowEmptyArchive: true
sleep 2
sh 'docker images | grep -E "ecentrics/concordia.+tests" | tr -s \' \' | cut -d \' \' -f 3 | xargs --no-run-if-empty docker rmi -f || true'
sh 'docker images | grep -E "ecentrics/concordia.+staging" | tr -s \' \' | cut -d \' \' -f 3 | xargs --no-run-if-empty docker rmi -f || true'
sh 'docker system prune -f'
sh 'rm -rf reports'
sh 'rm -rf build'
}
}
options {
gitLabConnection('apella')
}
triggers {
gitlab(triggerOnPush: true, triggerOnMergeRequest: true, branchFilterType: 'All')
}
environment {
DOCKER_BUILDKIT='1'
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/810180975580938290/HYYeK8Nqwt0h8Arx3qPpF-szjgLkPDTqbVVKLkzcmqY7ourTpKJCAc6IuCXHd_cxowuK"
CONCORDIA_LOGO_URL="https://i.postimg.cc/MGvgy9Lp/app-logo-circle.png"
}
stages {
stage ('VERSION') {
steps {
script {
cleanSlateEnabled = sh (script: "git log -1 | grep -qE 'ci: force'", returnStatus: true)
appPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh app "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim()
contractsPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh contracts "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim()
contractsProviderPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh concordia-contracts-provider "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim()
pinnerPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh pinner "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim()
sharedPackageChanged = sh(script: 'bash ./jenkins/check_package_changed.sh shared "$GIT_COMMIT" "$GIT_PREVIOUS_COMMIT"', returnStdout: true).trim()
appPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-app/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim()
contractsPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-contracts/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim()
contractsProviderPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-contracts-provider/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim()
pinnerPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-pinner/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim()
sharedPackageVersion = sh(script: 'grep "\\"version\\":" ./packages/concordia-shared/package.json | head -1 | awk -F: \'{ print $2 }\' | sed \'s/[",]//g\' | tr -d \'[[:space:]]\'', returnStdout: true).trim()
echo "Package: app, Version: ${appPackageVersion}, Changed: ${appPackageChanged}"
echo "Package: contracts, Version: ${contractsPackageVersion}, Changed: ${contractsPackageChanged}"
echo "Package: contracts-provider, Version: ${contractsProviderPackageVersion}, Changed: ${contractsProviderPackageChanged}"
echo "Package: pinner, Version: ${pinnerPackageVersion}, Changed: ${pinnerPackageChanged}"
echo "Package: shared, Version: ${sharedPackageVersion}, Changed: ${sharedPackageChanged}"
}
}
}
stage('TEST') {
parallel {
stage('TEST CONTRACTS') {
steps {
script {
try {
def ganacheTestPort = sh(script: "bash ./jenkins/hash_build_properties.sh ${BRANCH_NAME} ${BUILD_NUMBER} | xargs bash ./jenkins/map_to_thousand.sh", returnStdout: true).trim()
def ganacheTestImage = docker.build(
"ecentrics/concordia-ganache",
"-f docker/ganache/Dockerfile \
./"
)
sh 'docker network create --driver bridge concordia_ganache_test_network || true'
ganacheTestImage.withRun("""-d -p 6${ganacheTestPort}:8546 \
--env-file=./jenkins/env/ganache.test.jenkins.env \
--name concordia-ganache-test-6${ganacheTestPort} \
--net=concordia_ganache_test_network""") { concordiaGanacheTest ->
contractsTestsImage = docker.build(
"ecentrics/concordia-contracts-tests:v${contractsPackageVersion}-b${BUILD_NUMBER}-tests",
"-f docker/concordia-contracts/Dockerfile \
./ \
--target test \
--build-arg TZ=Europe/Athens"
)
contractsTestsImage.run("""--rm \
-v ecentrics_janus_common:/mnt/concordia/test-reports/ \
--env-file=./jenkins/env/contracts.test.jenkins.env \
-e WEB3_HOST=concordia-ganache-test-6${ganacheTestPort} \
-e WEB3_PORT=6${ganacheTestPort} \
--net=concordia_ganache_test_network""")
sh 'mkdir -p ./reports/${BUILD_NUMBER}/contracts'
sh 'find /mnt/janus/common/ -name "concordia-contracts-*" -exec cp \'{}\' ./reports/${BUILD_NUMBER}/contracts/ \\;'
}
} catch (e) {
error('Some tests failed!')
error('Aborting the build.')
throw e
}
}
}
}
stage('TEST APP') {
steps {
script {
appTestsImage = docker.build(
"ecentrics/concordia-app:v${appPackageVersion}-b${BUILD_NUMBER}-tests",
"-f docker/concordia-app/Dockerfile \
./ \
--target test \
--build-arg TZ=Europe/Athens"
)
try {
appTestsImage.run('--rm \
-v ecentrics_janus_common:/mnt/concordia/test-reports/')
sh 'mkdir -p ./reports/${BUILD_NUMBER}/app'
sh 'find /mnt/janus/common/ -name "concordia-app-*" -exec cp \'{}\' ./reports/${BUILD_NUMBER}/app/ \\;'
} catch (e) {
error('Some tests failed!')
error('Aborting the build.')
throw e
}
}
}
}
}
}
stage('BUILD FOR PRODUCTION') {
when {
branch 'master'
}
parallel {
stage('BUILD CONTRACTS') {
when {
expression {
return "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
contractsImage = docker.build(
"ecentrics/concordia-contracts-migrate:v${contractsPackageVersion}",
"-f docker/concordia-contracts/Dockerfile \
./ \
--build-arg TZ=Europe/Athens"
)
contractsImage.run('--rm \
-v ecentrics_janus_common:/mnt/concordia/build \
--entrypoint=sh',
"-c 'mkdir -p /mnt/concordia/build/contract-artifacts && cp /usr/src/concordia/packages/concordia-contracts/build/* /mnt/concordia/build/contract-artifacts'")
sh 'mkdir -p ./build/${BUILD_NUMBER}/contracts'
sh 'cp /mnt/janus/common/contract-artifacts/* ./build/${BUILD_NUMBER}/contracts'
}
}
}
stage('BUILD APP') {
when {
expression {
return "${appPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
appImage = docker.build(
"ecentrics/concordia-app:v${appPackageVersion}",
"-f docker/concordia-app/Dockerfile \
./ \
--build-arg TZ=Europe/Athens"
)
}
}
}
stage('BUILD CONTRACTS PROVIDER') {
when {
expression {
return "${contractsProviderPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
contractsProviderImage = docker.build(
"ecentrics/concordia-contracts-provider:v${contractsProviderPackageVersion}",
"-f docker/concordia-contracts-provider/Dockerfile \
./ \
--build-arg TZ=Europe/Athens"
)
}
}
}
stage('BUILD PINNER') {
when {
expression {
return "${pinnerPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
pinnerImage = docker.build(
"ecentrics/concordia-pinner:v${pinnerPackageVersion}",
"-f docker/concordia-pinner/Dockerfile \
./ \
--build-arg TZ=Europe/Athens"
)
}
}
}
}
}
stage('BUILD FOR STAGING') {
when {
branch 'develop'
}
parallel {
stage('BUILD CONTRACTS') {
when {
expression {
return "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
contractsImage = docker.build(
"ecentrics/concordia-contracts-migrate:v${contractsPackageVersion}-staging-b${BUILD_NUMBER}",
"-f docker/concordia-contracts/Dockerfile \
./ \
--build-arg TZ=Europe/Athens"
)
// Get contract artifacts
contractsImage.run('--rm \
-v ecentrics_janus_common:/mnt/concordia/build \
--entrypoint=sh',
"-c 'mkdir -p /mnt/concordia/build/contract-artifacts && cp /usr/src/concordia/packages/concordia-contracts/build/* /mnt/concordia/build/contract-artifacts'")
sh 'mkdir -p ./build/${BUILD_NUMBER}/contracts'
sh 'cp /mnt/janus/common/contract-artifacts/* ./build/${BUILD_NUMBER}/contracts'
}
}
}
stage('BUILD APP') {
when {
expression {
return "${appPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
appImage = docker.build(
"ecentrics/concordia-app:v${appPackageVersion}-staging-b${BUILD_NUMBER}",
"-f docker/concordia-app/Dockerfile \
./ \
--target staging \
--build-arg TZ=Europe/Athens"
)
}
}
}
stage('BUILD CONTRACTS PROVIDER') {
when {
expression {
return "${contractsProviderPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
contractsProviderImage = docker.build(
"ecentrics/concordia-contracts-provider:v${contractsProviderPackageVersion}-staging-b${BUILD_NUMBER}",
"-f docker/concordia-contracts-provider/Dockerfile \
./ \
--build-arg TZ=Europe/Athens"
)
}
}
}
stage('BUILD PINNER') {
when {
expression {
return "${pinnerPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
pinnerImage = docker.build(
"ecentrics/concordia-pinner:v${pinnerPackageVersion}-staging-b${BUILD_NUMBER}",
"-f docker/concordia-pinner/Dockerfile \
./ \
--build-arg TZ=Europe/Athens"
)
}
}
}
}
}
stage('PUBLISH') {
when {
branch 'master'
}
parallel {
stage('PUBLISH CONTRACTS') {
when {
expression {
return "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
docker.withRegistry('https://registry.hub.docker.com/', 'docker-hub-concordia') {
contractsImage.push()
contractsImage.push('latest')
}
}
}
}
stage('PUBLISH APP') {
when {
expression {
return "${appPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
docker.withRegistry('https://registry.hub.docker.com/', 'docker-hub-concordia') {
appImage.push()
appImage.push('latest')
}
}
}
}
stage('PUBLISH CONTRACTS PROVIDER') {
when {
expression {
return "${contractsProviderPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
docker.withRegistry('https://registry.hub.docker.com/', 'docker-hub-concordia') {
contractsProviderImage.push()
contractsProviderImage.push('latest')
}
}
}
}
stage('PUBLISH PINNER') {
when {
expression {
return "${pinnerPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
docker.withRegistry('https://registry.hub.docker.com/', 'docker-hub-concordia') {
pinnerImage.push()
pinnerImage.push('latest')
}
}
}
}
}
}
stage('DEPLOY STAGING') {
when {
branch 'develop'
}
stages {
stage('STAGING DEPLOY PREPARATION') {
steps {
script {
sh 'docker network create --driver bridge ecentrics_concordia_staging_network || true'
def rendezvousServerRunning = sh (script: 'docker ps -f name=concordia-rendezvous | \
grep -qE concordia-rendezvous', returnStatus: true)
if ("$rendezvousServerRunning" == '1') {
sh 'docker run \
-d \
-p 9090:9090 \
--name concordia-rendezvous \
--net=ecentrics_concordia_staging_network \
libp2p/js-libp2p-webrtc-star:version-0.20.5'
} else {
sh 'docker network connect ecentrics_concordia_staging_network concordia-rendezvous || true'
}
}
}
}
stage('DEPLOY CONTRACTS PROVIDER') {
when {
expression {
def contractsProviderStagingRunning = sh (script: 'docker ps -f name=concordia-contracts-provider-staging | \
grep -qE concordia-contracts-provider-staging', returnStatus: true)
return "${contractsProviderPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "$contractsProviderStagingRunning" == '1' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
sh 'docker stop concordia-contracts-provider-staging || true \
&& docker rm concordia-contracts-provider-staging || true'
sh 'if [ "$cleanSlateEnabled" -eq "0" ]; then \
docker volume rm concordia-contracts-provider-staging || true; \
fi'
sh (script: """docker run \
-d \
-v concordia-contracts-provider-staging:/mnt/concordia/contracts \
--env-file=./jenkins/env/contracts.provider.staging.env \
-p 8450:8450 \
--name concordia-contracts-provider-staging \
--net=ecentrics_concordia_staging_network \
ecentrics/concordia-contracts-provider:v${contractsProviderPackageVersion}-staging-b${BUILD_NUMBER}""")
}
}
}
stage('RECREATE GANACHE') {
when {
expression {
def ganacheStagingRunning = sh (script: 'docker ps -f name=concordia-ganache-staging | \
grep -qE concordia-ganache-staging', returnStatus: true)
return "$cleanSlateEnabled" == '0' || "$ganacheStagingRunning" == '1';
}
}
steps {
script {
sh 'docker stop concordia-ganache-staging || true \
&& docker rm concordia-ganache-staging || true'
sh 'docker volume rm concordia-ganache-staging || true'
sh (script: 'docker run \
-d \
-v concordia-ganache-staging:/mnt/concordia/ganache_keys \
-p 8555:8555 \
--env-file=./jenkins/env/ganache.staging.jenkins.env \
--name concordia-ganache-staging \
--net=ecentrics_concordia_staging_network \
ecentrics/concordia-ganache:latest')
// Ganache image might take a while to come alive
sleep 10
sh 'mkdir -p ./ganache/ && docker cp concordia-ganache-staging:/mnt/concordia/ganache_keys/keys.json ./ganache/'
freshGanacheStagingRunning = true
}
}
}
stage('DEPLOY CONTRACTS') {
when {
expression {
return "${contractsPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "$freshGanacheStagingRunning" || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
sh """docker run \
--rm \
--env-file=./jenkins/env/contracts.staging.jenkins.env \
-e CONTRACTS_VERSION_HASH=${contractsPackageVersion}-dev \
--net=ecentrics_concordia_staging_network \
ecentrics/concordia-contracts-migrate:v${contractsPackageVersion}-staging-b${BUILD_NUMBER}"""
}
}
}
stage('DEPLOY PINNER') {
when {
expression {
def pinnerStagingRunning = sh (script: 'docker ps -f name=concordia-pinner-staging | \
grep -qE concordia-pinner-staging', returnStatus: true)
return "${pinnerPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
sh 'docker stop concordia-pinner-staging || true \
&& docker rm concordia-pinner-staging || true'
sh 'if [ "$cleanSlateEnabled" -eq "0" ]; then \
docker volume rm concordia-pinner-staging || true; \
fi'
sh """docker run \
-d \
-v concordia-pinner-staging:/mnt/concordia/orbitdb \
-p 5555:5555 \
--env-file=./jenkins/env/pinner.staging.jenkins.env \
--name concordia-pinner-staging \
--net=ecentrics_concordia_staging_network \
ecentrics/concordia-pinner:v${pinnerPackageVersion}-staging-b${BUILD_NUMBER}"""
}
}
}
stage('DEPLOY APP') {
when {
expression {
def pinnerStagingRunning = sh (script: 'docker ps -f name=concordia-app-staging | \
grep -qE concordia-app-staging', returnStatus: true)
return "${appPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
sh 'docker stop concordia-app-staging || true \
&& docker rm concordia-app-staging || true'
sh """docker run \
-itd \
-p 7000:3000 \
--env-file=./jenkins/env/concordia.staging.jenkins.env \
--name concordia-app-staging \
ecentrics/concordia-app:v${appPackageVersion}-staging-b${BUILD_NUMBER}"""
}
}
}
}
}
stage('DEPLOY PRODUCTION') {
when {
branch 'master'
}
stages {
stage('PRODUCTION DEPLOY PREPARATION') {
steps {
script {
sh 'docker network create --driver bridge ecentrics_concordia_production_network || true'
def rendezvousServerRunning = sh (script: 'docker ps -f name=concordia-rendezvous | \
grep -qE concordia-rendezvous', returnStatus: true)
if ("$rendezvousServerRunning" == '1') {
sh 'docker run \
-d \
-p 9090:9090 \
--name concordia-rendezvous \
--net=ecentrics_concordia_production_network \
libp2p/js-libp2p-webrtc-star:version-0.20.5'
} else {
sh 'docker network connect ecentrics_concordia_production_network concordia-rendezvous || true'
}
}
}
}
stage('DEPLOY CONTRACTS PROVIDER') {
when {
expression {
def contractsProviderProductionRunning = sh (script: 'docker ps -f name=concordia-contracts-provider-production | \
grep -qE concordia-contracts-provider-production', returnStatus: true)
return "${contractsProviderPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "$contractsProviderProductionRunning" == '1' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
sh 'docker stop concordia-contracts-provider-production || true \
&& docker rm concordia-contracts-provider-production || true'
sh 'if [ "$cleanSlateEnabled" -eq "0" ]; then \
docker volume rm concordia-contracts-provider-production || true; \
fi'
sh (script: """docker run \
-d \
-v concordia-contracts-provider-production:/mnt/concordia/contracts \
--env-file=./jenkins/env/contracts.provider.production.env \
-e NODE_ENV=production \
-p 8400:8400 \
--name concordia-contracts-provider-production \
--net=ecentrics_concordia_production_network \
ecentrics/concordia-contracts-provider:v${contractsProviderPackageVersion}""")
}
}
}
stage('RECREATE GANACHE') {
when {
expression {
def ganacheProductionRunning = sh (script: 'docker ps -f name=concordia-ganache-production | \
grep -qE concordia-ganache-production', returnStatus: true)
return "$cleanSlateEnabled" == '0' || "$ganacheProductionRunning" == '1';
}
}
steps {
script {
sh 'docker stop concordia-ganache-production || true \
&& docker rm concordia-ganache-production || true'
sh 'docker volume rm concordia-ganache-production || true'
sh (script: 'docker run \
-d \
-v concordia-ganache-production:/mnt/concordia/ganache_keys \
-p 8545:8545 \
--env-file=./jenkins/env/ganache.production.jenkins.env \
--name concordia-ganache-production \
--net=ecentrics_concordia_production_network \
ecentrics/concordia-ganache:latest')
// Ganache image might take a while to come alive
sleep 10
sh 'mkdir -p ./ganache/ && docker cp concordia-ganache-production:/mnt/concordia/ganache_keys/keys.json ./ganache/'
freshGanacheProductionRunning = true
}
}
}
stage('DEPLOY CONTRACTS') {
when {
expression {
return "${contractsPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "$freshGanacheProductionRunning" || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
sh """docker run \
--rm \
--env-file=./jenkins/env/contracts.production.jenkins.env \
-e CONTRACTS_VERSION_HASH=${contractsPackageVersion} \
--net=ecentrics_concordia_production_network \
ecentrics/concordia-contracts-migrate:v${contractsPackageVersion}"""
}
}
}
stage('DEPLOY PINNER') {
when {
expression {
def pinnerProductionRunning = sh (script: 'docker ps -f name=concordia-pinner-production | \
grep -qE concordia-pinner-production', returnStatus: true)
return "${pinnerPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' || "${pinnerProductionRunning}" == '1' || "${contractsPackageChanged}" == '0' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
sh 'docker stop concordia-pinner-production || true \
&& docker rm concordia-pinner-production || true'
sh 'if [ "$cleanSlateEnabled" -eq "0" ]; then \
docker volume rm concordia-pinner-production || true; \
fi'
sh """docker run \
-d \
-v concordia-pinner-production:/mnt/concordia/orbitdb \
-p 4444:4444 \
-e NODE_ENV=production \
--env-file=./jenkins/env/pinner.production.jenkins.env \
--name concordia-pinner-production \
--net=ecentrics_concordia_production_network \
ecentrics/concordia-pinner:v${pinnerPackageVersion}"""
}
}
}
stage('DEPLOY APP') {
when {
expression {
def appProductionRunning = sh (script: 'docker ps -f name=concordia-app-production | \
grep -qE concordia-app-production', returnStatus: true)
return "${appPackageChanged}" == '0' || "$cleanSlateEnabled" == '0' ||"${appProductionRunning}" == '1' || "${sharedPackageChanged}" == '0';
}
}
steps {
script {
sh 'docker stop concordia-app-production || true \
&& docker rm concordia-app-production || true'
sh """docker run \
-d \
-p 7777:80 \
--env-file=./jenkins/env/concordia.production.jenkins.env \
--name concordia-app-production \
ecentrics/concordia-app:v${appPackageVersion}"""
}
}
}
}
}
}
}

24
jenkins/check_package_changed.sh

@ -0,0 +1,24 @@
#!/bin/bash
# Based on this post:
# https://engineering.brigad.co/only-deploy-services-impacted-by-changes-in-a-mono-repository-18f54b8ac109
APP=$1
# Jenkins should provide these in the environment by default
GIT_COMMIT=$2
GIT_PREVIOUS_COMMIT=$3
ROOT_FILES_AND_FOLDERS=${4:-"package.json" "yarn.lock" ".dockerignore" "docker" "jenkins"}
function join_by { local IFS="$1"; shift; echo "$*"; }
function package_changed { git diff --name-only "$COMMIT_RANGE" | grep -qE "^packages/$1/" && echo true || echo false; }
COMMIT_RANGE="$GIT_PREVIOUS_COMMIT...$GIT_COMMIT"
ROOT_FILES_AND_FOLDERS_ARRAY=($ROOT_FILES_AND_FOLDERS)
ROOT_FILES_AND_FOLDERS_JOINED=$(join_by "|" ${ROOT_FILES_AND_FOLDERS_ARRAY[*]})
ROOT_FILES_CHANGED=$(git diff --name-only "$COMMIT_RANGE" | grep -qE "^($ROOT_FILES_AND_FOLDERS_JOINED)" && echo true || echo false)
IS_FORCE_BUILD=$(git log --oneline "$COMMIT_RANGE" | grep -qE "ci: force" && echo true || echo false)
APP_FILES_CHANGED=$(package_changed ${APP})
($IS_FORCE_BUILD || $ROOT_FILES_CHANGED || $APP_FILES_CHANGED) && echo 0 || echo 1

16
jenkins/env/concordia.production.jenkins.env

@ -0,0 +1,16 @@
VIRTUAL_HOST=concordia.ecentrics.net
VIRTUAL_PORT=7777
LETSENCRYPT_HOST=concordia.ecentrics.net
LETSENCRYPT_EMAIL=ecentricsgr@gmail.com
# Variables needed in runtime (in browser)
REACT_APP_CONCORDIA_HOST=concordia.ecentrics.net
REACT_APP_CONCORDIA_PORT=7777
REACT_APP_RENDEZVOUS_HOST=rendezvous.ecentrics.net
REACT_APP_RENDEZVOUS_PORT=9090
REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER=true
REACT_APP_CONTRACTS_PROVIDER_HOST=contracts.concordia.ecentrics.net
REACT_APP_CONTRACTS_PROVIDER_PORT=8400
REACT_APP_CONTRACTS_VERSION_HASH=stable

16
jenkins/env/concordia.staging.jenkins.env

@ -0,0 +1,16 @@
VIRTUAL_HOST=staging.concordia.ecentrics.net
VIRTUAL_PORT=7000
LETSENCRYPT_HOST=staging.concordia.ecentrics.net
LETSENCRYPT_EMAIL=ecentricsgr@gmail.com
# Variables needed in runtime (in browser)
REACT_APP_CONCORDIA_HOST=staging.concordia.ecentrics.net
REACT_APP_CONCORDIA_PORT=7000
REACT_APP_RENDEZVOUS_HOST=rendezvous.ecentrics.net
REACT_APP_RENDEZVOUS_PORT=9090
REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER=true
REACT_APP_CONTRACTS_PROVIDER_HOST=staging.contracts.concordia.ecentrics.net
REACT_APP_CONTRACTS_PROVIDER_PORT=8450
REACT_APP_CONTRACTS_VERSION_HASH=latest

8
jenkins/env/contracts.production.jenkins.env

@ -0,0 +1,8 @@
# Variables needed in runtime
MIGRATE_NETWORK=env
WEB3_HOST=concordia-ganache-production
WEB3_PORT=8545
CONTRACTS_PROVIDER_HOST=contracts.concordia.ecentrics.net
CONTRACTS_PROVIDER_PORT=8400
CONTRACTS_VERSION_TAG=stable

8
jenkins/env/contracts.provider.production.env

@ -0,0 +1,8 @@
VIRTUAL_HOST=contracts.concordia.ecentrics.net
VIRTUAL_PORT=8400
LETSENCRYPT_HOST=contracts.concordia.ecentrics.net
LETSENCRYPT_EMAIL=ecentricsgr@gmail.com
CONTRACTS_PROVIDER_PORT=8400
UPLOAD_CONTRACTS_DIRECTORY=/mnt/concordia/contracts/
CORS_ALLOWED_ORIGINS="concordia.ecentrics.net;http://concordia.ecentrics.net;https://concordia.ecentrics.net;concordia.ecentrics.net:7777;http://concordia.ecentrics.net:7777;https://concordia.ecentrics.net:7777;127.0.0.1;http://127.0.0.1;127.0.0.1:7777;http://127.0.0.1"

8
jenkins/env/contracts.provider.staging.env

@ -0,0 +1,8 @@
VIRTUAL_HOST=staging.contracts.concordia.ecentrics.net
VIRTUAL_PORT=8450
LETSENCRYPT_HOST=staging.contracts.concordia.ecentrics.net
LETSENCRYPT_EMAIL=ecentricsgr@gmail.com
CONTRACTS_PROVIDER_PORT=8450
UPLOAD_CONTRACTS_DIRECTORY=/mnt/concordia/contracts/
#CORS_ALLOWED_ORIGINS="staging.concordia.ecentrics.net;http://staging.concordia.ecentrics.net;https://staging.concordia.ecentrics.net;staging.concordia.ecentrics.net:7000;http://staging.concordia.ecentrics.net:7000;https://staging.concordia.ecentrics.net:7000;172.21.0.4;http://172.21.0.4;127.0.0.1;http://127.0.0.1"

8
jenkins/env/contracts.staging.jenkins.env

@ -0,0 +1,8 @@
# Variables needed in runtime
MIGRATE_NETWORK=env
WEB3_HOST=concordia-ganache-staging
WEB3_PORT=8555
CONTRACTS_PROVIDER_HOST=staging.contracts.concordia.ecentrics.net
CONTRACTS_PROVIDER_PORT=8450
CONTRACTS_VERSION_TAG=latest

4
jenkins/env/contracts.test.jenkins.env

@ -0,0 +1,4 @@
# Variables needed in runtime
MIGRATE_NETWORK=env
WEB3_HOST=concordia-ganache-test
WEB3_PORT=8546

10
jenkins/env/ganache.production.jenkins.env

@ -0,0 +1,10 @@
VIRTUAL_HOST=ganache.ecentrics.net
VIRTUAL_PORT=8545
LETSENCRYPT_HOST=ganache.ecentrics.net
LETSENCRYPT_EMAIL=ecentricsgr@gmail.com
ACCOUNTS_NUMBER=1000
ACCOUNTS_ETHER=100000
HOST=0.0.0.0
PORT=8545
NETWORK_ID=5778

10
jenkins/env/ganache.staging.jenkins.env

@ -0,0 +1,10 @@
VIRTUAL_HOST=staging.ganache.ecentrics.net
VIRTUAL_PORT=8555
LETSENCRYPT_HOST=staging.ganache.ecentrics.net
LETSENCRYPT_EMAIL=ecentricsgr@gmail.com
ACCOUNTS_NUMBER=100
ACCOUNTS_ETHER=1000
HOST=0.0.0.0
PORT=8555
NETWORK_ID=5778

6
jenkins/env/ganache.test.jenkins.env

@ -0,0 +1,6 @@
ACCOUNTS_NUMBER=5
ACCOUNTS_ETHER=1
MNEMONIC="myth like bonus scare over problem client lizard pioneer submit female collect"
HOST=0.0.0.0
PORT=8546
NETWORK_ID=5778

20
jenkins/env/pinner.production.jenkins.env

@ -0,0 +1,20 @@
VIRTUAL_HOST=pinner.concordia.ecentrics.net
VIRTUAL_PORT=4444
LETSENCRYPT_HOST=pinner.concordia.ecentrics.net
LETSENCRYPT_EMAIL=ecentricsgr@gmail.com
USE_EXTERNAL_CONTRACTS_PROVIDER=true
ORBIT_DIRECTORY=/mnt/concordia/orbitdb
CONTRACTS_PROVIDER_HOST=contracts.concordia.ecentrics.net
CONTRACTS_PROVIDER_PORT=8400
CONTRACTS_VERSION_HASH=stable
PINNER_API_HOST=127.0.0.1
PINNER_API_PORT=4444
RENDEZVOUS_HOST=rendezvous.ecentrics.net
RENDEZVOUS_PORT=9090
WEB3_HOST=ganache.ecentrics.net
WEB3_PORT=8545

20
jenkins/env/pinner.staging.jenkins.env

@ -0,0 +1,20 @@
VIRTUAL_HOST=staging.pinner.concordia.ecentrics.net
VIRTUAL_PORT=5555
LETSENCRYPT_HOST=staging.pinner.concordia.ecentrics.net
LETSENCRYPT_EMAIL=ecentricsgr@gmail.com
USE_EXTERNAL_CONTRACTS_PROVIDER=true
ORBIT_DIRECTORY=/mnt/concordia/orbitdb
CONTRACTS_PROVIDER_HOST=staging.contracts.concordia.ecentrics.net
CONTRACTS_PROVIDER_PORT=8450
CONTRACTS_VERSION_HASH=latest
PINNER_API_HOST=127.0.0.1
PINNER_API_PORT=5555
RENDEZVOUS_HOST=rendezvous.ecentrics.net
RENDEZVOUS_PORT=9090
WEB3_HOST=staging.ganache.ecentrics.net
WEB3_PORT=8555

18
jenkins/hash_build_properties.sh

@ -0,0 +1,18 @@
#!/bin/bash
# Outputs to the stdout a deterministically generated integer in the range 0-4095. The integer is generated using the
# input strings and SHA1.
# Usage: hash_build_properties.sh <branch> <build_number>
# Inputs:
# - branch: the branch being build
# - build_number the incrementing number of the build
BRANCH=$1
BUILD_NUMBER=$2
STRING_TO_HASH="$BRANCH-$BUILD_NUMBER"
SHA1_SUM_HEX=$(sha1sum <<<"$STRING_TO_HASH")
SHA1_TRUNCATED_HEX=$(cut -c1-3 <<<"$SHA1_SUM_HEX")
HASHED_STRING=$((0x${SHA1_TRUNCATED_HEX}))
echo "$HASHED_STRING"

5
jenkins/map_to_thousand.sh

@ -0,0 +1,5 @@
#!/bin/bash
INTEGER_TO_MAP=$1
echo $(( INTEGER_TO_MAP * 999 / 4095 ))

4
packages/concordia-app/public/index.html

@ -20,6 +20,10 @@
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Concordia</title>
<!--
Allow access to runtime env vars after build.
-->
<script src="%PUBLIC_URL%/environment.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

4
packages/concordia-app/src/options/drizzleOptions.js

@ -12,7 +12,9 @@ const drizzleOptions = {
reloadWindowOnAccountChange: true, // We need it to reinitialize breeze and create new Orbit databases
};
if (process.env.REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER) {
if (process.env.REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER
|| (window.runtimeEnv && window.runtimeEnv.REACT_APP_USE_EXTERNAL_CONTRACTS_PROVIDER)) {
console.log('Downloading contracts from external provider');
drizzleOptions.contracts = downloadContractArtifactsSync();
} else {
drizzleOptions.contracts = contracts;

4
packages/concordia-app/src/redux/store.js

@ -28,9 +28,7 @@ const store = configureStore({
preloadedState: initialState,
});
const breezeConfiguration = getBreezeConfiguration(EthereumContractIdentityProvider,
process.env.REACT_APP_RENDEZVOUS_HOST,
process.env.REACT_APP_RENDEZVOUS_PORT);
const breezeConfiguration = getBreezeConfiguration(EthereumContractIdentityProvider);
export const drizzle = new Drizzle(drizzleOptions, store);
export const breeze = new Breeze(breezeConfiguration, store);

8
packages/concordia-app/src/utils/drizzleUtils.js

@ -10,8 +10,12 @@ import {
} from '../constants/configuration/defaults';
function getContractsDownloadRequest() {
const HOST = process.env.REACT_APP_CONCORDIA_HOST || CONCORDIA_HOST_DEFAULT;
const PORT = process.env.REACT_APP_CONCORDIA_PORT || CONCORDIA_PORT_DEFAULT;
const HOST = process.env.REACT_APP_CONCORDIA_HOST
|| (window.runtimeEnv && window.runtimeEnv.REACT_APP_CONCORDIA_HOST)
|| CONCORDIA_HOST_DEFAULT;
const PORT = process.env.REACT_APP_CONCORDIA_PORT
|| (window.runtimeEnv && window.runtimeEnv.REACT_APP_CONCORDIA_PORT)
|| CONCORDIA_PORT_DEFAULT;
const xhrRequest = new XMLHttpRequest();

2
packages/concordia-contracts-provider/package.json

@ -14,6 +14,8 @@
"cors": "^2.8.5",
"esm": "~3.2.25",
"express": "^4.17.1",
"express-async-handler": "^1.1.4",
"helmet": "^4.4.1",
"lodash": "^4.17.20",
"multer": "^1.4.2",
"multiparty": "^4.2.2"

43
packages/concordia-contracts-provider/src/controllers/download.js

@ -1,31 +1,38 @@
import * as fs from 'fs';
import { promises as fs, constants } from 'fs';
import path from 'path';
import { getStorageLocation, getTagsDirectory } from '../utils/storageUtils';
const readContractFilesToArray = (contractsDirectoryPath) => fs
.readdir(contractsDirectoryPath)
.then((contractFilenames) => contractFilenames
.map((contractFilename) => fs
.readFile(path.join(`${contractsDirectoryPath}/${contractFilename}`), 'utf-8')
.then((rawContractData) => JSON.parse(rawContractData))))
.then((contractObjectPromises) => Promise.all([...contractObjectPromises]));
const downloadContracts = async (req, res) => {
const { params: { hash: hashOrTag } } = req;
let directoryPath = getStorageLocation(hashOrTag);
const { params: { hash: identifier } } = req;
const hashBasedDirectoryPath = getStorageLocation(identifier);
if (!fs.existsSync(directoryPath)) {
return fs.access(hashBasedDirectoryPath, constants.R_OK)
.then(() => readContractFilesToArray(hashBasedDirectoryPath))
.catch(() => {
const tagsDirectory = getTagsDirectory();
if (fs.existsSync(tagsDirectory)) {
const tagFilePath = path.join(tagsDirectory, hashOrTag);
const tagReference = fs.readFileSync(tagFilePath, 'utf-8');
directoryPath = getStorageLocation(tagReference);
}
}
return fs
.access(tagsDirectory, constants.R_OK)
.then(() => {
const tagFilePath = path.join(tagsDirectory, identifier);
const contracts = [];
return fs.readFile(tagFilePath, 'utf-8')
.then((tagReference) => {
const tagBasedDirectoryPath = getStorageLocation(tagReference);
fs.readdirSync(directoryPath).forEach((contractFilename) => {
const rawContractData = fs.readFileSync(path.join(`${directoryPath}/${contractFilename}`), 'utf-8');
const contractJson = JSON.parse(rawContractData);
contracts.push(contractJson);
return readContractFilesToArray(tagBasedDirectoryPath);
});
res.send(contracts);
});
}).then((contracts) => res.send(contracts))
.catch(() => Promise.reject(new Error(`No contracts version or tag found for ${identifier}.`)));
};
export default downloadContracts;

45
packages/concordia-contracts-provider/src/controllers/upload.js

@ -1,37 +1,44 @@
import path from 'path';
import fs from 'fs';
import upload from '../middleware/upload';
import { getTagsDirectory } from '../utils/storageUtils';
import { constants, promises as fs } from 'fs';
import uploadFilesUsingMiddleware from '../middleware/upload';
import { getStorageLocation, getTagsDirectory } from '../utils/storageUtils';
const provisionContractsDirectory = (req) => {
const { params: { hash } } = req;
const contractsPath = getStorageLocation(hash);
return fs
.access(contractsPath, constants.W_OK)
.then(() => fs.rmdir(contractsPath, { recursive: true }))
.catch(() => Promise.resolve())
.then(() => fs.mkdir(contractsPath, { recursive: true }));
};
const addOrTransferTag = (tag, hash) => {
const tagsDirectory = getTagsDirectory();
const tagFilePath = path.join(tagsDirectory, tag);
fs.mkdirSync(tagsDirectory, { recursive: true });
fs.writeFileSync(tagFilePath, hash);
return fs
.mkdir(tagsDirectory, { recursive: true })
.then(() => fs.writeFile(tagFilePath, hash, 'utf-8'));
};
const uploadContracts = async (req, res) => {
try {
await upload(req, res);
const uploadContracts = async (req, res) => provisionContractsDirectory(req)
.then(() => uploadFilesUsingMiddleware(req, res)
.then(() => {
if (req.files.length <= 0) {
return Promise.reject(new Error('You must select at least 1 file.'));
}
const { body: { tag } } = req;
const { params: { hash } } = req;
if (tag) {
addOrTransferTag(tag, hash);
}
if (req.files.length <= 0) {
return res.send('You must select at least 1 file.');
return addOrTransferTag(tag, hash)
.then(() => res.send('Files have been uploaded and tagged.'));
}
return res.send('Files have been uploaded.');
} catch (error) {
console.log(error);
return res.send(`Error when trying upload many files: ${error}`);
}
};
}));
export default uploadContracts;

2
packages/concordia-contracts-provider/src/index.js

@ -1,5 +1,6 @@
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import { contractsProviderPort } from 'concordia-shared/src/environment/interpolated/contractsProvider';
import initRoutes from './routes/web';
import constants from './constants';
@ -17,6 +18,7 @@ const corsOptions = {
app.use(express.urlencoded({ extended: true }));
app.use(cors(corsOptions));
app.use(helmet());
initRoutes(app);

4
packages/concordia-contracts-provider/src/middleware/upload.js

@ -1,5 +1,4 @@
import * as util from 'util';
import * as fs from 'fs';
import multer from 'multer';
import { getStorageLocation } from '../utils/storageUtils';
@ -8,7 +7,6 @@ const storage = multer.diskStorage({
const { params: { hash } } = req;
const contractsPath = getStorageLocation(hash);
fs.mkdirSync(contractsPath, { recursive: true });
callback(null, contractsPath);
},
filename: (req, file, callback) => {
@ -16,7 +14,7 @@ const storage = multer.diskStorage({
if (match.indexOf(file.mimetype) === -1) {
const message = `<strong>${file.originalname}</strong> is invalid. Only JSON files are accepted.`;
return callback(message, null);
callback(message, null);
}
const filename = `${file.originalname}`;

5
packages/concordia-contracts-provider/src/routes/web.js

@ -1,12 +1,13 @@
import express from 'express';
import asyncHandler from 'express-async-handler';
import downloadContracts from '../controllers/download';
import uploadContracts from '../controllers/upload';
const router = express.Router();
const routes = (app) => {
router.get('/contracts/:hash', downloadContracts);
router.post('/contracts/:hash', uploadContracts);
router.get('/contracts/:hash', asyncHandler(downloadContracts));
router.post('/contracts/:hash', asyncHandler(uploadContracts));
return app.use('/', router);
};

3
packages/concordia-contracts/package.json

@ -15,7 +15,8 @@
"migrate-upload": "yarn _migrate --network develop && yarn upload",
"migrate-reset-upload": "yarn _migrate --network develop --reset && yarn upload",
"_migrate": "yarn truffle migrate",
"upload": "node ./utils/contractsProviderUtils.js ${npm_package_version}-dev latest"
"upload": "yarn _upload ${npm_package_version}-dev latest",
"_upload": "node ./utils/contractsProviderUtils.js"
},
"dependencies": {
"@openzeppelin/contracts": "~3.3.0",

11
packages/concordia-contracts/test/TestForum.sol

@ -0,0 +1,11 @@
pragma solidity >=0.4.21 <0.7.0;
import "truffle/Assert.sol";
import "../contracts/Forum.sol";
contract TestForum {
function testTrue() public {
Assert.isTrue(true, "Oops placeholder test failed!");
}
}

11
packages/concordia-contracts/test/forum.js

@ -0,0 +1,11 @@
const Forum = artifacts.require('Forum');
contract('Forum', (accounts) => {
it('...should succeed.', async () => {
const forumInstance = await Forum.deployed();
assert
.ok(forumInstance
.signUp('testUsername', { from: accounts[0] }), 'The user was not created.');
});
});

16
packages/concordia-pinner/src/app.js

@ -3,7 +3,7 @@ import _ from 'lodash';
import isReachable from 'is-reachable';
import { pinnerApiPort } from 'concordia-shared/src/environment/interpolated/pinner';
import getWeb3ProviderUrl from 'concordia-shared/src/utils/web3';
import getRendezvousUrl from 'concordia-shared/src/utils/rendezvous';
import { getResolvedRendezvousUrl } from './utils/ipfsUtils';
const POLLING_INTERVAL = 1000;
@ -13,11 +13,17 @@ const responseBody = {
},
orbit: { identity: {}, databases: [] },
web3: { url: getWeb3ProviderUrl(), reachable: false },
rendezvous: { url: getRendezvousUrl(), reachable: false },
rendezvous: { url: '', reachable: false },
timestamp: 0,
};
async function getStats(orbit) {
getResolvedRendezvousUrl().then(({ address }) => {
responseBody.rendezvous.url = address;
});
const getStats = async (orbit) => {
const { address: resolvedRendezvousUrl } = await getResolvedRendezvousUrl();
try {
const ipfs = orbit._ipfs;
const { id } = await ipfs.id();
@ -28,7 +34,7 @@ async function getStats(orbit) {
const orbitIdentity = orbit.identity;
const databases = Object.keys(orbit.stores);
const isWeb3Reachable = await isReachable(getWeb3ProviderUrl());
const isRendezvousReachable = await isReachable(getRendezvousUrl());
const isRendezvousReachable = await isReachable(resolvedRendezvousUrl.address);
const timestamp = +new Date();
responseBody.ipfs.id = id;
@ -44,7 +50,7 @@ async function getStats(orbit) {
} catch (err) {
console.error('Error while getting stats:', err);
}
}
};
const startAPI = (orbit) => {
const app = express();

5
packages/concordia-pinner/src/constants.js

@ -1,6 +1,5 @@
import path from 'path';
import getBreezeConfiguration from 'concordia-shared/src/configuration/breezeConfiguration';
export const swarmAddresses = getBreezeConfiguration().ipfs.config.Addresses.Swarm;
const ORBIT_DIRECTORY_DEFAULT = path.join(__dirname, '..', 'orbitdb');
export const ORBIT_DIRECTORY_DEFAULT = path.join(__dirname, '..', 'orbitdb');
export default ORBIT_DIRECTORY_DEFAULT;

5
packages/concordia-pinner/src/index.js

@ -5,9 +5,9 @@ import { contracts } from 'concordia-contracts';
import { FORUM_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import getWeb3ProviderUrl from 'concordia-shared/src/utils/web3';
import { createOrbitInstance, getPeerDatabases, openKVDBs } from './utils/orbitUtils';
import ipfsOptions from './options/ipfsOptions';
import startAPI from './app';
import downloadContractArtifacts from './utils/drizzleUtils';
import getIpfsOptions from './options/ipfsOptions';
process.on('unhandledRejection', (error) => {
// This happens when attempting to initialize without any available Swarm addresses (e.g. Rendezvous)
@ -68,7 +68,8 @@ const main = async () => {
const web3 = new Web3(new Web3.providers.WebsocketProvider(getWeb3ProviderUrl()));
getDeployedContract(web3)
.then(({ contract, contractAddress }) => IPFS.create(ipfsOptions)
.then(({ contract, contractAddress }) => getIpfsOptions()
.then((ipfsOptions) => IPFS.create(ipfsOptions))
.then((ipfs) => createOrbitInstance(ipfs, contractAddress))
.then((orbit) => openExistingUsersDatabases(contract, orbit)
.then(() => {

13
packages/concordia-pinner/src/options/ipfsOptions.js

@ -1,7 +1,8 @@
import libp2pBundle from './libp2pBundle';
import { swarmAddresses } from '../constants';
import getLibp2pBundle from './libp2pBundle';
import { getSwarmAddresses } from '../utils/ipfsUtils';
export default {
const getIpfsOptions = async () => getSwarmAddresses()
.then((swarmAddresses) => ({
repo: 'ipfs',
config: {
Profile: 'server',
@ -9,7 +10,7 @@ export default {
Swarm: swarmAddresses,
},
},
libp2p: libp2pBundle,
libp2p: getLibp2pBundle(swarmAddresses),
EXPERIMENTAL: {
pubsub: true,
},
@ -19,4 +20,6 @@ export default {
init: {
emptyRepo: true,
},
};
}));
export default getIpfsOptions;

5
packages/concordia-pinner/src/options/libp2pBundle.js

@ -7,10 +7,9 @@ import Gossipsub from 'libp2p-gossipsub';
import KadDHT from 'libp2p-kad-dht';
import MPLEX from 'libp2p-mplex';
import { NOISE } from 'libp2p-noise';
import { swarmAddresses } from '../constants';
// See also: https://github.com/libp2p/js-libp2p/blob/master/doc/CONFIGURATION.md
export default (opts) => new Libp2p({
const getLibp2pBundle = (swarmAddresses) => (opts) => new Libp2p({
peerId: opts.peerId,
addresses: {
listen: swarmAddresses,
@ -88,3 +87,5 @@ export default (opts) => new Libp2p({
maxOldPeersRetention: 50,
},
});
export default getLibp2pBundle;

11
packages/concordia-pinner/src/utils/ipfsUtils.js

@ -0,0 +1,11 @@
import dns from 'dns';
import util from 'util';
import { rendezvousHost, rendezvousPort } from 'concordia-shared/src/environment/interpolated/rendezvous';
const dnsLookup = util.promisify(dns.lookup);
export const getResolvedRendezvousUrl = async () => dnsLookup(rendezvousHost, { family: 4 })
.catch((error) => console.error(new Error(`DNS lookup of ${rendezvousHost} failed.\n${error}`)));
export const getSwarmAddresses = async () => getResolvedRendezvousUrl()
.then((resolvedRendezvousUrl) => [`/ip4/${resolvedRendezvousUrl.address}/tcp/${rendezvousPort}/wss/p2p-webrtc-star`]);

2
packages/concordia-pinner/src/utils/orbitUtils.js

@ -2,7 +2,7 @@ import OrbitDB from 'orbit-db';
import Identities from 'orbit-db-identity-provider';
import { EthereumContractIdentityProvider } from '@ezerous/eth-identity-provider';
import Web3 from 'web3';
import { ORBIT_DIRECTORY_DEFAULT } from '../constants';
import ORBIT_DIRECTORY_DEFAULT from '../constants';
// TODO: share code below with frontend (?)
const determineDBAddress = async ({

6
packages/concordia-shared/src/environment/contractsProviderEnv.js

@ -1,10 +1,16 @@
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
// the REACT_APP_ prefix or not
const runtimeEnv = typeof window !== 'undefined' && window.runtimeEnv;
const contractsProviderHostEnv = process.env.REACT_APP_CONTRACTS_PROVIDER_HOST
|| (runtimeEnv && runtimeEnv.REACT_APP_CONTRACTS_PROVIDER_HOST)
|| process.env.CONTRACTS_PROVIDER_HOST;
const contractsProviderPortEnv = process.env.REACT_APP_CONTRACTS_PROVIDER_PORT
|| (runtimeEnv && runtimeEnv.REACT_APP_CONTRACTS_PROVIDER_PORT)
|| process.env.CONTRACTS_PROVIDER_PORT;
const contractsVersionHashEnv = process.env.REACT_APP_CONTRACTS_VERSION_HASH
|| (runtimeEnv && runtimeEnv.REACT_APP_CONTRACTS_VERSION_HASH)
|| process.env.CONTRACTS_VERSION_HASH;
module.exports = {

11
packages/concordia-shared/src/environment/pinnerEnv.js

@ -1,7 +1,14 @@
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
// the REACT_APP_ prefix or not
const pinnerApiHostEnv = process.env.REACT_APP_PINNER_API_HOST || process.env.PINNER_API_HOST;
const pinnerApiPortEnv = process.env.REACT_APP_PINNER_API_PORT || process.env.PINNER_API_PORT;
const runtimeEnv = typeof window !== 'undefined' && window.runtimeEnv;
const pinnerApiHostEnv = process.env.REACT_APP_PINNER_API_HOST
|| (runtimeEnv && runtimeEnv.REACT_APP_PINNER_API_HOST)
|| process.env.PINNER_API_HOST;
const pinnerApiPortEnv = process.env.REACT_APP_PINNER_API_PORT
|| (runtimeEnv && runtimeEnv.REACT_APP_PINNER_API_PORT)
|| process.env.PINNER_API_PORT;
module.exports = {
pinnerApiHostEnv,

11
packages/concordia-shared/src/environment/rendezvousEnv.js

@ -1,7 +1,14 @@
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
// the REACT_APP_ prefix or not
const rendezvousHostEnv = process.env.REACT_APP_RENDEZVOUS_HOST || process.env.RENDEZVOUS_HOST;
const rendezvousPortEnv = process.env.REACT_APP_RENDEZVOUS_PORT || process.env.RENDEZVOUS_PORT;
const runtimeEnv = typeof window !== 'undefined' && window.runtimeEnv;
const rendezvousHostEnv = process.env.REACT_APP_RENDEZVOUS_HOST
|| (runtimeEnv && runtimeEnv.REACT_APP_RENDEZVOUS_HOST)
|| process.env.RENDEZVOUS_HOST;
const rendezvousPortEnv = process.env.REACT_APP_RENDEZVOUS_PORT
|| (runtimeEnv && runtimeEnv.REACT_APP_RENDEZVOUS_PORT)
|| process.env.RENDEZVOUS_PORT;
module.exports = {
rendezvousHostEnv,

7
packages/concordia-shared/src/environment/web3Env.js

@ -1,8 +1,13 @@
// Depending on the package user (app in contrast to any of the other packages) the env var names should either include
// the REACT_APP_ prefix or not
const runtimeEnv = typeof window !== 'undefined' && window.runtimeEnv;
const web3HostEnv = process.env.REACT_APP_WEB3_HOST
|| (runtimeEnv && runtimeEnv.REACT_APP_WEB3_HOST)
|| process.env.WEB3_HOST;
const web3PortEnv = process.env.REACT_APP_WEB3_PORT
|| (runtimeEnv && runtimeEnv.REACT_APP_WEB3_PORT)
|| process.env.WEB3_PORT;
// Web3 test environment shouldn't be available to the react app
@ -10,8 +15,10 @@ const web3HostTestEnv = process.env.WEB3_HOST_TEST;
const web3PortTestEnv = process.env.WEB3_PORT_TEST;
const web3PortSocketTimeoutEnv = process.env.REACT_APP_WEB3_PORT_SOCKET_TIMEOUT
|| (runtimeEnv && runtimeEnv.REACT_APP_WEB3_PORT_SOCKET_TIMEOUT)
|| process.env.WEB3_PORT_SOCKET_TIMEOUT;
const web3PortSocketConnectMaxAttemptsEnv = process.env.REACT_APP_WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS
|| (runtimeEnv && runtimeEnv.REACT_APP_WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS)
|| process.env.WEB3_PORT_SOCKET_CONNECT_MAX_ATTEMPTS;
module.exports = {

10
yarn.lock

@ -6868,6 +6868,11 @@ explain-error@^1.0.4:
resolved "https://registry.yarnpkg.com/explain-error/-/explain-error-1.0.4.tgz#a793d3ac0cad4c6ab571e9968fbbab6cb2532929"
integrity sha1-p5PTrAytTGq1cemWj7urbLJTKSk=
express-async-handler@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/express-async-handler/-/express-async-handler-1.1.4.tgz#225a84908df63b35ae9df94b6f0f1af061266426"
integrity sha512-HdmbVF4V4w1q/iz++RV7bUxIeepTukWewiJGkoCKQMtvPF11MLTa7It9PRc/reysXXZSEyD4Pthchju+IUbMiQ==
express@^4.14.0, express@^4.17.1:
version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
@ -8016,6 +8021,11 @@ heap@~0.2.6:
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac"
integrity sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw=
helmet@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/helmet/-/helmet-4.4.1.tgz#a17e1444d81d7a83ddc6e6f9bc6e2055b994efe7"
integrity sha512-G8tp0wUMI7i8wkMk2xLcEvESg5PiCitFMYgGRc/PwULB0RVhTP5GFdxOwvJwp9XVha8CuS8mnhmE8I/8dx/pbw==
hex-color-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"

Loading…
Cancel
Save