diff --git a/Makefile b/Makefile index 9c3fac7d..a06749f6 100644 --- a/Makefile +++ b/Makefile @@ -23,12 +23,17 @@ validation: lint go mod verify govulncheck ./... # should fail on non informational vulnerabilities +COMMIT_TAG ?= $(shell git describe --exact-match --tags) COMMIT_HASH ?= $(shell git rev-parse HEAD) SOURCE_VERSION := $(COMMIT_HASH) +SOURCE_TAG := $(COMMIT_TAG) + build: download mkdir -p build && cd build - @echo "Building liquidity-provider-server $(SOURCE_VERSION)" - CGO_ENABLED=0 go build -v -installsuffix 'static' -ldflags="-s -X 'main.BuildVersion=$(SOURCE_VERSION)' -X 'main.BuildTime=$(shell date)'" -o ./build/liquidity-provider-server ./cmd/application/main.go + @echo "Building liquidity-provider-server $(SOURCE_TAG) ($(SOURCE_VERSION))" + CGO_ENABLED=0 go build -v -installsuffix 'static' \ + -ldflags="-s -X 'main.BuildVersion=$(SOURCE_VERSION)' -X 'main.BuildTime=$(shell date)' -X 'github.com/rsksmart/liquidity-provider-server/internal/usecases/liquidity_provider.BuildVersion=$(SOURCE_TAG)' -X 'github.com/rsksmart/liquidity-provider-server/internal/usecases/liquidity_provider.BuildRevision=$(SOURCE_VERSION)'" \ + -o ./build/liquidity-provider-server ./cmd/application/main.go api: go-swagger3 --module-path . \ diff --git a/OpenApi.yml b/OpenApi.yml index a7f16d19..43063756 100644 --- a/OpenApi.yml +++ b/OpenApi.yml @@ -604,6 +604,20 @@ components: - refundPegoutTxHash - bridgeRefundTxHash type: object + ServerInfoDTO: + properties: + revision: + description: Version commit hash + example: b7bf393a2b1cedde8ee15b00780f44e6e5d2ba9d + type: string + version: + description: Server version tag + example: v1.0.0 + type: string + required: + - version + - revision + type: object Services: properties: btc: @@ -983,6 +997,17 @@ paths: $ref: '#/components/schemas/DepositEventDTO' description: Successfully retrieved the user quotes summary: GetUserQuotes + /version: + get: + description: ' Returns the server version and revision' + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ServerInfoDTO' + description: "" + summary: Get server version servers: - description: ' Testnet' url: https://lps.testnet.flyover.rif.technology diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index 7bda99d1..1a52ce3a 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -52,6 +52,8 @@ services: dockerfile: docker-compose/lps/Dockerfile args: UID: "${LPS_UID}" + COMMIT_HASH: "${COMMIT_HASH}" + COMMIT_TAG: "${COMMIT_TAG}" image: lps:latest container_name: lps01 environment: diff --git a/docker-compose/local/docker-compose.lps.yml b/docker-compose/local/docker-compose.lps.yml index 57e416a3..9cec01ad 100644 --- a/docker-compose/local/docker-compose.lps.yml +++ b/docker-compose/local/docker-compose.lps.yml @@ -6,6 +6,8 @@ services: dockerfile: docker-compose/lps/Dockerfile args: UID: "${LPS_UID}" + COMMIT_HASH: "${COMMIT_HASH}" + COMMIT_TAG: "${COMMIT_TAG}" image: lps:latest container_name: lps01 environment: diff --git a/docker-compose/local/lps-env.sh b/docker-compose/local/lps-env.sh index 34b8ec80..5cc6b969 100755 --- a/docker-compose/local/lps-env.sh +++ b/docker-compose/local/lps-env.sh @@ -2,6 +2,11 @@ set -e +COMMIT_HASH=$(git rev-parse HEAD) +COMMIT_TAG=$(git describe --exact-match --tags) +export COMMIT_HASH +export COMMIT_TAG + if [ -z "${LPS_STAGE}" ]; then echo "LPS_STAGE is not set. Exit 1" exit 1 @@ -16,7 +21,8 @@ else fi if [ -z "${LPS_UID}" ]; then - export LPS_UID=$(id -u) + LPS_UID=$(id -u) + export LPS_UID if [ "$LPS_UID" = "0" ]; then echo "Please set LPS_UID env var or run as a non-root user" exit 1 @@ -58,7 +64,7 @@ elif [ "$SCRIPT_CMD" = "deploy" ]; then exit 0 elif [ "$SCRIPT_CMD" = "import-rsk-db" ]; then echo "Importing rsk db..." - docker compose --env-file "$ENV_FILE" run -d rskj java -Xmx6g -Drpc.providers.web.http.bind_address=0.0.0.0 -Drpc.providers.web.http.hosts.0=localhost -Drpc.providers.web.http.hosts.1=rskj -cp rskj-core.jar co.rsk.Start --${LPS_STAGE} --import + docker compose --env-file "$ENV_FILE" run -d rskj java -Xmx6g -Drpc.providers.web.http.bind_address=0.0.0.0 -Drpc.providers.web.http.hosts.0=localhost -Drpc.providers.web.http.hosts.1=rskj -cp rskj-core.jar co.rsk.Start --"${LPS_STAGE}" --import exit 0 elif [ "$SCRIPT_CMD" = "start-bitcoind" ]; then echo "Starting bitcoind..." @@ -90,7 +96,7 @@ echo "LPS_UID: $LPS_UID; BTCD_HOME: '$BTCD_HOME'; RSKJ_HOME: '$RSKJ_HOME'; LPS_H # start bitcoind and RSKJ dependant services docker compose --env-file "$ENV_FILE" up -d bitcoind rskj mongodb localstack -# read env vars +# shellcheck disable=SC1090 . ./"$ENV_FILE" echo "Waiting for RskJ to be up and running..." @@ -127,8 +133,6 @@ curl -s "http://127.0.0.1:5555" --user "$BTC_USERNAME:$BTC_PASSWORD" -H "Content | jq .result | xargs -I ADDRESS curl -s "http://127.0.0.1:5555" --user "$BTC_USERNAME:$BTC_PASSWORD" -H "Content-Type: application/json" -d '{"jsonrpc": "1.0", "method": "generatetoaddress", "params": [1, "ADDRESS"], "id":"generatetoaddress"}' if [ "$LPS_STAGE" = "regtest" ]; then - PROVIDER_RSK_ADDR_LINE=$(cat "$ENV_FILE" | grep "$LIQUIDITY_PROVIDER_RSK_ADDR" | head -n 1 | tr -d '\r') - PROVIDER_RSK_ADDR="${PROVIDER_RSK_ADDR_LINE#"$LIQUIDITY_PROVIDER_RSK_ADDR="}" PROVIDER_TX_COUNT=$(curl -s -X POST "http://127.0.0.1:4444" -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionCount\",\"params\": [\"$LIQUIDITY_PROVIDER_RSK_ADDR\",\"latest\"],\"id\":1}" | jq -r ".result") if [ "$PROVIDER_TX_COUNT" = "0x0" ]; then echo "Transferring funds to $LIQUIDITY_PROVIDER_RSK_ADDR..." @@ -160,11 +164,11 @@ echo "LBC deployed at $LBC_ADDR" docker compose --env-file "$ENV_FILE" up -d powpeg-pegin powpeg-pegout # start LPS -docker compose --env-file "$ENV_FILE" -f docker-compose.yml -f docker-compose.lps.yml build --build-arg COMMIT_HASH="$(git rev-parse HEAD)" lps +docker compose --env-file "$ENV_FILE" -f docker-compose.yml -f docker-compose.lps.yml build lps docker compose --env-file "$ENV_FILE" -f docker-compose.yml -f docker-compose.lps.yml up -d lps FAIL=true -for i in {1..10} +for ((i=1;i<=10;i++)); do sleep 5 curl -s "http://localhost:8080/health" \ @@ -192,7 +196,7 @@ CSRF_TOKEN=$(curl -s -c cookie_jar.txt -H 'Content-Type: application/json' \ -H 'Sec-Fetch-Site: same-origin' \ "http://localhost:8080/management" | sed -n 's/.*name="csrf"[^>]*value="\([^"]*\)".*/\1/p') -CSRF_TOKEN=$(echo "$CSRF_TOKEN" | sed 's/+/+/g') +CSRF_TOKEN=${CSRF_TOKEN//+/+} curl -s -b cookie_jar.txt -c cookie_jar.txt "http://localhost:8080/management/login" \ -H "X-CSRF-Token: $CSRF_TOKEN" \ -H 'Content-Type: application/json' \ @@ -287,4 +291,4 @@ curl -s -b cookie_jar.txt 'http://localhost:8080/pegout/configuration' \ "expireBlocks": 500, "bridgeTransactionMin": "1500000000000000000" } - }' \ No newline at end of file + }' diff --git a/docker-compose/lps/Dockerfile b/docker-compose/lps/Dockerfile index a573a62b..cfb32e2f 100644 --- a/docker-compose/lps/Dockerfile +++ b/docker-compose/lps/Dockerfile @@ -1,7 +1,9 @@ FROM --platform=linux/amd64 golang:1.22.8@sha256:0ca97f4ab335f4b284a5b8190980c7cdc21d320d529f2b643e8a8733a69bfb6b AS builder ARG COMMIT_HASH -ENV COMMIT_HASH=${COMMIT_HASH} +ARG COMMIT_TAG +ENV COMMIT_HASH_VALUE=${COMMIT_HASH} +ENV COMMIT_TAG_VALUE=${COMMIT_TAG} WORKDIR /code @@ -10,7 +12,7 @@ COPY cmd ./cmd COPY pkg ./pkg COPY internal ./internal -RUN make build +RUN test -n "$COMMIT_TAG_VALUE" && test -n "$COMMIT_HASH_VALUE" && make build FROM --platform=linux/amd64 alpine:3.19.1@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b diff --git a/docker-compose/mainnet/docker-compose.yml b/docker-compose/mainnet/docker-compose.yml index a75e2715..3800bbea 100644 --- a/docker-compose/mainnet/docker-compose.yml +++ b/docker-compose/mainnet/docker-compose.yml @@ -22,6 +22,8 @@ services: dockerfile: docker-compose/lps/Dockerfile args: UID: "${LPS_UID}" + COMMIT_HASH: "${COMMIT_HASH}" + COMMIT_TAG: "${COMMIT_TAG}" image: lps:latest container_name: lps01 environment: diff --git a/docs/LP-Management.md b/docs/LP-Management.md index f4373005..83377e2d 100644 --- a/docs/LP-Management.md +++ b/docs/LP-Management.md @@ -1,7 +1,7 @@ # Liquidity Provider Server - Liquidity Provider specification The intent of this document is to explain all the points that the liquidity provider (LP) should know in order to operate his instance of the liquidity provider server (LPS). -This document contains both technical and non-technical information, so it is recommended to be reviewed by the LP itself and the person who is in change of +This document contains both technical and non-technical information, so it is recommended to be reviewed by the LP itself and the person who is in change of setting up the environment where the LPS is going to be deployed. ## Table of contents @@ -20,17 +20,17 @@ If you are a liquidity provider, and you're not interested in the technical deta - [Wallet Management](#wallet-management) ## Context -In the Flyover Protocol, there are two main actors, the regular user (user), who is party interested in executing Peg-In/Peg-Out operations and the Liquidity -Provider (LP), who puts liquidity to speed up the operation for the user in exchange for a fee as a reward. In order to do this, the user and the LP need to +In the Flyover Protocol, there are two main actors, the regular user (user), who is party interested in executing Peg-In/Peg-Out operations and the Liquidity +Provider (LP), who puts liquidity to speed up the operation for the user in exchange for a fee as a reward. In order to do this, the user and the LP need to agree on the terms of the service (a Peg-In/Peg-Out *Quote*). This implies that the different LPs may offer different quotes, so the user needs to be able to interact with each LP to receive quote details and decide which one is going to use for the operation. -The user interacts with the Flyover Protocol through the [Flyover SDK](https://github.com/rsksmart/unified-bridges-sdk/tree/main/packages/flyover-sdk). This +The user interacts with the Flyover Protocol through the [Flyover SDK](https://github.com/rsksmart/unified-bridges-sdk/tree/main/packages/flyover-sdk). This SDK fetches the list of the available LP from the liquidity bridge contract (LBC), this contract returns a list where each element has some information about -the LP, among this information will be the URL of the liquidity provider server (LPS) instance of that LP so the user can communicate with it. This means +the LP, among this information will be the URL of the liquidity provider server (LPS) instance of that LP so the user can communicate with it. This means that **the LPS has an API that every user interacts with to do the quote agreement**. -The LP also needs to interact with the protocol to perform some management operations related to topics such as collateral, funds, fees management, configuration, +The LP also needs to interact with the protocol to perform some management operations related to topics such as collateral, funds, fees management, configuration, etc. The LP does this operation through the LPS, that's the reason why the LPS also has an API that the LP interacts with to perform various management operations. To summarize, the LPS has two main APIs: @@ -55,14 +55,14 @@ environment where the LPS will run. By default, the Management API is disabled, and it can be enabled only by setting the `ENABLE_MANAGEMENT_API` environment variable to `true`. This is a security measure to ensure that the API will only be accessible if it is explicitly enabled by the LP (or the person setting up the environment). -Once this variable is set to true **it is responsibility of the LP and the person setting up the environment to ensure that the API is properly secured**. +Once this variable is set to true **it is responsibility of the LP and the person setting up the environment to ensure that the API is properly secured**. ### Management UI Access The LPS provides a Management UI out of the box to facilitate the interaction with the Management API. To go to that UI you just need to go to `/management` page in your browser. In order to interact with this API, the LP needs to be authenticated. The authentication mechanisms consists in user/password credentials. There is a default credentials -pair which is `admin` as username and a random password that the LPS will generate on its startup in the file `management_password.txt` inside the temporal directory +pair which is `admin` as username and a random password that the LPS will generate on its startup in the file `management_password.txt` inside the temporal directory of your OS. E. g.: `/tmp/management_password.txt`. The first time that the LP enters the Management UI he will be asked to provide the default credentials and set the new ones to use from that point to the future. @@ -108,13 +108,14 @@ whether it should be treated as public or secured as a private endpoint. | /management/logout | POST | PRIVATE | Logout from the Management API | | /management/credentials | POST | PRIVATE | Update credentials for Management API login | | /management | GET | PRIVATE | Serve Management UI | +| /version | GET | PUBLIC | Get server version info | ## Wallet management The LPS performs operations in behalf of the LP during the process of the protocol, it means that it requires access to both LP's Bitcoin and Rootstock wallets. To be more specific, it requires access to the RSK wallet of the LP and by having it, it also has access to the BTC wallet associated with that RSK wallet. -The LPS has the following options to be provided with the access of that wallet, and depending on the option picked by the LP (set with +The LPS has the following options to be provided with the access of that wallet, and depending on the option picked by the LP (set with the value of the `WALLET` environment variable), the LP will need to manage those wallets in a different way: ### Run LPS using local wallet integration @@ -168,5 +169,3 @@ of the ways that the AWS client allows (through a file in home directory, enviro the secrets to use through the environment variables (that are listed below). This is the recommended option for productive environments. - `KEY_SECRET` - `PASSWORD_SECRET` - - diff --git a/internal/adapters/entrypoints/rest/handlers/get_version_info.go b/internal/adapters/entrypoints/rest/handlers/get_version_info.go new file mode 100644 index 00000000..61649755 --- /dev/null +++ b/internal/adapters/entrypoints/rest/handlers/get_version_info.go @@ -0,0 +1,26 @@ +package handlers + +import ( + "github.com/rsksmart/liquidity-provider-server/internal/adapters/entrypoints/rest" + "github.com/rsksmart/liquidity-provider-server/internal/usecases/liquidity_provider" + "github.com/rsksmart/liquidity-provider-server/pkg" + "net/http" +) + +// NewVersionInfoHandler +// @Title Get server version +// @Description Returns the server version and revision +// @Route /version [get] +// @Success 200 object pkg.ServerInfoDTO +func NewVersionInfoHandler(useCase *liquidity_provider.ServerInfoUseCase) http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + version, err := useCase.Run() + if err != nil { + rest.JsonErrorResponse(w, http.StatusInternalServerError, rest.NewErrorResponse(err.Error(), false)) + return + } + + dto := pkg.ToServerInfoDTO(version) + rest.JsonResponseWithBody(w, http.StatusOK, &dto) + } +} diff --git a/internal/adapters/entrypoints/rest/registry/registry.go b/internal/adapters/entrypoints/rest/registry/registry.go index 4c3eb13b..6fa8d942 100644 --- a/internal/adapters/entrypoints/rest/registry/registry.go +++ b/internal/adapters/entrypoints/rest/registry/registry.go @@ -34,4 +34,5 @@ type UseCaseRegistry interface { GetPeginStatusUseCase() *pegin.StatusUseCase GetPegoutStatusUseCase() *pegout.StatusUseCase GetAvailableLiquidityUseCase() *liquidity_provider.GetAvailableLiquidityUseCase + GetServerInfoUseCase() *liquidity_provider.ServerInfoUseCase } diff --git a/internal/adapters/entrypoints/rest/routes/public.go b/internal/adapters/entrypoints/rest/routes/public.go index 4776fd1f..831a89f2 100644 --- a/internal/adapters/entrypoints/rest/routes/public.go +++ b/internal/adapters/entrypoints/rest/routes/public.go @@ -93,5 +93,12 @@ func GetPublicEndpoints(useCaseRegistry registry.UseCaseRegistry) []PublicEndpoi Handler: handlers.NewGetAvailableLiquidityHandler(useCaseRegistry.GetAvailableLiquidityUseCase()), }, }, + { + Endpoint: Endpoint{ + Path: "/version", + Method: http.MethodGet, + Handler: handlers.NewVersionInfoHandler(useCaseRegistry.GetServerInfoUseCase()), + }, + }, } } diff --git a/internal/adapters/entrypoints/rest/routes/public_test.go b/internal/adapters/entrypoints/rest/routes/public_test.go index 00140ba6..74f18a18 100644 --- a/internal/adapters/entrypoints/rest/routes/public_test.go +++ b/internal/adapters/entrypoints/rest/routes/public_test.go @@ -28,6 +28,7 @@ func TestGetPublicEndpoints(t *testing.T) { registryMock.EXPECT().GetPeginStatusUseCase().Return(&pegin.StatusUseCase{}) registryMock.EXPECT().GetPegoutStatusUseCase().Return(&pegout.StatusUseCase{}) registryMock.EXPECT().GetAvailableLiquidityUseCase().Return(&liquidity_provider.GetAvailableLiquidityUseCase{}) + registryMock.EXPECT().GetServerInfoUseCase().Return(&liquidity_provider.ServerInfoUseCase{}) endpoints := routes.GetPublicEndpoints(registryMock) specBytes := test.ReadFile(t, "OpenApi.yml") @@ -36,7 +37,7 @@ func TestGetPublicEndpoints(t *testing.T) { err := yaml.Unmarshal(specBytes, spec) require.NoError(t, err) - assert.Len(t, endpoints, 11) + assert.Len(t, endpoints, 12) for _, endpoint := range endpoints { lowerCaseMethod := strings.ToLower(endpoint.Method) assert.NotNilf(t, spec.Paths[endpoint.Path][lowerCaseMethod], "Handler not found for path %s and verb %s", endpoint.Path, endpoint.Method) diff --git a/internal/adapters/entrypoints/rest/routes/routes_test.go b/internal/adapters/entrypoints/rest/routes/routes_test.go index c1ebdc5e..e26e4d92 100644 --- a/internal/adapters/entrypoints/rest/routes/routes_test.go +++ b/internal/adapters/entrypoints/rest/routes/routes_test.go @@ -237,6 +237,7 @@ func setupRegistryMock(registryMock *mocks.UseCaseRegistryMock) { registryMock.EXPECT().SetCredentialsUseCase().Return(&liquidity_provider.SetCredentialsUseCase{}) registryMock.EXPECT().LoginUseCase().Return(&liquidity_provider.LoginUseCase{}) registryMock.EXPECT().GetManagementUiDataUseCase().Return(&liquidity_provider.GetManagementUiDataUseCase{}) + registryMock.EXPECT().GetServerInfoUseCase().Return(&liquidity_provider.ServerInfoUseCase{}) } func assertHasCorsHeaders(t *testing.T, recorder *httptest.ResponseRecorder) { diff --git a/internal/configuration/registry/usecase.go b/internal/configuration/registry/usecase.go index 25b77e6b..3e7d3aa1 100644 --- a/internal/configuration/registry/usecase.go +++ b/internal/configuration/registry/usecase.go @@ -57,6 +57,7 @@ type UseCaseRegistry struct { pegoutStatusUseCase *pegout.StatusUseCase availableLiquidityUseCase *liquidity_provider.GetAvailableLiquidityUseCase updatePeginDepositUseCase *watcher.UpdatePeginDepositUseCase + getServerInfoUseCase *liquidity_provider.ServerInfoUseCase } // NewUseCaseRegistry @@ -231,6 +232,7 @@ func NewUseCaseRegistry( pegoutStatusUseCase: pegout.NewStatusUseCase(databaseRegistry.PegoutRepository), availableLiquidityUseCase: liquidity_provider.NewGetAvailableLiquidityUseCase(liquidityProvider, liquidityProvider, liquidityProvider), updatePeginDepositUseCase: watcher.NewUpdatePeginDepositUseCase(databaseRegistry.PeginRepository), + getServerInfoUseCase: liquidity_provider.NewServerInfoUseCase(), } } @@ -341,3 +343,7 @@ func (registry *UseCaseRegistry) GetPegoutStatusUseCase() *pegout.StatusUseCase func (registry *UseCaseRegistry) GetAvailableLiquidityUseCase() *liquidity_provider.GetAvailableLiquidityUseCase { return registry.availableLiquidityUseCase } + +func (registry *UseCaseRegistry) GetServerInfoUseCase() *liquidity_provider.ServerInfoUseCase { + return registry.getServerInfoUseCase +} diff --git a/internal/entities/liquidity_provider/configuration.go b/internal/entities/liquidity_provider/configuration.go index 7aa26630..8e2d9d63 100644 --- a/internal/entities/liquidity_provider/configuration.go +++ b/internal/entities/liquidity_provider/configuration.go @@ -93,3 +93,8 @@ func (confirmations ConfirmationsPerAmount) ForValue(value *entities.Wei) uint16 return confirmations[values[index]] } } + +type ServerInfo struct { + Version string + Revision string +} diff --git a/internal/usecases/common.go b/internal/usecases/common.go index 9436012b..d026227b 100644 --- a/internal/usecases/common.go +++ b/internal/usecases/common.go @@ -57,6 +57,7 @@ const ( PegoutQuoteStatusId UseCaseId = "PegoutQuoteStatus" GetAvailableLiquidityId UseCaseId = "GetAvailableLiquidity" UpdatePeginDepositId UseCaseId = "UpdatePeginDeposit" + ServerInfoId UseCaseId = "ServerInfo" ) var ( diff --git a/internal/usecases/liquidity_provider/server_info.go b/internal/usecases/liquidity_provider/server_info.go new file mode 100644 index 00000000..cf665d43 --- /dev/null +++ b/internal/usecases/liquidity_provider/server_info.go @@ -0,0 +1,28 @@ +package liquidity_provider + +import ( + "errors" + "github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider" + "github.com/rsksmart/liquidity-provider-server/internal/usecases" +) + +var ( + BuildVersion string + BuildRevision string +) + +type ServerInfoUseCase struct{} + +func NewServerInfoUseCase() *ServerInfoUseCase { + return &ServerInfoUseCase{} +} + +func (useCase *ServerInfoUseCase) Run() (liquidity_provider.ServerInfo, error) { + if BuildVersion == "" || BuildRevision == "" { + return liquidity_provider.ServerInfo{}, usecases.WrapUseCaseError(usecases.ServerInfoId, errors.New("unable to read build info")) + } + return liquidity_provider.ServerInfo{ + Version: BuildVersion, + Revision: BuildRevision, + }, nil +} diff --git a/internal/usecases/liquidity_provider/server_info_test.go b/internal/usecases/liquidity_provider/server_info_test.go new file mode 100644 index 00000000..b4235c82 --- /dev/null +++ b/internal/usecases/liquidity_provider/server_info_test.go @@ -0,0 +1,36 @@ +package liquidity_provider_test + +import ( + lp "github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider" + "github.com/rsksmart/liquidity-provider-server/internal/usecases/liquidity_provider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "testing" +) + +func TestServerInfoUseCase_Run(t *testing.T) { + t.Run("Should return error if BuildRevision doesn't have any value", func(t *testing.T) { + liquidity_provider.BuildVersion = "version" + liquidity_provider.BuildRevision = "" + useCase := liquidity_provider.NewServerInfoUseCase() + result, err := useCase.Run() + assert.Empty(t, result) + require.Error(t, err) + }) + t.Run("Should return error if BuildVersion doesn't have any value", func(t *testing.T) { + liquidity_provider.BuildVersion = "" + liquidity_provider.BuildRevision = "revision" + useCase := liquidity_provider.NewServerInfoUseCase() + result, err := useCase.Run() + assert.Empty(t, result) + require.Error(t, err) + }) + t.Run("Should return ServerInfo with BuildVersion and BuildRevision", func(t *testing.T) { + liquidity_provider.BuildVersion = "version" + liquidity_provider.BuildRevision = "revision" + useCase := liquidity_provider.NewServerInfoUseCase() + result, err := useCase.Run() + assert.Equal(t, lp.ServerInfo{Version: "version", Revision: "revision"}, result) + require.NoError(t, err) + }) +} diff --git a/pkg/liquidity_provider.go b/pkg/liquidity_provider.go index adc00418..32b85f5f 100644 --- a/pkg/liquidity_provider.go +++ b/pkg/liquidity_provider.go @@ -82,6 +82,11 @@ type AvailableLiquidityDTO struct { PegoutLiquidityAmount *big.Int `json:"pegoutLiquidityAmount" example:"500000000" description:"Available liquidity for PegOut operations in satoshi" required:""` } +type ServerInfoDTO struct { + Version string `json:"version" example:"v1.0.0" description:"Server version tag" required:""` + Revision string `json:"revision" example:"b7bf393a2b1cedde8ee15b00780f44e6e5d2ba9d" description:"Version commit hash" required:""` +} + func ToAvailableLiquidityDTO(entity liquidity_provider.AvailableLiquidity) AvailableLiquidityDTO { satoshis, _ := entity.PegoutLiquidity.ToSatoshi().Int(nil) return AvailableLiquidityDTO{ @@ -135,3 +140,10 @@ func FromPegoutConfigurationDTO(dto PegoutConfigurationDTO) liquidity_provider.P BridgeTransactionMin: entities.NewBigWei(bridgeTransactionMin), } } + +func ToServerInfoDTO(entity liquidity_provider.ServerInfo) ServerInfoDTO { + return ServerInfoDTO{ + Version: entity.Version, + Revision: entity.Revision, + } +} diff --git a/pkg/liquidity_provider_test.go b/pkg/liquidity_provider_test.go index ab642f7d..bc4373ff 100644 --- a/pkg/liquidity_provider_test.go +++ b/pkg/liquidity_provider_test.go @@ -63,3 +63,13 @@ func TestFromPegoutConfigurationDTO(t *testing.T) { assert.Equal(t, uint64(20), configuration.ExpireBlocks) assert.Equal(t, "8000000000000000000000", configuration.BridgeTransactionMin.AsBigInt().String()) } + +func TestToServerInfoDTO(t *testing.T) { + serverInfo := liquidity_provider.ServerInfo{ + Version: "1.0.0", + Revision: "1234567890", + } + dto := pkg.ToServerInfoDTO(serverInfo) + assert.Equal(t, "1.0.0", dto.Version) + assert.Equal(t, "1234567890", dto.Revision) +} diff --git a/test/lp-swap/docker-compose.lps.yml b/test/lp-swap/docker-compose.lps.yml index d86bb03a..ee1179b6 100644 --- a/test/lp-swap/docker-compose.lps.yml +++ b/test/lp-swap/docker-compose.lps.yml @@ -3,6 +3,9 @@ services: build: context: ../../ dockerfile: docker-compose/lps/Dockerfile + args: + COMMIT_HASH: "${COMMIT_HASH}" + COMMIT_TAG: "${COMMIT_TAG}" image: lps:latest depends_on: - mongodb diff --git a/test/mocks/use_case_registry_mock.go b/test/mocks/use_case_registry_mock.go index 404b4dba..0b3a8090 100644 --- a/test/mocks/use_case_registry_mock.go +++ b/test/mocks/use_case_registry_mock.go @@ -825,6 +825,53 @@ func (_c *UseCaseRegistryMock_GetProvidersUseCase_Call) RunAndReturn(run func() return _c } +// GetServerInfoUseCase provides a mock function with given fields: +func (_m *UseCaseRegistryMock) GetServerInfoUseCase() *liquidity_provider.ServerInfoUseCase { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetServerInfoUseCase") + } + + var r0 *liquidity_provider.ServerInfoUseCase + if rf, ok := ret.Get(0).(func() *liquidity_provider.ServerInfoUseCase); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*liquidity_provider.ServerInfoUseCase) + } + } + + return r0 +} + +// UseCaseRegistryMock_GetServerInfoUseCase_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetServerInfoUseCase' +type UseCaseRegistryMock_GetServerInfoUseCase_Call struct { + *mock.Call +} + +// GetServerInfoUseCase is a helper method to define mock.On call +func (_e *UseCaseRegistryMock_Expecter) GetServerInfoUseCase() *UseCaseRegistryMock_GetServerInfoUseCase_Call { + return &UseCaseRegistryMock_GetServerInfoUseCase_Call{Call: _e.mock.On("GetServerInfoUseCase")} +} + +func (_c *UseCaseRegistryMock_GetServerInfoUseCase_Call) Run(run func()) *UseCaseRegistryMock_GetServerInfoUseCase_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *UseCaseRegistryMock_GetServerInfoUseCase_Call) Return(_a0 *liquidity_provider.ServerInfoUseCase) *UseCaseRegistryMock_GetServerInfoUseCase_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *UseCaseRegistryMock_GetServerInfoUseCase_Call) RunAndReturn(run func() *liquidity_provider.ServerInfoUseCase) *UseCaseRegistryMock_GetServerInfoUseCase_Call { + _c.Call.Return(run) + return _c +} + // GetUserDepositsUseCase provides a mock function with given fields: func (_m *UseCaseRegistryMock) GetUserDepositsUseCase() *pegout.GetUserDepositsUseCase { ret := _m.Called()