From c81f309fdd436c5e1b5f581a30fc7a8174dd16bf Mon Sep 17 00:00:00 2001 From: napoly Date: Mon, 21 Nov 2022 19:11:28 +0100 Subject: [PATCH] add dockerize and add project on Github CI/CD --- .github/workflows/build.yml | 57 ++++++++++++ .gitignore | 2 +- README.md | 8 +- config/envoy.test.yaml | 110 ++++++++++++++++------- config/envoy.yaml | 22 +++-- docker/docker-compose.yml | 173 ++++++++++++++++++++++++++++++++++++ docker/haveno/Dockerfile | 21 +++++ docker/pricenode/Dockerfile | 21 +++++ package.json | 2 - scripts/build_dist.sh | 11 --- scripts/build_protobuf.sh | 9 ++ 11 files changed, 381 insertions(+), 55 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 docker/docker-compose.yml create mode 100644 docker/haveno/Dockerfile create mode 100644 docker/pricenode/Dockerfile delete mode 100755 scripts/build_dist.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..854213da --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,57 @@ +name: CI + +on: + push: + pull_request: + paths-ignore: + - '**/README.md' + +jobs: + haveno-ts-e2e: + timeout-minutes: 50 + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Stop Mono service + run: sudo killall mono + + - name: Start containers + run: docker-compose -f "./docker/docker-compose.yml" up -d --build + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Install protoc-gen-grpc-web + run: | + curl -Lo protoc-gen-grpc-web https://github.com/grpc/grpc-web/releases/download/1.4.2/protoc-gen-grpc-web-1.4.2-linux-x86_64 + sudo mv protoc-gen-grpc-web /usr/local/bin + sudo chmod a+x /usr/local/bin/protoc-gen-grpc-web + protoc-gen-grpc-web --version + + - name: Install protoc + run: | + curl -Lo protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v3.20.1/protoc-3.20.1-linux-x86_64.zip + sudo unzip -q protoc.zip bin/protoc -d /usr/local + sudo chmod a+x /usr/local/bin/protoc + rm -rf protoc.zip + protoc --version + + - name: Copy compiled haveno project from node2 container + run: | + sudo docker cp node2:/home/haveno/haveno ./../ + sudo chmod 777 -R ./../haveno + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm run test -- --baseCurrencyNetwork=XMR_LOCAL + + - name: Stop containers + if: always() + run: docker-compose -f "./docker/docker-compose.yml" down diff --git a/.gitignore b/.gitignore index 49c7d40a..2f1131c0 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,4 @@ yarn-debug.log* yarn-error.log* # generated code -/src/protobuf/** \ No newline at end of file +/src/protobuf/** diff --git a/README.md b/README.md index c49b9888..86d5798c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Haveno TypeScript Library +![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/haveno-dex/haveno-ts/build.yml?branch=master) +[![Twitter Follow](https://img.shields.io/twitter/follow/HavenoDEX?style=social)](https://twitter.com/havenodex) +[![Matrix rooms](https://img.shields.io/badge/Matrix%20room-%23haveno-blue)](https://matrix.to/#/#haveno:monero.social) + TypeScript library for using Haveno. ## Install @@ -38,7 +42,7 @@ Running the [API tests](./src/HavenoClient.test.ts) is the best way to develop a 1. [Run a local Haveno test network](https://github.com/haveno-dex/haveno/blob/master/docs/installing.md) and then shut down the arbitrator, user1, and user2 or run them as daemons, e.g. `make user1-daemon-local`. You may omit the arbitrator registration steps since it's done automatically in the tests. 2. Clone this project to the same parent directory as the haveno project: `git clone https://github.com/haveno-dex/haveno-ts` -3. In a new terminal, start envoy with the config in haveno-ts/config/envoy.test.yaml (change absolute path for your system): `docker run --rm --add-host host.docker.internal:host-gateway -it -v ~/git/haveno-ts/config/envoy.test.yaml:/envoy.test.yaml -p 8079:8079 -p 8080:8080 -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8084:8084 -p 8085:8085 -p 8086:8086 envoyproxy/envoy-dev:8a2143613d43d17d1eb35a24b4a4a4c432215606 -c /envoy.test.yaml` +3. In a new terminal, start envoy with the config in haveno-ts/config/envoy.test.yaml (change absolute path for your system): `docker run --rm --add-host host.docker.internal:host-gateway -it -v ~/git/haveno-ts/config/envoy.test.yaml:/envoy.test.yaml -p 8079:8079 -p 8080:8080 -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8084:8084 -p 8085:8085 -p 8086:8086 envoyproxy/envoy-dev:latest -c /envoy.test.yaml` 4. In a new terminal, start the funding wallet. This wallet will be funded automatically in order to fund the tests.
For example: `cd ~/git/haveno && make funding-wallet-local`. 5. Install protobuf compiler v3.19.1 or later for your system:
mac: `brew install protobuf`
@@ -47,4 +51,4 @@ Running the [API tests](./src/HavenoClient.test.ts) is the best way to develop a 6. Download `protoc-gen-grpc-web` plugin and make executable as [shown here](https://github.com/grpc/grpc-web#code-generator-plugin). 7. `cd haveno-ts` 8. `npm install` -9. `npm run test -- --baseCurrencyNetwork=XMR_LOCAL` to run all tests or `npm run test -- --baseCurrencyNetwork=XMR_LOCAL -t "my test"` to run tests by name. \ No newline at end of file +9. `npm run test -- --baseCurrencyNetwork=XMR_LOCAL` to run all tests or `npm run test -- --baseCurrencyNetwork=XMR_LOCAL -t "my test"` to run tests by name. diff --git a/config/envoy.test.yaml b/config/envoy.test.yaml index 28c06c5e..1f8db111 100644 --- a/config/envoy.test.yaml +++ b/config/envoy.test.yaml @@ -37,10 +37,16 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router - - name: alice_listener + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + - name: user1_listener address: socket_address: { address: 0.0.0.0, port_value: 8080 } filter_chains: @@ -58,7 +64,7 @@ static_resources: routes: - match: { prefix: "/" } route: - cluster: alice_service + cluster: user1_service timeout: 0s max_stream_duration: grpc_timeout_header_max: 0s @@ -70,10 +76,16 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router - - name: bob_listener + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + - name: user2_listener address: socket_address: { address: 0.0.0.0, port_value: 8081 } filter_chains: @@ -91,7 +103,7 @@ static_resources: routes: - match: { prefix: "/" } route: - cluster: bob_service + cluster: user2_service timeout: 0s max_stream_duration: grpc_timeout_header_max: 0s @@ -103,9 +115,15 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - name: haveno1_listener address: socket_address: { address: 0.0.0.0, port_value: 8082 } @@ -136,9 +154,15 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - name: haveno2_listener address: socket_address: { address: 0.0.0.0, port_value: 8083 } @@ -169,9 +193,15 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - name: haveno3_listener address: socket_address: { address: 0.0.0.0, port_value: 8084 } @@ -202,9 +232,15 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - name: haveno4_listener address: socket_address: { address: 0.0.0.0, port_value: 8085 } @@ -235,9 +271,15 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router - name: haveno5_listener address: socket_address: { address: 0.0.0.0, port_value: 8086 } @@ -268,9 +310,15 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router clusters: - name: arbitrator_service connect_timeout: 0.25s @@ -286,7 +334,7 @@ static_resources: socket_address: address: host.docker.internal port_value: 9998 - - name: alice_service + - name: user1_service connect_timeout: 0.25s type: logical_dns http2_protocol_options: {} @@ -300,7 +348,7 @@ static_resources: socket_address: address: host.docker.internal port_value: 9999 - - name: bob_service + - name: user2_service connect_timeout: 0.25s type: logical_dns http2_protocol_options: {} @@ -383,4 +431,4 @@ static_resources: address: socket_address: address: host.docker.internal - port_value: 10005 \ No newline at end of file + port_value: 10005 diff --git a/config/envoy.yaml b/config/envoy.yaml index 306c2a4a..786018ad 100644 --- a/config/envoy.yaml +++ b/config/envoy.yaml @@ -1,4 +1,4 @@ -# envoy configuration to run alice ui +# envoy configuration to run user1 ui admin: access_log_path: /tmp/admin_access.log @@ -7,7 +7,7 @@ admin: static_resources: listeners: - - name: alice_listener + - name: user1_listener address: socket_address: { address: 0.0.0.0, port_value: 8080 } filter_chains: @@ -25,7 +25,7 @@ static_resources: routes: - match: { prefix: "/" } route: - cluster: alice_service + cluster: user1_service timeout: 0s max_stream_duration: grpc_timeout_header_max: 0s @@ -37,11 +37,17 @@ static_resources: max_age: "1728000" expose_headers: custom-header-1,grpc-status,grpc-message http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router + - name: envoy.filters.http.grpc_web + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb + - name: envoy.filters.http.cors + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router clusters: - - name: alice_service + - name: user1_service connect_timeout: 0.25s type: logical_dns http2_protocol_options: {} @@ -54,4 +60,4 @@ static_resources: address: socket_address: address: host.docker.internal - port_value: 9999 \ No newline at end of file + port_value: 9999 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 00000000..64bffef1 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,173 @@ +version: '3.9' + +services: + envoy: + image: envoyproxy/envoy-dev:latest + container_name: envoy + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "8079:8079" + - "8080:8080" + - "8081:8081" + - "8082:8082" + - "8083:8083" + - "8084:8084" + - "8085:8085" + - "8086:8086" + volumes: + - ./../config/envoy.test.yaml:/config/envoy.test.yaml + command: + - -c + - ../config/envoy.test.yaml + + node1: + build: haveno/ + container_name: node1 + entrypoint: [ "./.localnet/monerod" ] + command: [ + "--testnet", + "--no-igd", + "--hide-my-port", + "--data-dir=./.localnet/xmr_local/node1", + "--p2p-bind-ip=127.0.0.1", + "--p2p-bind-port=48080", + "--rpc-bind-port=48081", + "--no-zmq", + "--add-exclusive-node=127.0.0.1:28080", + "--rpc-access-control-origins=http://localhost:8080", + "--fixed-difficulty=10", + "--non-interactive", + ] + network_mode: "host" + + node2: + build: haveno/ + container_name: node2 + entrypoint: [ "./.localnet/monerod" ] + command: [ + "--testnet", + "--no-igd", + "--hide-my-port", + "--data-dir=./.localnet/xmr_local/node2", + "--p2p-bind-ip=127.0.0.1", + "--rpc-bind-ip=0.0.0.0", + "--no-zmq", + "--confirm-external-bind", + "--add-exclusive-node=127.0.0.1:48080", + "--rpc-access-control-origins=http://localhost:8080", + "--fixed-difficulty=10", + "--non-interactive", + ] + network_mode: "host" + depends_on: + - node1 + + seed1: + build: haveno/ + container_name: seed1 + entrypoint: [ "./haveno-seednode" ] + command: [ + "--baseCurrencyNetwork=XMR_LOCAL", + "--useLocalhostForP2P=true", + "--useDevPrivilegeKeys=true", + "--nodePort=2002", + "--appName=haveno-XMR_LOCAL_Seed1_2002", + ] + network_mode: "host" + depends_on: + - node2 + + seed2: + build: haveno/ + container_name: seed2 + entrypoint: [ "./haveno-seednode" ] + command: [ + "--baseCurrencyNetwork=XMR_LOCAL", + "--useLocalhostForP2P=true", + "--useDevPrivilegeKeys=true", + "--nodePort=3002", + "--appName=haveno-XMR_LOCAL_Seed2_3002", + ] + network_mode: "host" + depends_on: + - node2 + + arbitrator: + build: haveno/ + container_name: arbitrator + entrypoint: [ "./haveno-daemon" ] + command: [ + "--baseCurrencyNetwork=XMR_LOCAL", + "--useLocalhostForP2P=true", + "--useDevPrivilegeKeys=true", + "--nodePort=4444", + "--appName=haveno-XMR_LOCAL_arbitrator", + "--apiPassword=apitest", + "--apiPort=9998", + "--walletRpcBindPort=38090", + "--passwordRequired=false", + ] + network_mode: "host" + depends_on: + - seed1 + + user1: + build: haveno/ + container_name: user1 + entrypoint: [ "./haveno-daemon" ] + command: [ + "--baseCurrencyNetwork=XMR_LOCAL", + "--useLocalhostForP2P=true", + "--useDevPrivilegeKeys=true", + "--nodePort=5555", + "--appName=haveno_user1", + "--apiPassword=apitest", + "--apiPort=9999", + "--walletRpcBindPort=38091", + "--passwordRequired=false", + ] + network_mode: "host" + depends_on: + - seed1 + + user2: + build: haveno/ + container_name: user2 + entrypoint: [ "./haveno-daemon" ] + command: [ + "--baseCurrencyNetwork=XMR_LOCAL", + "--useLocalhostForP2P=true", + "--useDevPrivilegeKeys=true", + "--nodePort=6666", + "--appName=haveno_user2", + "--apiPassword=apitest", + "--apiPort=10000", + "--walletRpcBindPort=38092", + "--passwordRequired=false", + ] + network_mode: "host" + depends_on: + - seed1 + + pricenode: + build: pricenode/ + container_name: pricenode + entrypoint: [ "./haveno-pricenode" ] + network_mode: "host" + + funding: + build: haveno/ + container_name: funding_wallet + entrypoint: [ "./.localnet/monero-wallet-rpc" ] + command: [ + "--testnet", + "--daemon-address=http://localhost:28081", + "--rpc-bind-port=28084", + "--rpc-login=rpc_user:abc123", + "--rpc-access-control-origins=http://localhost:8080", + "--wallet-dir=./.localnet", + ] + network_mode: "host" + depends_on: + - arbitrator diff --git a/docker/haveno/Dockerfile b/docker/haveno/Dockerfile new file mode 100644 index 00000000..87b46b71 --- /dev/null +++ b/docker/haveno/Dockerfile @@ -0,0 +1,21 @@ +FROM openjdk:11 + +RUN set -ex && \ + apt update && \ + apt --no-install-recommends --yes install \ + make \ + git + +RUN set -ex && adduser --system --group --disabled-password haveno && \ + mkdir -p /home/haveno && \ + chown -R haveno:haveno /home/haveno + +USER haveno + +RUN set -ex && git clone https://github.com/haveno-dex/haveno.git /home/haveno/haveno + +WORKDIR /home/haveno/haveno + +RUN set -ex && make skip-tests + +ENTRYPOINT [ "./haveno-daemon" ] diff --git a/docker/pricenode/Dockerfile b/docker/pricenode/Dockerfile new file mode 100644 index 00000000..b6d433f2 --- /dev/null +++ b/docker/pricenode/Dockerfile @@ -0,0 +1,21 @@ +FROM gradle:jdk11 + +RUN set -ex && \ + apt update && \ + apt --no-install-recommends --yes install \ + make \ + git + +RUN set -ex && adduser --system --group --disabled-password pricenode && \ + mkdir -p /home/pricenode && \ + chown -R pricenode:pricenode /home/pricenode + +USER pricenode + +RUN set -ex && git clone --recursive https://github.com/haveno-dex/haveno-pricenode.git /home/pricenode + +WORKDIR /home/pricenode + +RUN gradle clean build -x test + +ENTRYPOINT [ "./haveno-pricenode" ] diff --git a/package.json b/package.json index 5641768c..2b8cbd2b 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,6 @@ "files": ["dist/**/*"], "scripts": { "prepare": "scripts/build_protobuf.sh", - "pretest": "scripts/build_protobuf.sh", - "build": "./scripts/build_dist.sh", "test": "jest", "eslint": "eslint .", "eslintfix": "eslint src/* --fix", diff --git a/scripts/build_dist.sh b/scripts/build_dist.sh deleted file mode 100755 index 542bcb60..00000000 --- a/scripts/build_dist.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# run typescript compiler -tsc - -# copy protobuf models to dist -mkdir -p dist/protobuf || exit 1 -cp src/protobuf/grpc_pb.d.ts dist/protobuf/grpc_pb.d.ts || exit 1 -cp src/protobuf/grpc_pb.js dist/protobuf/grpc_pb.js || exit 1 -cp src/protobuf/pb_pb.d.ts dist/protobuf/pb_pb.d.ts || exit 1 -cp src/protobuf/pb_pb.js dist/protobuf/pb_pb.js || exit 1 \ No newline at end of file diff --git a/scripts/build_protobuf.sh b/scripts/build_protobuf.sh index a6325044..2e0b228f 100755 --- a/scripts/build_protobuf.sh +++ b/scripts/build_protobuf.sh @@ -4,3 +4,12 @@ mkdir -p ./src/protobuf cd ./src/protobuf || exit 1 protoc -I=../../../haveno/proto/src/main/proto/ ../../../haveno/proto/src/main/proto/*.proto --js_out=import_style=commonjs,binary:./ --grpc-web_out=import_style=typescript,mode=grpcwebtext:./ || exit 1 + +# run typescript compiler +tsc + +# copy protobuf models to dist +cp ./grpc_pb.d.ts ../../dist/protobuf/grpc_pb.d.ts || exit 1 +cp ./grpc_pb.js ../../dist/protobuf/grpc_pb.js || exit 1 +cp ./pb_pb.d.ts ../../dist/protobuf/pb_pb.d.ts || exit 1 +cp ./pb_pb.js ../../dist/protobuf/pb_pb.js || exit 1