From 46337d4f945aae21a9e97a056fcd0deb03ec8617 Mon Sep 17 00:00:00 2001 From: Urvi Date: Fri, 19 Jul 2024 01:23:02 -0700 Subject: [PATCH 1/4] Revert ledgerexport relocation --- .github/workflows/ledgerexporter-release.yml | 59 +++ .github/workflows/ledgerexporter.yml | 46 ++ Makefile | 4 +- .../ledgerexporter/DEVELOPER_GUIDE.md | 82 ++++ exp/services/ledgerexporter/Makefile | 45 ++ exp/services/ledgerexporter/README.md | 129 +++++ exp/services/ledgerexporter/architecture.png | Bin 0 -> 357065 bytes .../ledgerexporter/config.example.toml | 42 ++ exp/services/ledgerexporter/docker/Dockerfile | 34 ++ .../ledgerexporter/docker/config.test.toml | 13 + exp/services/ledgerexporter/internal/app.go | 286 +++++++++++ .../ledgerexporter/internal/app_test.go | 115 +++++ .../ledgerexporter/internal/config.go | 293 ++++++++++++ .../ledgerexporter/internal/config_test.go | 448 ++++++++++++++++++ .../ledgerexporter/internal/exportmanager.go | 124 +++++ .../internal/exportmanager_test.go | 225 +++++++++ .../internal/integration_test.go | 354 ++++++++++++++ .../internal/ledger_meta_archive.go | 43 ++ .../internal/ledger_meta_archive_test.go | 71 +++ exp/services/ledgerexporter/internal/main.go | 104 ++++ .../ledgerexporter/internal/main_test.go | 123 +++++ exp/services/ledgerexporter/internal/queue.go | 58 +++ .../ledgerexporter/internal/queue_test.go | 63 +++ .../internal/test/10perfile.toml | 6 + .../internal/test/15perfile.toml | 6 + .../internal/test/1perfile.toml | 6 + .../internal/test/64perfile.toml | 6 + .../internal/test/captive-core-test.cfg | 12 + .../test/integration_captive_core.cfg | 21 + .../test/integration_config_template.toml | 15 + .../test/invalid_captive_core_toml_path.toml | 5 + .../internal/test/invalid_empty.toml | 1 + .../test/invalid_preconfigured_network.toml | 4 + .../internal/test/no_core_bin.toml | 3 + .../ledgerexporter/internal/test/test.toml | 13 + .../internal/test/useragent.toml | 7 + .../test/valid_captive_core_manual.toml | 5 + .../test/valid_captive_core_override.toml | 4 + .../valid_captive_core_override_archives.toml | 4 + .../valid_captive_core_preconfigured.toml | 4 + .../internal/test/validate_start_end.toml | 6 + .../ledgerexporter/internal/uploader.go | 167 +++++++ .../ledgerexporter/internal/uploader_test.go | 326 +++++++++++++ exp/services/ledgerexporter/main.go | 16 + 44 files changed, 3396 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ledgerexporter-release.yml create mode 100644 .github/workflows/ledgerexporter.yml create mode 100644 exp/services/ledgerexporter/DEVELOPER_GUIDE.md create mode 100644 exp/services/ledgerexporter/Makefile create mode 100644 exp/services/ledgerexporter/README.md create mode 100644 exp/services/ledgerexporter/architecture.png create mode 100644 exp/services/ledgerexporter/config.example.toml create mode 100644 exp/services/ledgerexporter/docker/Dockerfile create mode 100644 exp/services/ledgerexporter/docker/config.test.toml create mode 100644 exp/services/ledgerexporter/internal/app.go create mode 100644 exp/services/ledgerexporter/internal/app_test.go create mode 100644 exp/services/ledgerexporter/internal/config.go create mode 100644 exp/services/ledgerexporter/internal/config_test.go create mode 100644 exp/services/ledgerexporter/internal/exportmanager.go create mode 100644 exp/services/ledgerexporter/internal/exportmanager_test.go create mode 100644 exp/services/ledgerexporter/internal/integration_test.go create mode 100644 exp/services/ledgerexporter/internal/ledger_meta_archive.go create mode 100644 exp/services/ledgerexporter/internal/ledger_meta_archive_test.go create mode 100644 exp/services/ledgerexporter/internal/main.go create mode 100644 exp/services/ledgerexporter/internal/main_test.go create mode 100644 exp/services/ledgerexporter/internal/queue.go create mode 100644 exp/services/ledgerexporter/internal/queue_test.go create mode 100644 exp/services/ledgerexporter/internal/test/10perfile.toml create mode 100644 exp/services/ledgerexporter/internal/test/15perfile.toml create mode 100644 exp/services/ledgerexporter/internal/test/1perfile.toml create mode 100644 exp/services/ledgerexporter/internal/test/64perfile.toml create mode 100644 exp/services/ledgerexporter/internal/test/captive-core-test.cfg create mode 100644 exp/services/ledgerexporter/internal/test/integration_captive_core.cfg create mode 100644 exp/services/ledgerexporter/internal/test/integration_config_template.toml create mode 100644 exp/services/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml create mode 100644 exp/services/ledgerexporter/internal/test/invalid_empty.toml create mode 100644 exp/services/ledgerexporter/internal/test/invalid_preconfigured_network.toml create mode 100644 exp/services/ledgerexporter/internal/test/no_core_bin.toml create mode 100644 exp/services/ledgerexporter/internal/test/test.toml create mode 100644 exp/services/ledgerexporter/internal/test/useragent.toml create mode 100644 exp/services/ledgerexporter/internal/test/valid_captive_core_manual.toml create mode 100644 exp/services/ledgerexporter/internal/test/valid_captive_core_override.toml create mode 100644 exp/services/ledgerexporter/internal/test/valid_captive_core_override_archives.toml create mode 100644 exp/services/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml create mode 100644 exp/services/ledgerexporter/internal/test/validate_start_end.toml create mode 100644 exp/services/ledgerexporter/internal/uploader.go create mode 100644 exp/services/ledgerexporter/internal/uploader_test.go create mode 100644 exp/services/ledgerexporter/main.go diff --git a/.github/workflows/ledgerexporter-release.yml b/.github/workflows/ledgerexporter-release.yml new file mode 100644 index 0000000000..8738f53def --- /dev/null +++ b/.github/workflows/ledgerexporter-release.yml @@ -0,0 +1,59 @@ +name: Ledger Exporter release + +on: + push: + tags: ['ledgerexporter-v*'] + +jobs: + + publish-docker: + name: Test and push the Ledger Exporter images + runs-on: ubuntu-latest + env: + LEDGEREXPORTER_INTEGRATION_TESTS_ENABLED: "true" + LEDGEREXPORTER_INTEGRATION_TESTS_CAPTIVE_CORE_BIN: /usr/bin/stellar-core + # this pins to a version of quickstart:testing that has the same version as STELLAR_CORE_VERSION + # this is the multi-arch index sha, get it by 'docker buildx imagetools inspect stellar/quickstart:testing' + LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE: docker.io/stellar/quickstart:testing@sha256:03c6679f838a92b1eda4cd3a9e2bdee4c3586e278a138a0acf36a9bc99a0041f + LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE_PULL: "false" + STELLAR_CORE_VERSION: 21.1.0-1921.b3aeb14cc.focal + steps: + - name: Set VERSION + run: | + echo "VERSION=${GITHUB_REF_NAME#ledgerexporter-v}" >> $GITHUB_ENV + + - uses: actions/checkout@v3 + with: + ref: ${{ github.sha }} + - name: Pull Quickstart image + shell: bash + run: | + docker pull "$LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE" + - name: Install captive core + run: | + # Workaround for https://github.com/actions/virtual-environments/issues/5245, + # libc++1-8 won't be installed if another version is installed (but apt won't give you a helpul + # message about why the installation fails) + sudo apt list --installed | grep libc++ + sudo apt-get remove -y libc++1-* libc++abi1-* || true + + sudo wget -qO - https://apt.stellar.org/SDF.asc | APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=true sudo apt-key add - + sudo bash -c 'echo "deb https://apt.stellar.org focal unstable" > /etc/apt/sources.list.d/SDF-unstable.list' + sudo apt-get update && sudo apt-get install -y stellar-core="$STELLAR_CORE_VERSION" + echo "Using stellar core version $(stellar-core version)" + + - name: Run Ledger Exporter test + run: go test -v -race -run TestLedgerExporterTestSuite ./exp/services/ledgerexporter/... + + - name: Build Ledger Exporter docker + run: make -C exp/services/ledgerexporter docker-build + + # Push images + - name: Login to DockerHub + uses: docker/login-action@bb984efc561711aaa26e433c32c3521176eae55b + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Push to DockerHub + run: make -C exp/services/ledgerexporter docker-push diff --git a/.github/workflows/ledgerexporter.yml b/.github/workflows/ledgerexporter.yml new file mode 100644 index 0000000000..ac1e265582 --- /dev/null +++ b/.github/workflows/ledgerexporter.yml @@ -0,0 +1,46 @@ +name: LedgerExporter + +on: + push: + branches: [master] + pull_request: + +jobs: + ledger-exporter: + name: Test Ledger Exporter + runs-on: ubuntu-latest + env: + CAPTIVE_CORE_DEBIAN_PKG_VERSION: 21.1.0-1921.b3aeb14cc.focal + LEDGEREXPORTER_INTEGRATION_TESTS_ENABLED: "true" + LEDGEREXPORTER_INTEGRATION_TESTS_CAPTIVE_CORE_BIN: /usr/bin/stellar-core + # this pins to a version of quickstart:testing that has the same version of core + # as specified on LEDGEREXPORTER_INTEGRATION_TESTS_CAPTIVE_CORE_BIN + # this is the multi-arch index sha, get it by 'docker buildx imagetools inspect stellar/quickstart:testing' + LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE: docker.io/stellar/quickstart:testing@sha256:5c8186f53cc98571749054dd782dce33b0aca2d1a622a7610362f7c15b79b1bf + LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE_PULL: "false" + steps: + - name: Install captive core + run: | + # Workaround for https://github.com/actions/virtual-environments/issues/5245, + # libc++1-8 won't be installed if another version is installed (but apt won't give you a helpul + # message about why the installation fails) + sudo apt list --installed | grep libc++ + sudo apt-get remove -y libc++1-* libc++abi1-* || true + + sudo wget -qO - https://apt.stellar.org/SDF.asc | APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=true sudo apt-key add - + sudo bash -c 'echo "deb https://apt.stellar.org focal unstable" > /etc/apt/sources.list.d/SDF-unstable.list' + sudo apt-get update && sudo apt-get install -y stellar-core="$CAPTIVE_CORE_DEBIAN_PKG_VERSION" + echo "Using stellar core version $(stellar-core version)" + + - name: Pull Quickstart image + shell: bash + run: | + docker pull "$LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE" + + - uses: actions/checkout@v3 + with: + # For pull requests, build and test the PR head not a merge of the PR with the destination. + ref: ${{ github.event.pull_request.head.sha || github.ref }} + + - name: Run Ledger Exporter test + run: go test -v -race -run TestLedgerExporterTestSuite ./exp/services/ledgerexporter/... diff --git a/Makefile b/Makefile index 6e41e653bb..69d46f68c3 100644 --- a/Makefile +++ b/Makefile @@ -34,8 +34,8 @@ friendbot: horizon: $(MAKE) -C services/horizon/ binary-build -galexie: - $(MAKE) -C services/galexie/ docker-build +ledger-exporter: + $(MAKE) -C exp/services/ledgerexporter/ docker-build webauth: $(MAKE) -C exp/services/webauth/ docker-build diff --git a/exp/services/ledgerexporter/DEVELOPER_GUIDE.md b/exp/services/ledgerexporter/DEVELOPER_GUIDE.md new file mode 100644 index 0000000000..28a16ec1b0 --- /dev/null +++ b/exp/services/ledgerexporter/DEVELOPER_GUIDE.md @@ -0,0 +1,82 @@ + +# Ledger Exporter Developer Guide +The ledger exporter is a tool to export Stellar network transaction data to cloud storage in a way that is easy to access. + +## Prerequisites +This document assumes that you have installed and can run the ledger exporter, and that you have familiarity with its CLI and configuration. If not, please refer to the [Installation Guide](./README.md). + +## Goal +The goal of the ledger exporter is to build an easy-to-use tool to export Stellar network ledger data to a configurable remote data store, such as cloud blob storage. + - Use cloud storage optimally + - Minimize network usage to export + - Make it easy and fast to search for a specific ledger or ledger range + +## Architecture +To achieve its goals, the ledger exporter uses the following architecture, which consists of the 3 main components: +- Captive-core to extract raw transaction metadata from the Stellar Network. +- Export manager to bundles and organizes the ledgers to get them ready for export. +- The cloud storage plugin writes to the cloud storage. This is specific to the type of cloud storage, GCS in this case. + + +![ledgerexporter-architecture](./architecture.png) + + +## Data Format +- Ledger exporter uses a compact and efficient data format called [XDR](https://developers.stellar.org/docs/learn/encyclopedia/data-format/xdr) (External Data Representation), which is a compact binary format. A Stellar Captive Core instance emits data in this format and the data structure is referred to as `LedgerCloseMeta`. The exporter bundles multiple `LedgerCloseMeta`'s into a single object using a custom XDR structure called `LedgerCloseMetaBatch` which is defined in [Stellar-exporter.x](https://github.com/stellar/go/blob/master/xdr/Stellar-exporter.x). + +- The metadata for the same batch is also stored alongside each exported object. Supported metadata is defined in [metadata.go](https://github.com/stellar/go/blob/master/support/datastore/metadata.go). + +- Objects are compressed before uploading using the [zstd](http://facebook.github.io/zstd/) (zstandard) compression algorithm to optimize network usage and storage needs. + +## Data Storage +- An example implementation of `DataStore` for GCS, Google Cloud Storage. This plugin is located in the [support](https://github.com/stellar/go/tree/master/support/datastore) package. +- The ledger exporter currently implements the interface only for Google Cloud Storage (GCS). The [GCS plugin](https://github.com/stellar/go/blob/master/support/datastore/gcs_datastore.go) uses GCS-specific behaviors like conditional puts, automatic retry, metadata, and CRC checksum. + +## Build and Run using Docker +The Dockerfile contains all the necessary dependencies (e.g., Stellar-core) required to run the ledger exporter. + +- Build: To build the Docker container, use the provided [Makefile](./Makefile). Simply run make `make docker-build` to build a new container after making any changes. + +- Run: For instructions on running the Docker container, refer to the [Installation Guide](./README.md). + +- Run ledgerexporter with a local, fake GCS backend: Requires `make docker-build` first, then run `make docker-test-fake-gcs`. This will run the ledger exporter against `testnet` and export to the 'fake' GCS instance started in the container. + +## Running Integration Tests: +from top directory of stellar/go repo, run go test to launch ledger exporter integration +tests. + +`LEDGEREXPORTER_INTEGRATION_TESTS_ENABLED=true` is required environment variable to allow +tests to run. + +Optional, tests will try to run `stellar-core` from o/s PATH for captive core, if not resolvable, then set `LEDGEREXPORTER_INTEGRATION_TESTS_CAPTIVE_CORE_BIN=/path/to/stellar-core` + +Optional, can override the version of quickstart used to run standalone stellar network, `LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE=docker.io/stellar/quickstart:`. By default it will try to docker pull `stellar/quickstart:testing` image to local host's docker image store. Set `LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE_PULL=false` to skip the pull, if you know host has up to date image. + +Note, the version of stellar core in `LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE` and `LEDGEREXPORTER_INTEGRATION_TESTS_CAPTIVE_CORE_BIN` needs to be on the same major rev or the captive core process may not be able to join or parse ledger meta from the `local` network created by `LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE` + +``` +$ LEDGEREXPORTER_INTEGRATION_TESTS_ENABLED=true go test -v -race -run TestLedgerExporterTestSuite ./exp/services/ledgerexporter/... +``` + +## Adding support for a new storage type +Support for different data storage types are encapsulated as 'plugins', which are implementation of `DataStore` interface in a go package. To add a data storage plugin based on a new storage type (e.g. AWS S3), follow these steps: + +- A data storage plugin must implement the [DataStore](https://github.com/stellar/go/blob/master/support/datastore/datastore.go) interface. +- Add support for new datastore-specific features. Implement any datastore-specific custom logic. Different datastores have different ways of handling + - race conditions + - automatic retries + - metadata storage, etc. +- Add the new datastore to the factory function [NewDataStore](https://github.com/stellar/go/blob/master/support/datastore/datastore.go). +- Add a [config](./config.example.toml) section for the new storage type. This may include configurations like destination, authentication information etc. +- An emulator such as a GCS emulator [fake-gcs-server](https://github.com/fsouza/fake-gcs-server) can be used for testing without connecting to real cloud storage. + +### Design DOs and DONTs +- Multiple exporters should be able to run in parallel without the need for explicit locking or synchronization. +- Exporters when restarted do not have any memory of prior operation and rely on the already exported data as much as possible to decide where to resume. + +## Using exported data +The exported data in storage can be used in the ETL pipeline to gather analytics and reporting. To write a tool that consumes exported data you can use Stellar ingestion library's `ledgerbackend` package. This package includes a ledger backend called [BufferedStorageBackend](https://github.com/stellar/go/blob/master/ingest/ledgerbackend/buffered_storage_backend.go), +which imports data from the storage and validates it. For more details, refer to the ledgerbackend [documentation](https://github.com/stellar/go/tree/master/ingest/ledgerbackend). + +## Contributing +For information on how to contribute, please refer to our [Contribution Guidelines](https://github.com/stellar/go/blob/master/CONTRIBUTING.md). diff --git a/exp/services/ledgerexporter/Makefile b/exp/services/ledgerexporter/Makefile new file mode 100644 index 0000000000..6561c4f24c --- /dev/null +++ b/exp/services/ledgerexporter/Makefile @@ -0,0 +1,45 @@ +SUDO := $(shell docker version >/dev/null 2>&1 || echo "sudo") + +# https://github.com/opencontainers/image-spec/blob/master/annotations.md +BUILD_DATE := $(shell date -u +%FT%TZ) +VERSION ?= $(shell git rev-parse --short HEAD) +DOCKER_IMAGE := stellar/ledger-exporter + +docker-build: + cd ../../../ && \ + $(SUDO) docker build --platform linux/amd64 --pull --label org.opencontainers.image.created="$(BUILD_DATE)" \ + --build-arg GOFLAGS="-ldflags=-X=github.com/stellar/go/exp/services/ledgerexporter/internal.version=$(VERSION)" \ +$(if $(STELLAR_CORE_VERSION), --build-arg STELLAR_CORE_VERSION=$(STELLAR_CORE_VERSION)) \ + -f exp/services/ledgerexporter/docker/Dockerfile \ + -t $(DOCKER_IMAGE):$(VERSION) \ + -t $(DOCKER_IMAGE):latest . + +docker-clean: + $(SUDO) docker stop fake-gcs-server || true + $(SUDO) docker rm fake-gcs-server || true + $(SUDO) rm -rf ${PWD}/storage || true + $(SUDO) docker network rm test-network || true + +docker-test-fake-gcs: docker-clean + # Create temp storage dir + $(SUDO) mkdir -p ${PWD}/storage/exporter-test + + # Create test network for docker + $(SUDO) docker network create test-network + + # Run the fake GCS server + $(SUDO) docker run -d --name fake-gcs-server -p 4443:4443 \ + -v ${PWD}/storage:/data --network test-network fsouza/fake-gcs-server -scheme http + + # Run the ledger-exporter + $(SUDO) docker run --platform linux/amd64 -t --network test-network\ + -v ${PWD}/exp/services/ledgerexporter/docker/config.test.toml:/config.toml \ + -e STORAGE_EMULATOR_HOST=http://fake-gcs-server:4443 \ + $(DOCKER_IMAGE):$(VERSION) \ + scan-and-fill --start 1000 --end 2000 + + $(MAKE) docker-clean + +docker-push: + $(SUDO) docker push $(DOCKER_IMAGE):$(VERSION) + $(SUDO) docker push $(DOCKER_IMAGE):latest diff --git a/exp/services/ledgerexporter/README.md b/exp/services/ledgerexporter/README.md new file mode 100644 index 0000000000..8308bfdaeb --- /dev/null +++ b/exp/services/ledgerexporter/README.md @@ -0,0 +1,129 @@ +## Ledger Exporter: Installation and Usage Guide + +This guide provides step-by-step instructions on installing and using the Ledger Exporter, a tool that exports Stellar network ledger data to a Google Cloud Storage (GCS) bucket for efficient analysis and storage. + +* [Prerequisites](#prerequisites) +* [Setup](#setup) + * [Set Up GCP Credentials](#set-up-gcp-credentials) + * [Create a GCS Bucket for Storage](#create-a-gcs-bucket-for-storage) +* [Running the Ledger Exporter](#running-the-ledger-exporter) + * [Pull the Docker Image](#1-pull-the-docker-image) + * [Configure the Exporter](#2-configure-the-exporter-configtoml) + * [Run the Exporter](#3-run-the-exporter) +* [Command Line Interface (CLI)](#command-line-interface-cli) + 1. [scan-and-fill: Fill Data Gaps](#1-scan-and-fill-fill-data-gaps) + 2. [append: Continuously Export New Data](#2-append-continuously-export-new-data) + +## Prerequisites + +* **Google Cloud Platform (GCP) Account:** You will need a GCP account to create a GCS bucket for storing the exported data. +* **Docker:** Allows you to run the Ledger Exporter in a self-contained environment. The official Docker installation guide: [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/) + +## Setup + +### Set Up GCP Credentials + +Create application default credentials for your Google Cloud Platform (GCP) project by following these steps: +1. Download the [SDK](https://cloud.google.com/sdk/docs/install). +2. Install and initialize the [gcloud CLI](https://cloud.google.com/sdk/docs/initializing). +3. Create [application authentication credentials](https://cloud.google.com/docs/authentication/provide-credentials-adc#google-idp) and store it in a secure location on your system, such as $HOME/.config/gcloud/application_default_credentials.json. + +For detailed instructions, refer to the [Providing Credentials for Application Default Credentials (ADC) guide.](https://cloud.google.com/docs/authentication/provide-credentials-adc) + +### Create a GCS Bucket for Storage + +1. Go to the GCP Console's Storage section ([https://console.cloud.google.com/storage](https://console.cloud.google.com/storage)) and create a new bucket. +2. Choose a descriptive name for the bucket, such as `stellar-ledger-data`. Refer to [Google Cloud Storage Bucket Naming Guideline](https://cloud.google.com/storage/docs/buckets#naming) for more information. +3. **Note down the bucket name** as you'll need it later in the configuration process. + + +## Running the Ledger Exporter + +### 1. Pull the Docker Image + +Open a terminal window and download the Stellar Ledger Exporter Docker image using the following command: + +```bash +docker pull stellar/ledger-exporter +``` + +### 2. Configure the Exporter (config.toml) +The Ledger Exporter relies on a configuration file (config.toml) to connect to your specific environment. This file defines details like: +- Your Google Cloud Storage (GCS) bucket where exported ledger data will be stored. +- Stellar network settings, such as the network you're using (testnet or pubnet). +- Datastore schema to control data organization. + +A sample configuration file [config.example.toml](config.example.toml) is provided. Copy and rename it to config.toml for customization. Edit the copied file (config.toml) to replace placeholders with your specific details. + +### 3. Run the Exporter + +The following command demonstrates how to run the Ledger Exporter: + +```bash +docker run --platform linux/amd64 \ + -v "$HOME/.config/gcloud/application_default_credentials.json":/.config/gcp/credentials.json:ro \ + -e GOOGLE_APPLICATION_CREDENTIALS=/.config/gcp/credentials.json \ + -v ${PWD}/config.toml:/config.toml \ + stellar/ledger-exporter [options] +``` + +**Explanation:** + +* `--platform linux/amd64`: Specifies the platform architecture (adjust if needed for your system). +* `-v`: Mounts volumes to map your local GCP credentials and config.toml file to the container: + * `$HOME/.config/gcloud/application_default_credentials.json`: Your local GCP credentials file. + * `${PWD}/config.toml`: Your local configuration file. +* `-e GOOGLE_APPLICATION_CREDENTIALS=/.config/gcp/credentials.json`: Sets the environment variable for credentials within the container. +* `stellar/ledger-exporter`: The Docker image name. +* ``: The Stellar Ledger Exporter command: [append](#1-append-continuously-export-new-data), [scan-and-fill](#2-scan-and-fill-fill-data-gaps)) + +## Command Line Interface (CLI) + +The Ledger Exporter offers two mode of operation for exporting ledger data: + +### 1. append: Continuously Export New Data + + +Exports ledgers initially searching from --start, looking for the next absent ledger sequence number proceeding --start on the data store. If abscence is detected, the export range is narrowed to `--start `. +This feature requires ledgers to be present on the remote data store for some (possibly empty) prefix of the requested range and then absent for the (possibly empty) remainder. + +In this mode, the --end ledger can be provided to stop the process once export has reached that ledger, or if absent or 0 it will result in continous exporting of new ledgers emitted from the network. + +It’s guaranteed that ledgers exported during `append` mode from `start` and up to the last logged ledger file `Uploaded {ledger file name}` were contiguous, meaning all ledgers within that range were exported to the data lake with no gaps or missing ledgers in between. + + +**Usage:** + +```bash +docker run --platform linux/amd64 -d \ + -v "$HOME/.config/gcloud/application_default_credentials.json":/.config/gcp/credentials.json:ro \ + -e GOOGLE_APPLICATION_CREDENTIALS=/.config/gcp/credentials.json \ + -v ${PWD}/config.toml:/config.toml \ + stellar/ledger-exporter \ + append --start [--end ] [--config-file ] +``` + +Arguments: +- `--start ` (required): The starting ledger sequence number for the export process. +- `--end ` (optional): The ending ledger sequence number. If omitted or set to 0, the exporter will continuously export new ledgers as they appear on the network. +- `--config-file ` (optional): The path to your configuration file, containing details like GCS bucket information. If not provided, the exporter will look for config.toml in the directory where you run the command. + +### 2. scan-and-fill: Fill Data Gaps + +Scans the datastore (GCS bucket) for the specified ledger range and exports any missing ledgers to the datastore. This mode avoids unnecessary exports if the data is already present. The range is specified using the --start and --end options. + +**Usage:** + +```bash +docker run --platform linux/amd64 -d \ + -v "$HOME/.config/gcloud/application_default_credentials.json":/.config/gcp/credentials.json:ro \ + -e GOOGLE_APPLICATION_CREDENTIALS=/.config/gcp/credentials.json \ + -v ${PWD}/config.toml:/config.toml \ + stellar/ledger-exporter \ + scan-and-fill --start --end [--config-file ] +``` + +Arguments: +- `--start ` (required): The starting ledger sequence number in the range to export. +- `--end ` (required): The ending ledger sequence number in the range. +- `--config-file ` (optional): The path to your configuration file, containing details like GCS bucket information. If not provided, the exporter will look for config.toml in the directory where you run the command. \ No newline at end of file diff --git a/exp/services/ledgerexporter/architecture.png b/exp/services/ledgerexporter/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..85bd6d8b31d6224a6897681351c9b8f90f48d479 GIT binary patch literal 357065 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

    f@md6p3SRM@8L&e;~8irL4IX0dnAWFBIx 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

    Z|>RsK38qm5_F7@ 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 z%0D+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/etc/apt/sources.list.d/SDF.list +RUN echo "deb https://apt.stellar.org focal unstable" >/etc/apt/sources.list.d/SDF-unstable.list +RUN apt-get update && apt-get install -y stellar-core=${STELLAR_CORE_VERSION} +RUN apt-get clean + +COPY --from=builder /go/bin/ledgerexporter /usr/bin/ledgerexporter + +ENTRYPOINT ["/usr/bin/ledgerexporter"] + +CMD ["--help"] + diff --git a/exp/services/ledgerexporter/docker/config.test.toml b/exp/services/ledgerexporter/docker/config.test.toml new file mode 100644 index 0000000000..c5c4519f0b --- /dev/null +++ b/exp/services/ledgerexporter/docker/config.test.toml @@ -0,0 +1,13 @@ +[datastore_config] +type = "GCS" + +[datastore_config.params] +destination_bucket_path = "exporter-test/ledgers/testnet" + +[datastore_config.schema] +ledgers_per_file = 1 +files_per_partition = 64000 + +[stellar_core_config] + network = "testnet" + diff --git a/exp/services/ledgerexporter/internal/app.go b/exp/services/ledgerexporter/internal/app.go new file mode 100644 index 0000000000..00382f00e4 --- /dev/null +++ b/exp/services/ledgerexporter/internal/app.go @@ -0,0 +1,286 @@ +package ledgerexporter + +import ( + "context" + "fmt" + "net/http" + "os" + "os/exec" + "os/signal" + "sync" + "syscall" + "time" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" + "github.com/prometheus/client_golang/prometheus/promhttp" + + "github.com/stellar/go/historyarchive" + "github.com/stellar/go/ingest/ledgerbackend" + "github.com/stellar/go/support/datastore" + supporthttp "github.com/stellar/go/support/http" + "github.com/stellar/go/support/log" +) + +const ( + adminServerReadTimeout = 5 * time.Second + adminServerShutdownTimeout = time.Second * 5 + // TODO: make this timeout configurable + uploadShutdownTimeout = 10 * time.Second + // We expect the queue size to rarely exceed 1 or 2 because + // upload speeds are expected to be much faster than the rate at which + // captive core emits ledgers. However, configuring a higher capacity + // than our expectation is useful because if we observe a large queue + // size in our metrics that is an indication that uploads to the + // data store have degraded + uploadQueueCapacity = 128 +) + +var ( + logger = log.New().WithField("service", "ledger-exporter") + version = "develop" +) + +func NewDataAlreadyExportedError(Start uint32, End uint32) *DataAlreadyExportedError { + return &DataAlreadyExportedError{ + Start: Start, + End: End, + } +} + +type DataAlreadyExportedError struct { + Start uint32 + End uint32 +} + +func (m DataAlreadyExportedError) Error() string { + return fmt.Sprintf("For export ledger range start=%d, end=%d, the remote storage has all the data, there is no need to continue export", m.Start, m.End) +} + +func NewInvalidDataStoreError(LedgerSequence uint32, LedgersPerFile uint32) *InvalidDataStoreError { + return &InvalidDataStoreError{ + LedgerSequence: LedgerSequence, + LedgersPerFile: LedgersPerFile, + } +} + +type InvalidDataStoreError struct { + LedgerSequence uint32 + LedgersPerFile uint32 +} + +func (m InvalidDataStoreError) Error() string { + return fmt.Sprintf("The remote data store has inconsistent data, "+ + "a resumable starting ledger of %v was identified, "+ + "but that is not aligned to expected ledgers-per-file of %v. use 'scan-and-fill' sub-command to bypass", + m.LedgerSequence, m.LedgersPerFile) +} + +type App struct { + config *Config + ledgerBackend ledgerbackend.LedgerBackend + dataStore datastore.DataStore + exportManager *ExportManager + uploader Uploader + adminServer *http.Server +} + +func NewApp() *App { + logger.SetLevel(log.DebugLevel) + app := &App{} + return app +} + +func (a *App) init(ctx context.Context, runtimeSettings RuntimeSettings) error { + var err error + var archive historyarchive.ArchiveInterface + + logger.Infof("Starting Ledger Exporter with version %s", version) + + registry := prometheus.NewRegistry() + registry.MustRegister( + collectors.NewProcessCollector(collectors.ProcessCollectorOpts{Namespace: "ledger_exporter"}), + collectors.NewGoCollector(), + ) + + if a.config, err = NewConfig(runtimeSettings, nil); err != nil { + return errors.Wrap(err, "Could not load configuration") + } + if archive, err = a.config.GenerateHistoryArchive(ctx, logger); err != nil { + return err + } + if err = a.config.ValidateAndSetLedgerRange(ctx, archive); err != nil { + return err + } + + if a.dataStore, err = datastore.NewDataStore(ctx, a.config.DataStoreConfig); err != nil { + return errors.Wrap(err, "Could not connect to destination data store") + } + if a.config.Resumable() { + if err = a.applyResumability(ctx, + datastore.NewResumableManager(a.dataStore, a.config.DataStoreConfig.Schema, archive)); err != nil { + return err + } + } + + logger.Infof("Final computed ledger range for backend retrieval and export, start=%d, end=%d", a.config.StartLedger, a.config.EndLedger) + + if a.ledgerBackend, err = newLedgerBackend(a.config, registry); err != nil { + return err + } + + queue := NewUploadQueue(uploadQueueCapacity, registry) + if a.exportManager, err = NewExportManager(a.config.DataStoreConfig.Schema, + a.ledgerBackend, queue, registry, + a.config.StellarCoreConfig.NetworkPassphrase, + a.config.CoreVersion); err != nil { + return err + } + a.uploader = NewUploader(a.dataStore, queue, registry) + + if a.config.AdminPort != 0 { + a.adminServer = newAdminServer(a.config.AdminPort, registry) + } + return nil +} + +func (a *App) applyResumability(ctx context.Context, resumableManager datastore.ResumableManager) error { + absentLedger, ok, err := resumableManager.FindStart(ctx, a.config.StartLedger, a.config.EndLedger) + if err != nil { + return err + } + if !ok { + return NewDataAlreadyExportedError(a.config.StartLedger, a.config.EndLedger) + } + + // TODO - evaluate a more robust validation of remote data for ledgers-per-file consistency + // this assumes ValidateAndSetLedgerRange() has conditioned the a.config.StartLedger to be at least > 1 + if absentLedger > 2 && absentLedger != a.config.DataStoreConfig.Schema.GetSequenceNumberStartBoundary(absentLedger) { + return NewInvalidDataStoreError(absentLedger, a.config.DataStoreConfig.Schema.LedgersPerFile) + } + logger.Infof("For export ledger range start=%d, end=%d, the remote storage has some of this data already, will resume at later start ledger of %d", a.config.StartLedger, a.config.EndLedger, absentLedger) + a.config.StartLedger = absentLedger + + return nil +} + +func (a *App) close() { + if err := a.dataStore.Close(); err != nil { + logger.WithError(err).Error("Error closing datastore") + } + if err := a.ledgerBackend.Close(); err != nil { + logger.WithError(err).Error("Error closing ledgerBackend") + } +} + +func newAdminServer(adminPort int, prometheusRegistry *prometheus.Registry) *http.Server { + mux := supporthttp.NewMux(logger) + mux.Handle("/metrics", promhttp.HandlerFor(prometheusRegistry, promhttp.HandlerOpts{})) + adminAddr := fmt.Sprintf(":%d", adminPort) + return &http.Server{ + Addr: adminAddr, + Handler: mux, + ReadTimeout: adminServerReadTimeout, + } +} + +func (a *App) Run(runtimeSettings RuntimeSettings) error { + ctx, cancel := context.WithCancel(runtimeSettings.Ctx) + defer cancel() + + if err := a.init(ctx, runtimeSettings); err != nil { + var dataAlreadyExported *DataAlreadyExportedError + if errors.As(err, &dataAlreadyExported) { + logger.Info(err.Error()) + logger.Info("Shutting down ledger-exporter") + return nil + } + logger.WithError(err).Error("Stopping ledger-exporter") + return err + } + defer a.close() + + var wg sync.WaitGroup + wg.Add(2) + + go func() { + defer wg.Done() + + err := a.uploader.Run(ctx, uploadShutdownTimeout) + if err != nil && !errors.Is(err, context.Canceled) { + logger.WithError(err).Error("Error executing Uploader") + cancel() + } + }() + + go func() { + defer wg.Done() + + err := a.exportManager.Run(ctx, a.config.StartLedger, a.config.EndLedger) + if err != nil && !errors.Is(err, context.Canceled) { + logger.WithError(err).Error("Error executing ExportManager") + cancel() + } + }() + + if a.adminServer != nil { + // no need to include this goroutine in the wait group + // because a.adminServer.Shutdown() is called below and + // that will block until a.adminServer has finished + // shutting down + go func() { + logger.Infof("Starting admin server on port %v", a.config.AdminPort) + if err := a.adminServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Warn(errors.Wrap(err, "error in internalServer.ListenAndServe()")) + } + }() + } + + // Handle OS signals to gracefully terminate the service + sigCh := make(chan os.Signal, 1) + defer close(sigCh) + signal.Notify(sigCh, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + go func() { + sig, ok := <-sigCh + if ok { + logger.Infof("Received termination signal: %v", sig) + cancel() + } + }() + + wg.Wait() + logger.Info("Shutting down ledger-exporter") + + if a.adminServer != nil { + serverShutdownCtx, serverShutdownCancel := context.WithTimeout(context.Background(), adminServerShutdownTimeout) + defer serverShutdownCancel() + + if err := a.adminServer.Shutdown(serverShutdownCtx); err != nil { + logger.WithError(err).Warn("error in internalServer.Shutdown") + } + } + return nil +} + +// newLedgerBackend Creates and initializes captive core ledger backend +// Currently, only supports captive-core as ledger backend +func newLedgerBackend(config *Config, prometheusRegistry *prometheus.Registry) (ledgerbackend.LedgerBackend, error) { + // best effort check on a core bin available from PATH to provide as default if + // no core bin is provided from config. + coreBinFromPath, _ := exec.LookPath("stellar-core") + captiveConfig, err := config.GenerateCaptiveCoreConfig(coreBinFromPath) + if err != nil { + return nil, err + } + + var backend ledgerbackend.LedgerBackend + // Create a new captive core backend + backend, err = ledgerbackend.NewCaptive(captiveConfig) + if err != nil { + return nil, errors.Wrap(err, "Failed to create captive-core instance") + } + backend = ledgerbackend.WithMetrics(backend, prometheusRegistry, "ledger_exporter") + + return backend, nil +} diff --git a/exp/services/ledgerexporter/internal/app_test.go b/exp/services/ledgerexporter/internal/app_test.go new file mode 100644 index 0000000000..bb715baa6f --- /dev/null +++ b/exp/services/ledgerexporter/internal/app_test.go @@ -0,0 +1,115 @@ +package ledgerexporter + +import ( + "context" + "testing" + + "github.com/pkg/errors" + "github.com/stellar/go/support/datastore" + "github.com/stretchr/testify/require" +) + +func TestApplyResumeHasStartError(t *testing.T) { + ctx := context.Background() + app := &App{} + app.config = &Config{StartLedger: 10, EndLedger: 19, Mode: Append} + mockResumableManager := &datastore.MockResumableManager{} + mockResumableManager.On("FindStart", ctx, uint32(10), uint32(19)).Return(uint32(0), false, errors.New("start error")).Once() + + err := app.applyResumability(ctx, mockResumableManager) + require.ErrorContains(t, err, "start error") + mockResumableManager.AssertExpectations(t) +} + +func TestApplyResumeDatastoreComplete(t *testing.T) { + ctx := context.Background() + app := &App{} + app.config = &Config{StartLedger: 10, EndLedger: 19, Mode: Append} + mockResumableManager := &datastore.MockResumableManager{} + mockResumableManager.On("FindStart", ctx, uint32(10), uint32(19)).Return(uint32(0), false, nil).Once() + + var alreadyExported *DataAlreadyExportedError + err := app.applyResumability(ctx, mockResumableManager) + require.ErrorAs(t, err, &alreadyExported) + mockResumableManager.AssertExpectations(t) +} + +func TestApplyResumeInvalidDataStoreLedgersPerFileBoundary(t *testing.T) { + ctx := context.Background() + app := &App{} + app.config = &Config{ + StartLedger: 3, + EndLedger: 9, + Mode: Append, + DataStoreConfig: datastore.DataStoreConfig{Schema: datastore.DataStoreSchema{LedgersPerFile: 10, FilesPerPartition: 50}}, + } + mockResumableManager := &datastore.MockResumableManager{} + // simulate the datastore has inconsistent data, + // with last ledger not aligned to starting boundary + mockResumableManager.On("FindStart", ctx, uint32(3), uint32(9)).Return(uint32(6), true, nil).Once() + + var invalidStore *InvalidDataStoreError + err := app.applyResumability(ctx, mockResumableManager) + require.ErrorAs(t, err, &invalidStore) + mockResumableManager.AssertExpectations(t) +} + +func TestApplyResumeWithPartialRemoteDataPresent(t *testing.T) { + ctx := context.Background() + app := &App{} + app.config = &Config{ + StartLedger: 10, + EndLedger: 99, + Mode: Append, + DataStoreConfig: datastore.DataStoreConfig{Schema: datastore.DataStoreSchema{LedgersPerFile: 10, FilesPerPartition: 50}}, + } + mockResumableManager := &datastore.MockResumableManager{} + // simulates a data store that had ledger files populated up to seq=49, so the first absent ledger would be 50 + mockResumableManager.On("FindStart", ctx, uint32(10), uint32(99)).Return(uint32(50), true, nil).Once() + + err := app.applyResumability(ctx, mockResumableManager) + require.NoError(t, err) + require.Equal(t, app.config.StartLedger, uint32(50)) + mockResumableManager.AssertExpectations(t) +} + +func TestApplyResumeWithNoRemoteDataPresent(t *testing.T) { + ctx := context.Background() + app := &App{} + app.config = &Config{ + StartLedger: 10, + EndLedger: 99, + Mode: Append, + DataStoreConfig: datastore.DataStoreConfig{Schema: datastore.DataStoreSchema{LedgersPerFile: 10, FilesPerPartition: 50}}, + } + mockResumableManager := &datastore.MockResumableManager{} + // simulates a data store that had no data in the requested range + mockResumableManager.On("FindStart", ctx, uint32(10), uint32(99)).Return(uint32(2), true, nil).Once() + + err := app.applyResumability(ctx, mockResumableManager) + require.NoError(t, err) + require.Equal(t, app.config.StartLedger, uint32(2)) + mockResumableManager.AssertExpectations(t) +} + +func TestApplyResumeWithNoRemoteDataAndRequestFromGenesis(t *testing.T) { + // app will coerce config.StartLedger values less than 2 to a min of 2 before applying resumability FindStart + // app will validate the response from FindStart to ensure datastore is ledgers-per-file aligned + // config.StartLedger=2 is a special genesis case that shouldn't trigger ledgers-per-file validation error + ctx := context.Background() + app := &App{} + app.config = &Config{ + StartLedger: 2, + EndLedger: 99, + Mode: Append, + DataStoreConfig: datastore.DataStoreConfig{Schema: datastore.DataStoreSchema{LedgersPerFile: 10, FilesPerPartition: 50}}, + } + mockResumableManager := &datastore.MockResumableManager{} + // simulates a data store that had no data in the requested range + mockResumableManager.On("FindStart", ctx, uint32(2), uint32(99)).Return(uint32(2), true, nil).Once() + + err := app.applyResumability(ctx, mockResumableManager) + require.NoError(t, err) + require.Equal(t, app.config.StartLedger, uint32(2)) + mockResumableManager.AssertExpectations(t) +} diff --git a/exp/services/ledgerexporter/internal/config.go b/exp/services/ledgerexporter/internal/config.go new file mode 100644 index 0000000000..196327e229 --- /dev/null +++ b/exp/services/ledgerexporter/internal/config.go @@ -0,0 +1,293 @@ +package ledgerexporter + +import ( + "context" + _ "embed" + "fmt" + "os" + + "github.com/stellar/go/historyarchive" + "github.com/stellar/go/ingest/ledgerbackend" + "github.com/stellar/go/network" + "github.com/stellar/go/support/log" + + "github.com/pelletier/go-toml" + + "github.com/stellar/go/support/datastore" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/support/ordered" + "github.com/stellar/go/support/storage" +) + +const ( + Pubnet = "pubnet" + Testnet = "testnet" + UserAgent = "ledgerexporter" +) + +type Mode int + +const ( + _ Mode = iota + ScanFill Mode = iota + Append +) + +func (mode Mode) Name() string { + switch mode { + case ScanFill: + return "Scan and Fill" + case Append: + return "Append" + } + return "none" +} + +type RuntimeSettings struct { + StartLedger uint32 + EndLedger uint32 + ConfigFilePath string + Mode Mode + Ctx context.Context +} + +type StellarCoreConfig struct { + Network string `toml:"network"` + NetworkPassphrase string `toml:"network_passphrase"` + HistoryArchiveUrls []string `toml:"history_archive_urls"` + StellarCoreBinaryPath string `toml:"stellar_core_binary_path"` + CaptiveCoreTomlPath string `toml:"captive_core_toml_path"` + CheckpointFrequency uint32 `toml:"checkpoint_frequency"` + StoragePath string `toml:"storage_path"` +} + +type Config struct { + AdminPort int `toml:"admin_port"` + + DataStoreConfig datastore.DataStoreConfig `toml:"datastore_config"` + StellarCoreConfig StellarCoreConfig `toml:"stellar_core_config"` + UserAgent string `toml:"user_agent"` + + StartLedger uint32 + EndLedger uint32 + Mode Mode + + CoreVersion string + SerializedCaptiveCoreToml []byte + CoreBuildVersionFn ledgerbackend.CoreBuildVersionFunc +} + +// This will generate the config based on settings +// +// settings - requested settings +// +// return - *Config or an error if any range validation failed. +func NewConfig(settings RuntimeSettings, getCoreVersionFn ledgerbackend.CoreBuildVersionFunc) (*Config, error) { + config := &Config{} + + config.StartLedger = uint32(settings.StartLedger) + config.EndLedger = uint32(settings.EndLedger) + config.Mode = settings.Mode + config.CoreBuildVersionFn = ledgerbackend.CoreBuildVersion + if getCoreVersionFn != nil { + config.CoreBuildVersionFn = getCoreVersionFn + } + + logger.Infof("Requested export mode of %v with start=%d, end=%d", settings.Mode.Name(), config.StartLedger, config.EndLedger) + + var err error + if err = config.processToml(settings.ConfigFilePath); err != nil { + return nil, err + } + logger.Infof("Network Config Archive URLs: %v", config.StellarCoreConfig.HistoryArchiveUrls) + logger.Infof("Network Config Archive Passphrase: %v", config.StellarCoreConfig.NetworkPassphrase) + logger.Infof("Network Config Stellar Core Binary Path: %v", config.StellarCoreConfig.StellarCoreBinaryPath) + logger.Infof("Network Config Stellar Core Toml Config: %v", string(config.SerializedCaptiveCoreToml)) + + return config, nil +} + +func (config *Config) Resumable() bool { + return config.Mode == Append +} + +// Validates requested ledger range, and will automatically adjust it +// to be ledgers-per-file boundary aligned +func (config *Config) ValidateAndSetLedgerRange(ctx context.Context, archive historyarchive.ArchiveInterface) error { + + if config.StartLedger < 2 { + return errors.New("invalid start value, must be greater than one.") + } + + if config.Mode == ScanFill && config.EndLedger == 0 { + return errors.New("invalid end value, unbounded mode not supported, end must be greater than start.") + } + + if config.EndLedger != 0 && config.EndLedger <= config.StartLedger { + return errors.New("invalid end value, must be greater than start") + } + + latestNetworkLedger, err := archive.GetLatestLedgerSequence() + latestNetworkLedger = latestNetworkLedger + (archive.GetCheckpointManager().GetCheckpointFrequency() * 2) + + if err != nil { + return errors.Wrap(err, "Failed to retrieve the latest ledger sequence from history archives.") + } + logger.Infof("Latest ledger sequence was detected as %d", latestNetworkLedger) + + if config.StartLedger > latestNetworkLedger { + return errors.Errorf("start %d exceeds latest network ledger %d", + config.StartLedger, latestNetworkLedger) + } + + if config.EndLedger > latestNetworkLedger { + return errors.Errorf("end %d exceeds latest network ledger %d", + config.EndLedger, latestNetworkLedger) + } + + config.adjustLedgerRange() + return nil +} + +func (config *Config) GenerateHistoryArchive(ctx context.Context, entry *log.Entry) (historyarchive.ArchiveInterface, error) { + return historyarchive.NewArchivePool(config.StellarCoreConfig.HistoryArchiveUrls, historyarchive.ArchiveOptions{ + ConnectOptions: storage.ConnectOptions{ + UserAgent: config.UserAgent, + Context: ctx, + }, + Logger: logger, + }) +} + +// coreBinDefaultPath - a default value to use for core binary path on system. +// +// this will be used if StellarCoreConfig.StellarCoreBinaryPath is not specified +func (config *Config) GenerateCaptiveCoreConfig(coreBinFromPath string) (ledgerbackend.CaptiveCoreConfig, error) { + var err error + + if config.StellarCoreConfig.StellarCoreBinaryPath == "" && coreBinFromPath == "" { + return ledgerbackend.CaptiveCoreConfig{}, errors.New("Invalid captive core config, no stellar-core binary path was provided.") + } + + if config.StellarCoreConfig.StellarCoreBinaryPath == "" { + config.StellarCoreConfig.StellarCoreBinaryPath = coreBinFromPath + } + + if err = config.setCoreVersionInfo(); err != nil { + return ledgerbackend.CaptiveCoreConfig{}, fmt.Errorf("failed to set stellar-core version info: %w", err) + } + + params := ledgerbackend.CaptiveCoreTomlParams{ + NetworkPassphrase: config.StellarCoreConfig.NetworkPassphrase, + HistoryArchiveURLs: config.StellarCoreConfig.HistoryArchiveUrls, + UseDB: true, + } + + captiveCoreToml, err := ledgerbackend.NewCaptiveCoreTomlFromData(config.SerializedCaptiveCoreToml, params) + if err != nil { + return ledgerbackend.CaptiveCoreConfig{}, errors.Wrap(err, "Failed to create captive-core toml") + } + + checkpointFrequency := historyarchive.DefaultCheckpointFrequency + if config.StellarCoreConfig.CheckpointFrequency > 0 { + checkpointFrequency = config.StellarCoreConfig.CheckpointFrequency + } + return ledgerbackend.CaptiveCoreConfig{ + BinaryPath: config.StellarCoreConfig.StellarCoreBinaryPath, + NetworkPassphrase: params.NetworkPassphrase, + HistoryArchiveURLs: params.HistoryArchiveURLs, + CheckpointFrequency: checkpointFrequency, + Log: logger.WithField("subservice", "stellar-core"), + Toml: captiveCoreToml, + UserAgent: "ledger-exporter", + UseDB: true, + StoragePath: config.StellarCoreConfig.StoragePath, + }, nil +} + +func (c *Config) setCoreVersionInfo() (err error) { + c.CoreVersion, err = c.CoreBuildVersionFn(c.StellarCoreConfig.StellarCoreBinaryPath) + if err != nil { + return fmt.Errorf("failed to set stellar-core version: %w", err) + } + logger.Infof("stellar-core version: %s", c.CoreVersion) + return nil +} + +func (config *Config) processToml(tomlPath string) error { + // Load config TOML file + cfg, err := toml.LoadFile(tomlPath) + if err != nil { + return errors.Wrapf(err, "config file %v was not found", tomlPath) + } + + // Unmarshal TOML data into the Config struct + if err = cfg.Unmarshal(config); err != nil { + return errors.Wrap(err, "Error unmarshalling TOML config.") + } + + if config.UserAgent == "" { + config.UserAgent = UserAgent + } + + if config.StellarCoreConfig.Network == "" && (len(config.StellarCoreConfig.HistoryArchiveUrls) == 0 || config.StellarCoreConfig.NetworkPassphrase == "" || config.StellarCoreConfig.CaptiveCoreTomlPath == "") { + return errors.New("Invalid captive core config, the 'network' parameter must be set to pubnet or testnet or " + + "'stellar_core_config.history_archive_urls' and 'stellar_core_config.network_passphrase' and 'stellar_core_config.captive_core_toml_path' must be set.") + } + + // network config values are an overlay, with network preconfigured values being first if network is present + // and then toml settings specific for passphrase, archiveurls, core toml file can override lastly. + var networkPassPhrase string + var networkArchiveUrls []string + switch config.StellarCoreConfig.Network { + case "": + + case Pubnet: + networkPassPhrase = network.PublicNetworkPassphrase + networkArchiveUrls = network.PublicNetworkhistoryArchiveURLs + config.SerializedCaptiveCoreToml = ledgerbackend.PubnetDefaultConfig + + case Testnet: + networkPassPhrase = network.TestNetworkPassphrase + networkArchiveUrls = network.TestNetworkhistoryArchiveURLs + config.SerializedCaptiveCoreToml = ledgerbackend.TestnetDefaultConfig + + default: + return errors.New("invalid captive core config, " + + "preconfigured_network must be set to 'pubnet' or 'testnet' or network_passphrase, history_archive_urls," + + " and captive_core_toml_path must be set") + } + + if config.StellarCoreConfig.NetworkPassphrase == "" { + config.StellarCoreConfig.NetworkPassphrase = networkPassPhrase + } + + if len(config.StellarCoreConfig.HistoryArchiveUrls) < 1 { + config.StellarCoreConfig.HistoryArchiveUrls = networkArchiveUrls + } + + if config.StellarCoreConfig.CaptiveCoreTomlPath != "" { + if config.SerializedCaptiveCoreToml, err = os.ReadFile(config.StellarCoreConfig.CaptiveCoreTomlPath); err != nil { + return errors.Wrap(err, "Failed to load captive-core-toml-path file") + } + } + + return nil +} + +func (config *Config) adjustLedgerRange() { + // Check if either the start or end ledger does not fall on the "LedgersPerFile" boundary + // and adjust the start and end ledger accordingly. + // Align the start ledger to the nearest "LedgersPerFile" boundary. + config.StartLedger = config.DataStoreConfig.Schema.GetSequenceNumberStartBoundary(config.StartLedger) + + // Ensure that the adjusted start ledger is at least 2. + config.StartLedger = ordered.Max(2, config.StartLedger) + + // Align the end ledger (for bounded cases) to the nearest "LedgersPerFile" boundary. + if config.EndLedger != 0 { + config.EndLedger = config.DataStoreConfig.Schema.GetSequenceNumberEndBoundary(config.EndLedger) + } + + logger.Infof("Computed effective export boundary ledger range: start=%d, end=%d", config.StartLedger, config.EndLedger) +} diff --git a/exp/services/ledgerexporter/internal/config_test.go b/exp/services/ledgerexporter/internal/config_test.go new file mode 100644 index 0000000000..d1c24cb198 --- /dev/null +++ b/exp/services/ledgerexporter/internal/config_test.go @@ -0,0 +1,448 @@ +package ledgerexporter + +import ( + "context" + "fmt" + "testing" + + "github.com/stellar/go/historyarchive" + "github.com/stellar/go/network" + + "github.com/stretchr/testify/require" +) + +func TestNewConfig(t *testing.T) { + ctx := context.Background() + + mockArchive := &historyarchive.MockArchive{} + mockArchive.On("GetLatestLedgerSequence").Return(uint32(5), nil).Once() + mockArchive.On("GetCheckpointManager"). + Return(historyarchive.NewCheckpointManager( + historyarchive.DefaultCheckpointFrequency)).Once() + + config, err := NewConfig( + RuntimeSettings{StartLedger: 2, EndLedger: 3, ConfigFilePath: "test/test.toml", Mode: Append}, nil) + + require.NoError(t, err) + err = config.ValidateAndSetLedgerRange(ctx, mockArchive) + require.NoError(t, err) + require.Equal(t, config.StellarCoreConfig.Network, "pubnet") + require.Equal(t, config.DataStoreConfig.Type, "ABC") + require.Equal(t, config.DataStoreConfig.Schema.FilesPerPartition, uint32(1)) + require.Equal(t, config.DataStoreConfig.Schema.LedgersPerFile, uint32(3)) + require.Equal(t, config.UserAgent, "ledgerexporter") + require.True(t, config.Resumable()) + url, ok := config.DataStoreConfig.Params["destination_bucket_path"] + require.True(t, ok) + require.Equal(t, url, "your-bucket-name/subpath/testnet") + mockArchive.AssertExpectations(t) +} + +func TestGenerateHistoryArchiveFromPreconfiguredNetwork(t *testing.T) { + ctx := context.Background() + config, err := NewConfig( + RuntimeSettings{StartLedger: 2, EndLedger: 3, ConfigFilePath: "test/valid_captive_core_preconfigured.toml", Mode: Append}, nil) + require.NoError(t, err) + + _, err = config.GenerateHistoryArchive(ctx, nil) + require.NoError(t, err) +} + +func TestGenerateHistoryArchiveFromManulConfiguredNetwork(t *testing.T) { + ctx := context.Background() + config, err := NewConfig( + RuntimeSettings{StartLedger: 2, EndLedger: 3, ConfigFilePath: "test/valid_captive_core_manual.toml", Mode: Append}, nil) + require.NoError(t, err) + + _, err = config.GenerateHistoryArchive(ctx, nil) + require.NoError(t, err) +} + +func TestNewConfigUserAgent(t *testing.T) { + config, err := NewConfig( + RuntimeSettings{StartLedger: 2, EndLedger: 3, ConfigFilePath: "test/useragent.toml"}, nil) + require.NoError(t, err) + require.Equal(t, config.UserAgent, "useragent_x") +} + +func TestResumeDisabled(t *testing.T) { + // resumable is only enabled when mode is Append + config, err := NewConfig( + RuntimeSettings{StartLedger: 2, EndLedger: 3, ConfigFilePath: "test/test.toml", Mode: ScanFill}, nil) + require.NoError(t, err) + require.False(t, config.Resumable()) +} + +func TestInvalidConfigFilePath(t *testing.T) { + _, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/notfound.toml"}, nil) + require.ErrorContains(t, err, "config file test/notfound.toml was not found") +} + +func TestNoCaptiveCoreBin(t *testing.T) { + cfg, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/no_core_bin.toml"}, nil) + require.NoError(t, err) + + _, err = cfg.GenerateCaptiveCoreConfig("") + require.ErrorContains(t, err, "Invalid captive core config, no stellar-core binary path was provided.") +} + +func TestDefaultCaptiveCoreBin(t *testing.T) { + cfg, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/no_core_bin.toml"}, + func(string) (string, error) { return "v20.2.0-2-g6e73c0a88", nil }) + require.NoError(t, err) + + ccConfig, err := cfg.GenerateCaptiveCoreConfig("/test/default/stellar-core") + require.NoError(t, err) + require.Equal(t, ccConfig.BinaryPath, "/test/default/stellar-core") +} + +func TestInvalidCaptiveCorePreconfiguredNetwork(t *testing.T) { + _, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/invalid_preconfigured_network.toml"}, nil) + + require.ErrorContains(t, err, "invalid captive core config") +} + +func TestValidCaptiveCorePreconfiguredNetwork(t *testing.T) { + cfg, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/valid_captive_core_preconfigured.toml"}, + func(string) (string, error) { return "v20.2.0-2-g6e73c0a88", nil }) + require.NoError(t, err) + + require.Equal(t, cfg.StellarCoreConfig.NetworkPassphrase, network.PublicNetworkPassphrase) + require.Equal(t, cfg.StellarCoreConfig.HistoryArchiveUrls, network.PublicNetworkhistoryArchiveURLs) + + ccConfig, err := cfg.GenerateCaptiveCoreConfig("") + require.NoError(t, err) + + // validates that ingest/ledgerbackend/configs/captive-core-pubnet.cfg was loaded + require.Equal(t, ccConfig.BinaryPath, "test/stellar-core") + require.Equal(t, ccConfig.NetworkPassphrase, network.PublicNetworkPassphrase) + require.Equal(t, ccConfig.HistoryArchiveURLs, network.PublicNetworkhistoryArchiveURLs) + require.Empty(t, ccConfig.Toml.HistoryEntries) + require.Len(t, ccConfig.Toml.Validators, 23) + require.Equal(t, ccConfig.Toml.Validators[0].Name, "Boötes") +} + +func TestValidCaptiveCoreManualNetwork(t *testing.T) { + cfg, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/valid_captive_core_manual.toml"}, + func(string) (string, error) { return "v20.2.0-2-g6e73c0a88", nil }) + require.NoError(t, err) + require.Equal(t, cfg.CoreVersion, "") + require.Equal(t, cfg.StellarCoreConfig.NetworkPassphrase, "test") + require.Equal(t, cfg.StellarCoreConfig.HistoryArchiveUrls, []string{"http://testarchive"}) + + ccConfig, err := cfg.GenerateCaptiveCoreConfig("") + require.NoError(t, err) + + require.Equal(t, ccConfig.BinaryPath, "test/stellar-core") + require.Equal(t, ccConfig.NetworkPassphrase, "test") + require.Equal(t, ccConfig.HistoryArchiveURLs, []string{"http://testarchive"}) + require.Empty(t, ccConfig.Toml.HistoryEntries) + require.Len(t, ccConfig.Toml.Validators, 1) + require.Equal(t, ccConfig.Toml.Validators[0].Name, "local_core") + require.Equal(t, cfg.CoreVersion, "v20.2.0-2-g6e73c0a88") +} + +func TestValidCaptiveCoreOverridenToml(t *testing.T) { + cfg, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/valid_captive_core_override.toml"}, + func(string) (string, error) { return "v20.2.0-2-g6e73c0a88", nil }) + require.NoError(t, err) + require.Equal(t, cfg.StellarCoreConfig.NetworkPassphrase, network.PublicNetworkPassphrase) + require.Equal(t, cfg.StellarCoreConfig.HistoryArchiveUrls, network.PublicNetworkhistoryArchiveURLs) + + ccConfig, err := cfg.GenerateCaptiveCoreConfig("") + require.NoError(t, err) + + // the external core cfg file should have applied over the preconf'd network config + require.Equal(t, ccConfig.BinaryPath, "test/stellar-core") + require.Equal(t, ccConfig.NetworkPassphrase, network.PublicNetworkPassphrase) + require.Equal(t, ccConfig.HistoryArchiveURLs, network.PublicNetworkhistoryArchiveURLs) + require.Empty(t, ccConfig.Toml.HistoryEntries) + require.Len(t, ccConfig.Toml.Validators, 1) + require.Equal(t, ccConfig.Toml.Validators[0].Name, "local_core") + require.Equal(t, cfg.CoreVersion, "v20.2.0-2-g6e73c0a88") +} + +func TestValidCaptiveCoreOverridenArchiveUrls(t *testing.T) { + cfg, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/valid_captive_core_override_archives.toml"}, + func(string) (string, error) { return "v20.2.0-2-g6e73c0a88\n", nil }) + require.NoError(t, err) + + require.Equal(t, cfg.StellarCoreConfig.NetworkPassphrase, network.PublicNetworkPassphrase) + require.Equal(t, cfg.StellarCoreConfig.HistoryArchiveUrls, []string{"http://testarchive"}) + + ccConfig, err := cfg.GenerateCaptiveCoreConfig("") + require.NoError(t, err) + + // validates that ingest/ledgerbackend/configs/captive-core-pubnet.cfg was loaded + require.Equal(t, ccConfig.BinaryPath, "test/stellar-core") + require.Equal(t, ccConfig.NetworkPassphrase, network.PublicNetworkPassphrase) + require.Equal(t, ccConfig.HistoryArchiveURLs, []string{"http://testarchive"}) + require.Empty(t, ccConfig.Toml.HistoryEntries) + require.Len(t, ccConfig.Toml.Validators, 23) + require.Equal(t, ccConfig.Toml.Validators[0].Name, "Boötes") +} + +func TestInvalidCaptiveCoreTomlPath(t *testing.T) { + _, err := NewConfig( + RuntimeSettings{ConfigFilePath: "test/invalid_captive_core_toml_path.toml"}, + nil) + require.ErrorContains(t, err, "Failed to load captive-core-toml-path file") +} + +func TestValidateStartAndEndLedger(t *testing.T) { + latestNetworkLedger := uint32(20000) + latestNetworkLedgerPadding := historyarchive.DefaultCheckpointFrequency * 2 + + tests := []struct { + name string + startLedger uint32 + endLedger uint32 + errMsg string + mode Mode + mockHas bool + }{ + { + name: "End ledger same as latest ledger", + startLedger: 512, + endLedger: 512, + mode: ScanFill, + errMsg: "invalid end value, must be greater than start", + mockHas: false, + }, + { + name: "End ledger greater than start ledger", + startLedger: 512, + endLedger: 600, + mode: ScanFill, + errMsg: "", + mockHas: true, + }, + { + name: "No end ledger provided, append mode, no error", + startLedger: 512, + endLedger: 0, + mode: Append, + errMsg: "", + mockHas: true, + }, + { + name: "No end ledger provided, scan-and-fill error", + startLedger: 512, + endLedger: 0, + mode: ScanFill, + errMsg: "invalid end value, unbounded mode not supported, end must be greater than start.", + }, + { + name: "End ledger before start ledger", + startLedger: 512, + endLedger: 2, + mode: ScanFill, + errMsg: "invalid end value, must be greater than start", + }, + { + name: "End ledger exceeds latest ledger", + startLedger: 512, + endLedger: latestNetworkLedger + latestNetworkLedgerPadding + 1, + mode: ScanFill, + mockHas: true, + errMsg: fmt.Sprintf("end %d exceeds latest network ledger %d", + latestNetworkLedger+latestNetworkLedgerPadding+1, latestNetworkLedger+latestNetworkLedgerPadding), + }, + { + name: "Start ledger 0", + startLedger: 0, + endLedger: 2, + mode: ScanFill, + errMsg: "invalid start value, must be greater than one.", + }, + { + name: "Start ledger 1", + startLedger: 1, + endLedger: 2, + mode: ScanFill, + errMsg: "invalid start value, must be greater than one.", + }, + { + name: "Start ledger exceeds latest ledger", + startLedger: latestNetworkLedger + latestNetworkLedgerPadding + 1, + endLedger: latestNetworkLedger + latestNetworkLedgerPadding + 2, + mode: ScanFill, + mockHas: true, + errMsg: fmt.Sprintf("start %d exceeds latest network ledger %d", + latestNetworkLedger+latestNetworkLedgerPadding+1, latestNetworkLedger+latestNetworkLedgerPadding), + }, + } + + ctx := context.Background() + mockArchive := &historyarchive.MockArchive{} + mockArchive.On("GetLatestLedgerSequence").Return(latestNetworkLedger, nil) + mockArchive.On("GetCheckpointManager"). + Return(historyarchive.NewCheckpointManager( + historyarchive.DefaultCheckpointFrequency)) + + mockedHasCtr := 0 + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.mockHas { + mockedHasCtr++ + } + config, err := NewConfig( + RuntimeSettings{StartLedger: tt.startLedger, EndLedger: tt.endLedger, ConfigFilePath: "test/validate_start_end.toml", Mode: tt.mode}, nil) + require.NoError(t, err) + err = config.ValidateAndSetLedgerRange(ctx, mockArchive) + if tt.errMsg != "" { + require.Error(t, err) + require.Equal(t, tt.errMsg, err.Error()) + } else { + require.NoError(t, err) + } + }) + } + mockArchive.AssertExpectations(t) +} + +func TestAdjustedLedgerRangeBoundedMode(t *testing.T) { + tests := []struct { + name string + configFile string + start uint32 + end uint32 + expectedStart uint32 + expectedEnd uint32 + }{ + { + name: "No change, 1 ledger per file", + configFile: "test/1perfile.toml", + start: 2, + end: 3, + expectedStart: 2, + expectedEnd: 3, + }, + { + name: "Min start ledger2, round up end ledger, 10 ledgers per file", + configFile: "test/10perfile.toml", + start: 2, + end: 3, + expectedStart: 2, + expectedEnd: 9, + }, + { + name: "Round down start ledger and round up end ledger, 15 ledgers per file ", + configFile: "test/15perfile.toml", + start: 4, + end: 10, + expectedStart: 2, + expectedEnd: 14, + }, + { + name: "Round down start ledger and round up end ledger, 64 ledgers per file ", + configFile: "test/64perfile.toml", + start: 400, + end: 500, + expectedStart: 384, + expectedEnd: 511, + }, + { + name: "No change, 64 ledger per file", + configFile: "test/64perfile.toml", + start: 64, + end: 128, + expectedStart: 64, + expectedEnd: 191, + }, + } + + ctx := context.Background() + mockArchive := &historyarchive.MockArchive{} + mockArchive.On("GetLatestLedgerSequence").Return(uint32(500), nil) + mockArchive.On("GetCheckpointManager"). + Return(historyarchive.NewCheckpointManager( + historyarchive.DefaultCheckpointFrequency)) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + config, err := NewConfig( + RuntimeSettings{StartLedger: tt.start, EndLedger: tt.end, ConfigFilePath: tt.configFile, Mode: ScanFill}, nil) + + require.NoError(t, err) + err = config.ValidateAndSetLedgerRange(ctx, mockArchive) + require.NoError(t, err) + require.EqualValues(t, tt.expectedStart, config.StartLedger) + require.EqualValues(t, tt.expectedEnd, config.EndLedger) + }) + } + mockArchive.AssertExpectations(t) +} + +func TestAdjustedLedgerRangeUnBoundedMode(t *testing.T) { + tests := []struct { + name string + configFile string + start uint32 + end uint32 + expectedStart uint32 + expectedEnd uint32 + }{ + { + name: "No change, 1 ledger per file", + configFile: "test/1perfile.toml", + start: 2, + end: 0, + expectedStart: 2, + expectedEnd: 0, + }, + { + name: "Round down start ledger, 15 ledgers per file ", + configFile: "test/15perfile.toml", + start: 4, + end: 0, + expectedStart: 2, + expectedEnd: 0, + }, + { + name: "Round down start ledger, 64 ledgers per file ", + configFile: "test/64perfile.toml", + start: 400, + end: 0, + expectedStart: 384, + expectedEnd: 0, + }, + { + name: "No change, 64 ledger per file", + configFile: "test/64perfile.toml", + start: 64, + end: 0, + expectedStart: 64, + expectedEnd: 0, + }, + } + + ctx := context.Background() + + mockArchive := &historyarchive.MockArchive{} + mockArchive.On("GetLatestLedgerSequence").Return(uint32(500), nil) + mockArchive.On("GetCheckpointManager"). + Return(historyarchive.NewCheckpointManager( + historyarchive.DefaultCheckpointFrequency)) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + config, err := NewConfig( + RuntimeSettings{StartLedger: tt.start, EndLedger: tt.end, ConfigFilePath: tt.configFile, Mode: Append}, nil) + require.NoError(t, err) + err = config.ValidateAndSetLedgerRange(ctx, mockArchive) + require.NoError(t, err) + require.EqualValues(t, tt.expectedStart, config.StartLedger) + require.EqualValues(t, tt.expectedEnd, config.EndLedger) + }) + } + mockArchive.AssertExpectations(t) +} diff --git a/exp/services/ledgerexporter/internal/exportmanager.go b/exp/services/ledgerexporter/internal/exportmanager.go new file mode 100644 index 0000000000..af2633d6be --- /dev/null +++ b/exp/services/ledgerexporter/internal/exportmanager.go @@ -0,0 +1,124 @@ +package ledgerexporter + +import ( + "context" + "strconv" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + + "github.com/stellar/go/ingest/ledgerbackend" + "github.com/stellar/go/support/datastore" + "github.com/stellar/go/xdr" +) + +type ExportManager struct { + dataStoreSchema datastore.DataStoreSchema + ledgerBackend ledgerbackend.LedgerBackend + currentMetaArchive *xdr.LedgerCloseMetaBatch + queue UploadQueue + latestLedgerMetric *prometheus.GaugeVec + networkPassPhrase string + coreVersion string +} + +// NewExportManager creates a new ExportManager with the provided configuration. +func NewExportManager(dataStoreSchema datastore.DataStoreSchema, + backend ledgerbackend.LedgerBackend, + queue UploadQueue, + prometheusRegistry *prometheus.Registry, + networkPassPhrase string, + coreVersion string) (*ExportManager, error) { + if dataStoreSchema.LedgersPerFile < 1 { + return nil, errors.Errorf("Invalid ledgers per file (%d): must be at least 1", dataStoreSchema.LedgersPerFile) + } + + latestLedgerMetric := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: "ledger_exporter", Subsystem: "export_manager", Name: "latest_ledger", + Help: "sequence number of the latest ledger consumed by the export manager", + }, []string{"start_ledger", "end_ledger"}) + prometheusRegistry.MustRegister(latestLedgerMetric) + + return &ExportManager{ + dataStoreSchema: dataStoreSchema, + ledgerBackend: backend, + queue: queue, + latestLedgerMetric: latestLedgerMetric, + networkPassPhrase: networkPassPhrase, + coreVersion: coreVersion, + }, nil +} + +// AddLedgerCloseMeta adds ledger metadata to the current export object +func (e *ExportManager) AddLedgerCloseMeta(ctx context.Context, ledgerCloseMeta xdr.LedgerCloseMeta) error { + ledgerSeq := ledgerCloseMeta.LedgerSequence() + + // Determine the object key for the given ledger sequence + objectKey := e.dataStoreSchema.GetObjectKeyFromSequenceNumber(ledgerSeq) + + if e.currentMetaArchive == nil { + endSeq := ledgerSeq + e.dataStoreSchema.LedgersPerFile - 1 + if ledgerSeq < e.dataStoreSchema.LedgersPerFile { + // Special case: Adjust the end ledger sequence for the first batch. + // Since the start ledger is 2 instead of 0, we want to ensure that the end ledger sequence + // does not exceed LedgersPerFile. + // For example, if LedgersPerFile is 64, the file name for the first batch should be 0-63, not 2-66. + endSeq = e.dataStoreSchema.LedgersPerFile - 1 + } + + // Create a new LedgerCloseMetaBatch + e.currentMetaArchive = &xdr.LedgerCloseMetaBatch{StartSequence: xdr.Uint32(ledgerSeq), EndSequence: xdr.Uint32(endSeq)} + } + + if err := e.currentMetaArchive.AddLedger(ledgerCloseMeta); err != nil { + return errors.Wrapf(err, "failed to add ledger %d", ledgerSeq) + } + + if ledgerSeq >= uint32(e.currentMetaArchive.EndSequence) { + ledgerMetaArchive, err := NewLedgerMetaArchiveFromXDR(e.networkPassPhrase, e.coreVersion, objectKey, *e.currentMetaArchive) + if err != nil { + return err + } + if err := e.queue.Enqueue(ctx, ledgerMetaArchive); err != nil { + return err + } + e.currentMetaArchive = nil + } + return nil +} + +// Run iterates over the specified range of ledgers, retrieves ledger data +// from the backend, and processes the corresponding ledger close metadata. +// The process continues until the ending ledger number is reached or a cancellation +// signal is received. +func (e *ExportManager) Run(ctx context.Context, startLedger, endLedger uint32) error { + defer e.queue.Close() + labels := prometheus.Labels{ + "start_ledger": strconv.FormatUint(uint64(startLedger), 10), + "end_ledger": strconv.FormatUint(uint64(endLedger), 10), + } + + var ledgerRange ledgerbackend.Range + if endLedger < 1 { + ledgerRange = ledgerbackend.UnboundedRange(startLedger) + } else { + ledgerRange = ledgerbackend.BoundedRange(startLedger, endLedger) + } + if err := e.ledgerBackend.PrepareRange(ctx, ledgerRange); err != nil { + return errors.Wrap(err, "Could not prepare captive core ledger backend") + } + + for nextLedger := startLedger; endLedger < 1 || nextLedger <= endLedger; nextLedger++ { + ledgerCloseMeta, err := e.ledgerBackend.GetLedger(ctx, nextLedger) + if err != nil { + return errors.Wrapf(err, "failed to retrieve ledger %d from the ledger backend", nextLedger) + } + e.latestLedgerMetric.With(labels).Set(float64(nextLedger)) + err = e.AddLedgerCloseMeta(ctx, ledgerCloseMeta) + if err != nil { + return errors.Wrapf(err, "failed to add ledgerCloseMeta for ledger %d", nextLedger) + } + } + logger.Infof("ExportManager successfully exported ledgers from %d to %d", startLedger, endLedger) + return nil +} diff --git a/exp/services/ledgerexporter/internal/exportmanager_test.go b/exp/services/ledgerexporter/internal/exportmanager_test.go new file mode 100644 index 0000000000..7845186c06 --- /dev/null +++ b/exp/services/ledgerexporter/internal/exportmanager_test.go @@ -0,0 +1,225 @@ +package ledgerexporter + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/stretchr/testify/suite" + + "github.com/stellar/go/ingest/ledgerbackend" + "github.com/stellar/go/support/collections/set" + "github.com/stellar/go/support/datastore" + "github.com/stellar/go/xdr" +) + +func createLedgerCloseMeta(ledgerSeq uint32) xdr.LedgerCloseMeta { + return xdr.LedgerCloseMeta{ + V: int32(0), + V0: &xdr.LedgerCloseMetaV0{ + LedgerHeader: xdr.LedgerHeaderHistoryEntry{ + Header: xdr.LedgerHeader{ + LedgerVersion: 21, + LedgerSeq: xdr.Uint32(ledgerSeq), + ScpValue: xdr.StellarValue{CloseTime: xdr.TimePoint(ledgerSeq * 100)}, + }, + }, + TxSet: xdr.TransactionSet{}, + TxProcessing: nil, + UpgradesProcessing: nil, + ScpInfo: nil, + }, + V1: nil, + } +} + +func TestExporterSuite(t *testing.T) { + suite.Run(t, new(ExportManagerSuite)) +} + +// ExportManagerSuite is a test suite for the ExportManager. +type ExportManagerSuite struct { + suite.Suite + ctx context.Context + mockBackend ledgerbackend.MockDatabaseBackend +} + +func (s *ExportManagerSuite) SetupTest() { + s.ctx = context.Background() + s.mockBackend = ledgerbackend.MockDatabaseBackend{} +} + +func (s *ExportManagerSuite) TearDownTest() { + s.mockBackend.AssertExpectations(s.T()) +} + +func (s *ExportManagerSuite) TestInvalidExportConfig() { + config := datastore.DataStoreSchema{LedgersPerFile: 0, FilesPerPartition: 10} + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + _, err := NewExportManager(config, &s.mockBackend, queue, registry, "passphrase", "coreversion") + s.Require().Error(err) +} + +func (s *ExportManagerSuite) TestRun() { + config := datastore.DataStoreSchema{LedgersPerFile: 64, FilesPerPartition: 10} + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + exporter, err := NewExportManager(config, &s.mockBackend, queue, registry, "passphrase", "coreversion") + s.Require().NoError(err) + + start := uint32(0) + end := uint32(255) + expectedKeys := set.NewSet[string](10) + s.mockBackend.On("PrepareRange", s.ctx, ledgerbackend.BoundedRange(start, end)).Return(nil) + for i := start; i <= end; i++ { + s.mockBackend.On("GetLedger", s.ctx, i). + Return(createLedgerCloseMeta(i), nil) + key := config.GetObjectKeyFromSequenceNumber(i) + expectedKeys.Add(key) + } + + actualKeys := set.NewSet[string](10) + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + for { + v, ok, dqErr := queue.Dequeue(s.ctx) + s.Assert().NoError(dqErr) + if !ok { + break + } + actualKeys.Add(v.ObjectKey) + } + }() + + err = exporter.Run(s.ctx, start, end) + s.Require().NoError(err) + + wg.Wait() + + s.Require().Equal(expectedKeys, actualKeys) + s.Require().Equal( + float64(255), + getMetricValue(exporter.latestLedgerMetric.With( + prometheus.Labels{ + "start_ledger": "0", + "end_ledger": "255", + }), + ).GetGauge().GetValue(), + ) +} + +func (s *ExportManagerSuite) TestRunContextCancel() { + config := datastore.DataStoreSchema{LedgersPerFile: 1, FilesPerPartition: 1} + + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + exporter, err := NewExportManager(config, &s.mockBackend, queue, registry, "passphrase", "coreversion") + s.Require().NoError(err) + ctx, cancel := context.WithCancel(context.Background()) + + s.mockBackend.On("PrepareRange", ctx, ledgerbackend.BoundedRange(0, 255)).Return(nil) + s.mockBackend.On("GetLedger", mock.Anything, mock.Anything). + Return(createLedgerCloseMeta(1), nil) + + go func() { + <-time.After(time.Second * 1) + cancel() + }() + + go func() { + for i := 0; i < 127; i++ { + _, ok, dqErr := queue.Dequeue(s.ctx) + s.Assert().NoError(dqErr) + s.Assert().True(ok) + } + }() + + err = exporter.Run(ctx, 0, 255) + s.Require().EqualError(err, "failed to add ledgerCloseMeta for ledger 128: context canceled") + +} + +func (s *ExportManagerSuite) TestRunWithCanceledContext() { + config := datastore.DataStoreSchema{LedgersPerFile: 1, FilesPerPartition: 10} + + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + exporter, err := NewExportManager(config, &s.mockBackend, queue, registry, "passphrase", "coreversion") + s.Require().NoError(err) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + s.mockBackend.On("PrepareRange", ctx, ledgerbackend.BoundedRange(1, 10)). + Return(context.Canceled).Run(func(args mock.Arguments) { + ctx := args.Get(0).(context.Context) + s.Require().ErrorIs(ctx.Err(), context.Canceled) + }) + err = exporter.Run(ctx, 1, 10) + s.Require().ErrorIs(err, context.Canceled) +} + +func (s *ExportManagerSuite) TestAddLedgerCloseMeta() { + config := datastore.DataStoreSchema{LedgersPerFile: 1, FilesPerPartition: 10} + + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + exporter, err := NewExportManager(config, &s.mockBackend, queue, registry, "passphrase", "coreversion") + s.Require().NoError(err) + + expectedKeys := set.NewSet[string](10) + actualKeys := set.NewSet[string](10) + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + for { + v, ok, err := queue.Dequeue(s.ctx) + s.Assert().NoError(err) + if !ok { + break + } + actualKeys.Add(v.ObjectKey) + } + }() + + start := uint32(0) + end := uint32(255) + for i := start; i <= end; i++ { + s.Require().NoError(exporter.AddLedgerCloseMeta(context.Background(), createLedgerCloseMeta(i))) + + key := config.GetObjectKeyFromSequenceNumber(i) + expectedKeys.Add(key) + } + + queue.Close() + wg.Wait() + s.Require().Equal(expectedKeys, actualKeys) +} + +func (s *ExportManagerSuite) TestAddLedgerCloseMetaContextCancel() { + config := datastore.DataStoreSchema{LedgersPerFile: 1, FilesPerPartition: 10} + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + exporter, err := NewExportManager(config, &s.mockBackend, queue, registry, "passphrase", "coreversion") + s.Require().NoError(err) + + ctx, cancel := context.WithCancel(context.Background()) + go func() { + <-time.After(time.Second * 1) + cancel() + }() + + require.NoError(s.T(), exporter.AddLedgerCloseMeta(ctx, createLedgerCloseMeta(1))) + err = exporter.AddLedgerCloseMeta(ctx, createLedgerCloseMeta(2)) + require.EqualError(s.T(), err, "context canceled") +} diff --git a/exp/services/ledgerexporter/internal/integration_test.go b/exp/services/ledgerexporter/internal/integration_test.go new file mode 100644 index 0000000000..ccc5463908 --- /dev/null +++ b/exp/services/ledgerexporter/internal/integration_test.go @@ -0,0 +1,354 @@ +package ledgerexporter + +import ( + "bytes" + "context" + "io" + "os" + "os/signal" + "path/filepath" + "testing" + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/image" + "github.com/docker/docker/client" + "github.com/docker/docker/pkg/stdcopy" + "github.com/docker/go-connections/nat" + "github.com/pkg/errors" + + "github.com/pelletier/go-toml" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + "github.com/fsouza/fake-gcs-server/fakestorage" + "github.com/stellar/go/historyarchive" + "github.com/stellar/go/support/datastore" + "github.com/stellar/go/support/storage" +) + +const ( + maxWaitForCoreStartup = (180 * time.Second) + coreStartupPingInterval = time.Second + // set the max ledger we want the standalone network to emit + // tests then refer to ledger sequences only up to this, therefore + // don't have to do complex waiting within test for a sequence to exist. + waitForCoreLedgerSequence = 16 + configTemplate = "test/integration_config_template.toml" +) + +func TestLedgerExporterTestSuite(t *testing.T) { + if os.Getenv("LEDGEREXPORTER_INTEGRATION_TESTS_ENABLED") != "true" { + t.Skip("skipping integration test: LEDGEREXPORTER_INTEGRATION_TESTS_ENABLED not true") + } + + ledgerExporterSuite := &LedgerExporterTestSuite{} + suite.Run(t, ledgerExporterSuite) +} + +type LedgerExporterTestSuite struct { + suite.Suite + tempConfigFile string + ctx context.Context + ctxStop context.CancelFunc + coreContainerID string + dockerCli *client.Client + gcsServer *fakestorage.Server + finishedSetup bool + config Config +} + +func (s *LedgerExporterTestSuite) TestScanAndFill() { + require := s.Require() + + rootCmd := defineCommands() + + rootCmd.SetArgs([]string{"scan-and-fill", "--start", "4", "--end", "5", "--config-file", s.tempConfigFile}) + var errWriter bytes.Buffer + var outWriter bytes.Buffer + rootCmd.SetErr(&errWriter) + rootCmd.SetOut(&outWriter) + err := rootCmd.ExecuteContext(s.ctx) + require.NoError(err) + + output := outWriter.String() + errOutput := errWriter.String() + s.T().Log(output) + s.T().Log(errOutput) + + datastore, err := datastore.NewDataStore(s.ctx, s.config.DataStoreConfig) + require.NoError(err) + + _, err = datastore.GetFile(s.ctx, "FFFFFFFF--0-9/FFFFFFFA--5.xdr.zstd") + require.NoError(err) +} + +func (s *LedgerExporterTestSuite) TestAppend() { + require := s.Require() + + // first populate ledgers 4-5 + rootCmd := defineCommands() + rootCmd.SetArgs([]string{"scan-and-fill", "--start", "6", "--end", "7", "--config-file", s.tempConfigFile}) + err := rootCmd.ExecuteContext(s.ctx) + require.NoError(err) + + // now run an append of overalapping range, it will resume past existing ledgers + rootCmd.SetArgs([]string{"append", "--start", "6", "--end", "9", "--config-file", s.tempConfigFile}) + var errWriter bytes.Buffer + var outWriter bytes.Buffer + rootCmd.SetErr(&errWriter) + rootCmd.SetOut(&outWriter) + err = rootCmd.ExecuteContext(s.ctx) + require.NoError(err) + + output := outWriter.String() + errOutput := errWriter.String() + s.T().Log(output) + s.T().Log(errOutput) + + datastore, err := datastore.NewDataStore(s.ctx, s.config.DataStoreConfig) + require.NoError(err) + + _, err = datastore.GetFile(s.ctx, "FFFFFFFF--0-9/FFFFFFF6--9.xdr.zstd") + require.NoError(err) +} + +func (s *LedgerExporterTestSuite) TestAppendUnbounded() { + require := s.Require() + + rootCmd := defineCommands() + rootCmd.SetArgs([]string{"append", "--start", "10", "--config-file", s.tempConfigFile}) + var errWriter bytes.Buffer + var outWriter bytes.Buffer + rootCmd.SetErr(&errWriter) + rootCmd.SetOut(&outWriter) + + appendCtx, cancel := context.WithCancel(s.ctx) + syn := make(chan struct{}) + defer func() { <-syn }() + defer cancel() + go func() { + defer close(syn) + require.NoError(rootCmd.ExecuteContext(appendCtx)) + output := outWriter.String() + errOutput := errWriter.String() + s.T().Log(output) + s.T().Log(errOutput) + }() + + datastore, err := datastore.NewDataStore(s.ctx, s.config.DataStoreConfig) + require.NoError(err) + + require.EventuallyWithT(func(c *assert.CollectT) { + // this checks every 50ms up to 180s total + assert := assert.New(c) + _, err = datastore.GetFile(s.ctx, "FFFFFFF5--10-19/FFFFFFF0--15.xdr.zstd") + assert.NoError(err) + }, 180*time.Second, 50*time.Millisecond, "append unbounded did not work") +} + +func (s *LedgerExporterTestSuite) SetupSuite() { + var err error + t := s.T() + + s.ctx, s.ctxStop = signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) + + defer func() { + if !s.finishedSetup { + s.TearDownSuite() + } + }() + testTempDir := t.TempDir() + + ledgerExporterConfigTemplate, err := toml.LoadFile(configTemplate) + if err != nil { + t.Fatalf("unable to load config template file %v, %v", configTemplate, err) + } + + // if LEDGEREXPORTER_INTEGRATION_TESTS_CAPTIVE_CORE_BIN not specified, + // ledgerexporter will attempt resolve core bin using 'stellar-core' from OS path + ledgerExporterConfigTemplate.Set("stellar_core_config.stellar_core_binary_path", + os.Getenv("LEDGEREXPORTER_INTEGRATION_TESTS_CAPTIVE_CORE_BIN")) + + ledgerExporterConfigTemplate.Set("stellar_core_config.storage_path", filepath.Join(testTempDir, "captive-core")) + + tomlBytes, err := toml.Marshal(ledgerExporterConfigTemplate) + if err != nil { + t.Fatalf("unable to parse config file toml %v, %v", configTemplate, err) + } + if err = toml.Unmarshal(tomlBytes, &s.config); err != nil { + t.Fatalf("unable to marshal config file toml into struct, %v", err) + } + + tempSeedDataPath := filepath.Join(testTempDir, "data") + if err = os.MkdirAll(filepath.Join(tempSeedDataPath, "integration-test"), 0777); err != nil { + t.Fatalf("unable to create seed data in temp path, %v", err) + } + + s.tempConfigFile = filepath.Join(testTempDir, "config.toml") + err = os.WriteFile(s.tempConfigFile, tomlBytes, 0777) + if err != nil { + t.Fatalf("unable to write temp config file %v, %v", s.tempConfigFile, err) + } + + testWriter := &testWriter{test: t} + opts := fakestorage.Options{ + Scheme: "http", + Host: "127.0.0.1", + Port: uint16(0), + Writer: testWriter, + Seed: tempSeedDataPath, + StorageRoot: filepath.Join(testTempDir, "bucket"), + PublicHost: "127.0.0.1", + } + + s.gcsServer, err = fakestorage.NewServerWithOptions(opts) + + if err != nil { + t.Fatalf("couldn't start the fake gcs http server %v", err) + } + + t.Logf("fake gcs server started at %v", s.gcsServer.URL()) + t.Setenv("STORAGE_EMULATOR_HOST", s.gcsServer.URL()) + + quickstartImage := os.Getenv("LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE") + if quickstartImage == "" { + quickstartImage = "stellar/quickstart:testing" + } + pullQuickStartImage := true + if os.Getenv("LEDGEREXPORTER_INTEGRATION_TESTS_QUICKSTART_IMAGE_PULL") == "false" { + pullQuickStartImage = false + } + + s.mustStartCore(t, quickstartImage, pullQuickStartImage) + s.mustWaitForCore(t, ledgerExporterConfigTemplate.GetArray("stellar_core_config.history_archive_urls").([]string), + ledgerExporterConfigTemplate.Get("stellar_core_config.network_passphrase").(string)) + s.finishedSetup = true +} + +func (s *LedgerExporterTestSuite) TearDownSuite() { + if s.coreContainerID != "" { + s.T().Logf("Stopping the quickstart container %v", s.coreContainerID) + containerLogs, err := s.dockerCli.ContainerLogs(s.ctx, s.coreContainerID, container.LogsOptions{ShowStdout: true, ShowStderr: true}) + + if err == nil { + var errWriter bytes.Buffer + var outWriter bytes.Buffer + stdcopy.StdCopy(&outWriter, &errWriter, containerLogs) + s.T().Log(outWriter.String()) + s.T().Log(errWriter.String()) + } + if err := s.dockerCli.ContainerStop(context.Background(), s.coreContainerID, container.StopOptions{}); err != nil { + s.T().Logf("unable to stop core container, %v, %v", s.coreContainerID, err) + } + } + if s.dockerCli != nil { + s.dockerCli.Close() + } + if s.gcsServer != nil { + s.gcsServer.Stop() + } + s.ctxStop() +} + +func (s *LedgerExporterTestSuite) mustStartCore(t *testing.T, quickstartImage string, pullImage bool) { + var err error + s.dockerCli, err = client.NewClientWithOpts(client.WithAPIVersionNegotiation()) + if err != nil { + t.Fatalf("could not create docker client, %v", err) + } + + if pullImage { + imgReader, imgErr := s.dockerCli.ImagePull(s.ctx, quickstartImage, image.PullOptions{}) + if imgErr != nil { + t.Fatalf("could not pull docker image, %v, %v", quickstartImage, imgErr) + } + // ImagePull is asynchronous. + // The reader needs to be read completely for the pull operation to complete. + _, err = io.Copy(io.Discard, imgReader) + if err != nil { + t.Fatalf("could not pull docker image, %v, %v", quickstartImage, err) + } + + err = imgReader.Close() + if err != nil { + t.Fatalf("could not download all of docker image bytes after pull, %v, %v", quickstartImage, err) + } + } + + resp, err := s.dockerCli.ContainerCreate(s.ctx, + &container.Config{ + Image: quickstartImage, + // only run tge core service(no horizon, rpc, etc) and don't spend any time upgrading + // the core with newer soroban limits + Cmd: []string{"--enable", "core,,", "--limits", "default", "--local"}, + ExposedPorts: nat.PortSet{ + nat.Port("1570/tcp"): {}, + nat.Port("11625/tcp"): {}, + }, + }, + + &container.HostConfig{ + PortBindings: nat.PortMap{ + nat.Port("1570/tcp"): {nat.PortBinding{HostIP: "127.0.0.1", HostPort: "1570"}}, + nat.Port("11625/tcp"): {nat.PortBinding{HostIP: "127.0.0.1", HostPort: "11625"}}, + }, + AutoRemove: true, + }, + nil, nil, "") + + if err != nil { + t.Fatalf("could not create quickstart docker container, %v, error %v", quickstartImage, err) + } + s.coreContainerID = resp.ID + + if err := s.dockerCli.ContainerStart(s.ctx, resp.ID, container.StartOptions{}); err != nil { + t.Fatalf("could not run quickstart docker container, %v, error %v", quickstartImage, err) + } + t.Logf("Started quickstart container %v", s.coreContainerID) +} + +func (s *LedgerExporterTestSuite) mustWaitForCore(t *testing.T, archiveUrls []string, passphrase string) { + t.Log("Waiting for core to be up...") + startTime := time.Now() + infoTime := startTime + archive, err := historyarchive.NewArchivePool(archiveUrls, historyarchive.ArchiveOptions{ + NetworkPassphrase: passphrase, + // due to ARTIFICIALLY_ACCELERATE_TIME_FOR_TESTING that is done by quickstart's local network + CheckpointFrequency: 8, + ConnectOptions: storage.ConnectOptions{ + Context: s.ctx, + }, + }) + if err != nil { + t.Fatalf("unable to create archive pool against core, %v", err) + } + for time.Since(startTime) < maxWaitForCoreStartup { + if durationSince := time.Since(infoTime); durationSince < coreStartupPingInterval { + time.Sleep(coreStartupPingInterval - durationSince) + } + infoTime = time.Now() + has, requestErr := archive.GetRootHAS() + if errors.Is(requestErr, context.Canceled) { + break + } + if requestErr != nil { + t.Logf("request to fetch checkpoint failed: %v", requestErr) + continue + } + latestCheckpoint := has.CurrentLedger + if latestCheckpoint >= waitForCoreLedgerSequence { + return + } + } + t.Fatalf("core did not progress ledgers within %v seconds", maxWaitForCoreStartup) +} + +type testWriter struct { + test *testing.T +} + +func (w *testWriter) Write(p []byte) (n int, err error) { + w.test.Log(string(p)) + return len(p), nil +} diff --git a/exp/services/ledgerexporter/internal/ledger_meta_archive.go b/exp/services/ledgerexporter/internal/ledger_meta_archive.go new file mode 100644 index 0000000000..f63a77f28b --- /dev/null +++ b/exp/services/ledgerexporter/internal/ledger_meta_archive.go @@ -0,0 +1,43 @@ +package ledgerexporter + +import ( + "github.com/stellar/go/support/compressxdr" + "github.com/stellar/go/support/datastore" + "github.com/stellar/go/xdr" +) + +// LedgerMetaArchive represents a file with metadata and binary data. +type LedgerMetaArchive struct { + ObjectKey string + Data xdr.LedgerCloseMetaBatch + metaData datastore.MetaData +} + +// NewLedgerMetaArchiveFromXDR creates a new LedgerMetaArchive instance. +func NewLedgerMetaArchiveFromXDR(networkPassPhrase string, coreVersion string, key string, data xdr.LedgerCloseMetaBatch) (*LedgerMetaArchive, error) { + startLedger, err := data.GetLedger(uint32(data.StartSequence)) + if err != nil { + return &LedgerMetaArchive{}, err + + } + endLedger, err := data.GetLedger(uint32(data.EndSequence)) + if err != nil { + return &LedgerMetaArchive{}, err + } + + return &LedgerMetaArchive{ + ObjectKey: key, + Data: data, + metaData: datastore.MetaData{ + StartLedger: startLedger.LedgerSequence(), + EndLedger: endLedger.LedgerSequence(), + StartLedgerCloseTime: startLedger.LedgerCloseTime(), + EndLedgerCloseTime: endLedger.LedgerCloseTime(), + NetworkPassPhrase: networkPassPhrase, + CompressionType: compressxdr.DefaultCompressor.Name(), + ProtocolVersion: endLedger.ProtocolVersion(), + CoreVersion: coreVersion, + Version: version, + }, + }, nil +} diff --git a/exp/services/ledgerexporter/internal/ledger_meta_archive_test.go b/exp/services/ledgerexporter/internal/ledger_meta_archive_test.go new file mode 100644 index 0000000000..152f2c6496 --- /dev/null +++ b/exp/services/ledgerexporter/internal/ledger_meta_archive_test.go @@ -0,0 +1,71 @@ +package ledgerexporter + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/stellar/go/support/datastore" + "github.com/stellar/go/xdr" +) + +func TestNewLedgerMetaArchiveFromXDR(t *testing.T) { + data := xdr.LedgerCloseMetaBatch{ + StartSequence: 1234, + EndSequence: 1234, + LedgerCloseMetas: []xdr.LedgerCloseMeta{ + createLedgerCloseMeta(1234), + }, + } + + archive, err := NewLedgerMetaArchiveFromXDR("testnet", "v1.2.3", "key", data) + + require.NoError(t, err) + require.NotNil(t, archive) + + // Check if the metadata fields are correctly populated + expectedMetaData := datastore.MetaData{ + StartLedger: 1234, + EndLedger: 1234, + StartLedgerCloseTime: 1234 * 100, + EndLedgerCloseTime: 1234 * 100, + NetworkPassPhrase: "testnet", + CompressionType: "zstd", + ProtocolVersion: 21, + CoreVersion: "v1.2.3", + Version: "develop", + } + + require.Equal(t, expectedMetaData, archive.metaData) + + data = xdr.LedgerCloseMetaBatch{ + StartSequence: 1234, + EndSequence: 1237, + LedgerCloseMetas: []xdr.LedgerCloseMeta{ + createLedgerCloseMeta(1234), + createLedgerCloseMeta(1235), + createLedgerCloseMeta(1236), + createLedgerCloseMeta(1237), + }, + } + + archive, err = NewLedgerMetaArchiveFromXDR("testnet", "v1.2.3", "key", data) + + require.NoError(t, err) + require.NotNil(t, archive) + + // Check if the metadata fields are correctly populated + expectedMetaData = datastore.MetaData{ + StartLedger: 1234, + EndLedger: 1237, + StartLedgerCloseTime: 1234 * 100, + EndLedgerCloseTime: 1237 * 100, + NetworkPassPhrase: "testnet", + CompressionType: "zstd", + ProtocolVersion: 21, + CoreVersion: "v1.2.3", + Version: "develop", + } + + require.Equal(t, expectedMetaData, archive.metaData) +} diff --git a/exp/services/ledgerexporter/internal/main.go b/exp/services/ledgerexporter/internal/main.go new file mode 100644 index 0000000000..f0ff076ae3 --- /dev/null +++ b/exp/services/ledgerexporter/internal/main.go @@ -0,0 +1,104 @@ +package ledgerexporter + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + "github.com/stellar/go/support/strutils" +) + +var ( + ledgerExporterCmdRunner = func(runtimeSettings RuntimeSettings) error { + app := NewApp() + return app.Run(runtimeSettings) + } +) + +func Execute() error { + rootCmd := defineCommands() + return rootCmd.Execute() +} + +func defineCommands() *cobra.Command { + var rootCmd = &cobra.Command{ + Use: "ledgerexporter", + Short: "Export Stellar network ledger data to a remote data store", + Long: "Converts ledger meta data from Stellar network into static data and exports it remote data storage.", + + RunE: func(cmd *cobra.Command, args []string) error { + return fmt.Errorf("please specify one of the availble sub-commands to initiate export") + }, + } + var scanAndFillCmd = &cobra.Command{ + Use: "scan-and-fill", + Short: "scans the entire bounded requested range between 'start' and 'end' flags and exports only the ledgers which are missing from the data lake.", + Long: "scans the entire bounded requested range between 'start' and 'end' flags and exports only the ledgers which are missing from the data lake.", + RunE: func(cmd *cobra.Command, args []string) error { + settings := bindCliParameters(cmd.PersistentFlags().Lookup("start"), + cmd.PersistentFlags().Lookup("end"), + cmd.PersistentFlags().Lookup("config-file"), + ) + settings.Mode = ScanFill + settings.Ctx = cmd.Context() + if settings.Ctx == nil { + settings.Ctx = context.Background() + } + return ledgerExporterCmdRunner(settings) + }, + } + var appendCmd = &cobra.Command{ + Use: "append", + Short: "export ledgers beginning with the first missing ledger after the specified 'start' ledger and resumes exporting from there", + Long: "export ledgers beginning with the first missing ledger after the specified 'start' ledger and resumes exporting from there", + RunE: func(cmd *cobra.Command, args []string) error { + settings := bindCliParameters(cmd.PersistentFlags().Lookup("start"), + cmd.PersistentFlags().Lookup("end"), + cmd.PersistentFlags().Lookup("config-file"), + ) + settings.Mode = Append + settings.Ctx = cmd.Context() + if settings.Ctx == nil { + settings.Ctx = context.Background() + } + return ledgerExporterCmdRunner(settings) + }, + } + + rootCmd.AddCommand(scanAndFillCmd) + rootCmd.AddCommand(appendCmd) + + scanAndFillCmd.PersistentFlags().Uint32P("start", "s", 0, "Starting ledger (inclusive), must be set to a value greater than 1") + scanAndFillCmd.PersistentFlags().Uint32P("end", "e", 0, "Ending ledger (inclusive), must be set to value greater than 'start' and less than the network's current ledger") + scanAndFillCmd.PersistentFlags().String("config-file", "config.toml", "Path to the TOML config file. Defaults to 'config.toml' on runtime working directory path.") + viper.BindPFlags(scanAndFillCmd.PersistentFlags()) + + appendCmd.PersistentFlags().Uint32P("start", "s", 0, "Starting ledger (inclusive), must be set to a value greater than 1") + appendCmd.PersistentFlags().Uint32P("end", "e", 0, "Ending ledger (inclusive), optional, setting to non-zero means bounded mode, "+ + "only export ledgers from 'start' up to 'end' value which must be greater than 'start' and less than the network's current ledger. "+ + "If 'end' is absent or '0' means unbounded mode, exporter will continue to run indefintely and export the latest closed ledgers from network as they are generated in real time.") + appendCmd.PersistentFlags().String("config-file", "config.toml", "Path to the TOML config file. Defaults to 'config.toml' on runtime working directory path.") + viper.BindPFlags(appendCmd.PersistentFlags()) + + return rootCmd +} + +func bindCliParameters(startFlag *pflag.Flag, endFlag *pflag.Flag, configFileFlag *pflag.Flag) RuntimeSettings { + settings := RuntimeSettings{} + + viper.BindPFlag(startFlag.Name, startFlag) + viper.BindEnv(startFlag.Name, strutils.KebabToConstantCase(startFlag.Name)) + settings.StartLedger = viper.GetUint32(startFlag.Name) + + viper.BindPFlag(endFlag.Name, endFlag) + viper.BindEnv(endFlag.Name, strutils.KebabToConstantCase(endFlag.Name)) + settings.EndLedger = viper.GetUint32(endFlag.Name) + + viper.BindPFlag(configFileFlag.Name, configFileFlag) + viper.BindEnv(configFileFlag.Name, strutils.KebabToConstantCase(configFileFlag.Name)) + settings.ConfigFilePath = viper.GetString(configFileFlag.Name) + + return settings +} diff --git a/exp/services/ledgerexporter/internal/main_test.go b/exp/services/ledgerexporter/internal/main_test.go new file mode 100644 index 0000000000..c9fe0f853d --- /dev/null +++ b/exp/services/ledgerexporter/internal/main_test.go @@ -0,0 +1,123 @@ +package ledgerexporter + +import ( + "bytes" + "context" + "io" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" +) + +func TestFlagsOutput(t *testing.T) { + var testResultSettings RuntimeSettings + appRunnerSuccess := func(runtimeSettings RuntimeSettings) error { + testResultSettings = runtimeSettings + return nil + } + + appRunnerError := func(runtimeSettings RuntimeSettings) error { + return errors.New("test error") + } + + ctx := context.Background() + + testCases := []struct { + name string + commandArgs []string + expectedErrOutput string + appRunner func(runtimeSettings RuntimeSettings) error + expectedSettings RuntimeSettings + }{ + { + name: "no sub-command", + commandArgs: []string{"--start", "4", "--end", "5", "--config-file", "myfile"}, + expectedErrOutput: "Error: ", + }, + { + name: "append sub-command with start and end present", + commandArgs: []string{"append", "--start", "4", "--end", "5", "--config-file", "myfile"}, + expectedErrOutput: "", + appRunner: appRunnerSuccess, + expectedSettings: RuntimeSettings{ + StartLedger: 4, + EndLedger: 5, + ConfigFilePath: "myfile", + Mode: Append, + Ctx: ctx, + }, + }, + { + name: "append sub-command with start and end absent", + commandArgs: []string{"append", "--config-file", "myfile"}, + expectedErrOutput: "", + appRunner: appRunnerSuccess, + expectedSettings: RuntimeSettings{ + StartLedger: 0, + EndLedger: 0, + ConfigFilePath: "myfile", + Mode: Append, + Ctx: ctx, + }, + }, + { + name: "append sub-command prints app error", + commandArgs: []string{"append", "--start", "4", "--end", "5", "--config-file", "myfile"}, + expectedErrOutput: "test error", + appRunner: appRunnerError, + }, + { + name: "scanfill sub-command with start and end present", + commandArgs: []string{"scan-and-fill", "--start", "4", "--end", "5", "--config-file", "myfile"}, + expectedErrOutput: "", + appRunner: appRunnerSuccess, + expectedSettings: RuntimeSettings{ + StartLedger: 4, + EndLedger: 5, + ConfigFilePath: "myfile", + Mode: ScanFill, + Ctx: ctx, + }, + }, + { + name: "scanfill sub-command with start and end absent", + commandArgs: []string{"scan-and-fill", "--config-file", "myfile"}, + expectedErrOutput: "", + appRunner: appRunnerSuccess, + expectedSettings: RuntimeSettings{ + StartLedger: 0, + EndLedger: 0, + ConfigFilePath: "myfile", + Mode: ScanFill, + Ctx: ctx, + }, + }, + { + name: "scanfill sub-command prints app error", + commandArgs: []string{"scan-and-fill", "--start", "4", "--end", "5", "--config-file", "myfile"}, + expectedErrOutput: "test error", + appRunner: appRunnerError, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + // mock the ledger exporter's cmd runner to be this test's mock routine instead of real app + ledgerExporterCmdRunner = testCase.appRunner + rootCmd := defineCommands() + rootCmd.SetArgs(testCase.commandArgs) + var errWriter io.Writer = &bytes.Buffer{} + var outWriter io.Writer = &bytes.Buffer{} + rootCmd.SetErr(errWriter) + rootCmd.SetOut(outWriter) + rootCmd.ExecuteContext(ctx) + + errOutput := errWriter.(*bytes.Buffer).String() + if testCase.expectedErrOutput != "" { + assert.Contains(t, errOutput, testCase.expectedErrOutput) + } else { + assert.Equal(t, testCase.expectedSettings, testResultSettings) + } + }) + } +} diff --git a/exp/services/ledgerexporter/internal/queue.go b/exp/services/ledgerexporter/internal/queue.go new file mode 100644 index 0000000000..372ccb0056 --- /dev/null +++ b/exp/services/ledgerexporter/internal/queue.go @@ -0,0 +1,58 @@ +package ledgerexporter + +import ( + "context" + + "github.com/prometheus/client_golang/prometheus" +) + +// UploadQueue is a queue of LedgerMetaArchive objects which are scheduled for upload +type UploadQueue struct { + metaArchiveCh chan *LedgerMetaArchive + queueLengthMetric prometheus.Gauge +} + +// NewUploadQueue constructs a new UploadQueue +func NewUploadQueue(size int, prometheusRegistry *prometheus.Registry) UploadQueue { + queueLengthMetric := prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "ledger_exporter", + Subsystem: "upload_queue", + Name: "length", + Help: "The number of objects queued for upload", + }) + prometheusRegistry.MustRegister(queueLengthMetric) + return UploadQueue{ + metaArchiveCh: make(chan *LedgerMetaArchive, size), + queueLengthMetric: queueLengthMetric, + } +} + +// Enqueue will add an upload task to the queue. Enqueue may block if the queue is full. +func (u UploadQueue) Enqueue(ctx context.Context, archive *LedgerMetaArchive) error { + u.queueLengthMetric.Inc() + select { + case u.metaArchiveCh <- archive: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} + +// Dequeue will pop a task off the queue. Dequeue may block if the queue is empty. +func (u UploadQueue) Dequeue(ctx context.Context) (*LedgerMetaArchive, bool, error) { + select { + case <-ctx.Done(): + return nil, false, ctx.Err() + + case metaObject, ok := <-u.metaArchiveCh: + if ok { + u.queueLengthMetric.Dec() + } + return metaObject, ok, nil + } +} + +// Close will close the queue. +func (u UploadQueue) Close() { + close(u.metaArchiveCh) +} diff --git a/exp/services/ledgerexporter/internal/queue_test.go b/exp/services/ledgerexporter/internal/queue_test.go new file mode 100644 index 0000000000..0676f3594f --- /dev/null +++ b/exp/services/ledgerexporter/internal/queue_test.go @@ -0,0 +1,63 @@ +package ledgerexporter + +import ( + "context" + "testing" + + "github.com/prometheus/client_golang/prometheus" + dto "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/require" +) + +func TestQueueContext(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + queue := NewUploadQueue(0, prometheus.NewRegistry()) + cancel() + + require.ErrorIs(t, queue.Enqueue(ctx, nil), context.Canceled) + _, _, err := queue.Dequeue(ctx) + require.ErrorIs(t, err, context.Canceled) +} + +func getMetricValue(metric prometheus.Metric) *dto.Metric { + value := &dto.Metric{} + err := metric.Write(value) + if err != nil { + panic(err) + } + return value +} + +func TestQueue(t *testing.T) { + queue := NewUploadQueue(3, prometheus.NewRegistry()) + + require.NoError(t, queue.Enqueue(context.Background(), NewLedgerMetaArchive("test", 1, 1))) + require.NoError(t, queue.Enqueue(context.Background(), NewLedgerMetaArchive("test", 2, 2))) + require.NoError(t, queue.Enqueue(context.Background(), NewLedgerMetaArchive("test", 3, 3))) + + require.Equal(t, float64(3), getMetricValue(queue.queueLengthMetric).GetGauge().GetValue()) + queue.Close() + + l, ok, err := queue.Dequeue(context.Background()) + require.NoError(t, err) + require.True(t, ok) + require.Equal(t, float64(2), getMetricValue(queue.queueLengthMetric).GetGauge().GetValue()) + require.Equal(t, uint32(1), uint32(l.Data.StartSequence)) + + l, ok, err = queue.Dequeue(context.Background()) + require.NoError(t, err) + require.True(t, ok) + require.Equal(t, float64(1), getMetricValue(queue.queueLengthMetric).GetGauge().GetValue()) + require.Equal(t, uint32(2), uint32(l.Data.StartSequence)) + + l, ok, err = queue.Dequeue(context.Background()) + require.NoError(t, err) + require.True(t, ok) + require.Equal(t, float64(0), getMetricValue(queue.queueLengthMetric).GetGauge().GetValue()) + require.Equal(t, uint32(3), uint32(l.Data.StartSequence)) + + l, ok, err = queue.Dequeue(context.Background()) + require.NoError(t, err) + require.False(t, ok) + require.Nil(t, l) +} diff --git a/exp/services/ledgerexporter/internal/test/10perfile.toml b/exp/services/ledgerexporter/internal/test/10perfile.toml new file mode 100644 index 0000000000..cae3d9f9ea --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/10perfile.toml @@ -0,0 +1,6 @@ +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "pubnet" + +[datastore_config.schema] +ledgers_per_file = 10 \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/15perfile.toml b/exp/services/ledgerexporter/internal/test/15perfile.toml new file mode 100644 index 0000000000..e3e4ee9d44 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/15perfile.toml @@ -0,0 +1,6 @@ +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "pubnet" + +[datastore_config.schema] +ledgers_per_file = 15 \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/1perfile.toml b/exp/services/ledgerexporter/internal/test/1perfile.toml new file mode 100644 index 0000000000..f8e88de478 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/1perfile.toml @@ -0,0 +1,6 @@ +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "pubnet" + +[datastore_config.schema] +ledgers_per_file = 1 \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/64perfile.toml b/exp/services/ledgerexporter/internal/test/64perfile.toml new file mode 100644 index 0000000000..769546afaf --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/64perfile.toml @@ -0,0 +1,6 @@ +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "pubnet" + +[datastore_config.schema] +ledgers_per_file = 64 \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/captive-core-test.cfg b/exp/services/ledgerexporter/internal/test/captive-core-test.cfg new file mode 100644 index 0000000000..dac9369464 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/captive-core-test.cfg @@ -0,0 +1,12 @@ +PEER_PORT=11725 + +UNSAFE_QUORUM=true +FAILURE_SAFETY=0 + +[[VALIDATORS]] +NAME="local_core" +HOME_DOMAIN="core.local" +PUBLIC_KEY="GD5KD2KEZJIGTC63IGW6UMUSMVUVG5IHG64HUTFWCHVZH2N2IBOQN7PS" +ADDRESS="localhost" +HISTORY="curl -sf https://localhost/{0} -o {1}" +QUALITY="MEDIUM" \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/integration_captive_core.cfg b/exp/services/ledgerexporter/internal/test/integration_captive_core.cfg new file mode 100644 index 0000000000..14e3772542 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/integration_captive_core.cfg @@ -0,0 +1,21 @@ +# this is based on quickstart --local network settings +ARTIFICIALLY_ACCELERATE_TIME_FOR_TESTING = true +DATABASE = "sqlite3://stellar.db" +DEPRECATED_SQL_LEDGER_STATE = false +ENABLE_SOROBAN_DIAGNOSTIC_EVENTS = true +FAILURE_SAFETY = 0 +HTTP_PORT = 0 +PUBLIC_HTTP_PORT = false +# avoid colliding with peer port from standalone core instance on same host +PEER_PORT = 15625 +LOG_FILE_PATH = "" +NETWORK_PASSPHRASE = "Standalone Network ; February 2017" +UNSAFE_QUORUM = true + +[[VALIDATORS]] + ADDRESS = "localhost:11625" + HISTORY = "curl -sf http://localhost:1570/{0} -o {1}" + HOME_DOMAIN = "core.local" + NAME = "local_core" + PUBLIC_KEY = "GCTI6HMWRH2QGMFKWVU5M5ZSOTKL7P7JAHZDMJJBKDHGWTEC4CJ7O3DU" + QUALITY = "MEDIUM" diff --git a/exp/services/ledgerexporter/internal/test/integration_config_template.toml b/exp/services/ledgerexporter/internal/test/integration_config_template.toml new file mode 100644 index 0000000000..410aa0f7e5 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/integration_config_template.toml @@ -0,0 +1,15 @@ +[datastore_config] +type = "GCS" + +[datastore_config.params] +destination_bucket_path = "integration-test/standalone" + +[datastore_config.schema] +ledgers_per_file = 1 +files_per_partition = 10 + +[stellar_core_config] +captive_core_toml_path = "test/integration_captive_core.cfg" +history_archive_urls = ["http://localhost:1570"] +network_passphrase = "Standalone Network ; February 2017" +checkpoint_frequency = 8 \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml b/exp/services/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml new file mode 100644 index 0000000000..580590b667 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml @@ -0,0 +1,5 @@ +[stellar_core_config] +captive_core_toml_path = "test/notfound.cfg" +stellar_core_binary_path = "test/stellar-core" +history_archive_urls = ["http://testarchive"] +network_passphrase = "test" diff --git a/exp/services/ledgerexporter/internal/test/invalid_empty.toml b/exp/services/ledgerexporter/internal/test/invalid_empty.toml new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/invalid_empty.toml @@ -0,0 +1 @@ + diff --git a/exp/services/ledgerexporter/internal/test/invalid_preconfigured_network.toml b/exp/services/ledgerexporter/internal/test/invalid_preconfigured_network.toml new file mode 100644 index 0000000000..8e09f05e55 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/invalid_preconfigured_network.toml @@ -0,0 +1,4 @@ +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "invalid" + diff --git a/exp/services/ledgerexporter/internal/test/no_core_bin.toml b/exp/services/ledgerexporter/internal/test/no_core_bin.toml new file mode 100644 index 0000000000..abbd1d9972 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/no_core_bin.toml @@ -0,0 +1,3 @@ +[stellar_core_config] +network = "testnet" + \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/test.toml b/exp/services/ledgerexporter/internal/test/test.toml new file mode 100644 index 0000000000..6a6804c70f --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/test.toml @@ -0,0 +1,13 @@ +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "pubnet" + +[datastore_config] +type = "ABC" + +[datastore_config.params] +destination_bucket_path = "your-bucket-name/subpath/testnet" + +[datastore_config.schema] +ledgers_per_file = 3 +files_per_partition = 1 \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/useragent.toml b/exp/services/ledgerexporter/internal/test/useragent.toml new file mode 100644 index 0000000000..209c04155b --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/useragent.toml @@ -0,0 +1,7 @@ +user_agent = "useragent_x" + +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "pubnet" + + diff --git a/exp/services/ledgerexporter/internal/test/valid_captive_core_manual.toml b/exp/services/ledgerexporter/internal/test/valid_captive_core_manual.toml new file mode 100644 index 0000000000..24a4304844 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/valid_captive_core_manual.toml @@ -0,0 +1,5 @@ +[stellar_core_config] +captive_core_toml_path = "test/captive-core-test.cfg" +stellar_core_binary_path = "test/stellar-core" +history_archive_urls = ["http://testarchive"] +network_passphrase = "test" \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/test/valid_captive_core_override.toml b/exp/services/ledgerexporter/internal/test/valid_captive_core_override.toml new file mode 100644 index 0000000000..312ccb29bb --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/valid_captive_core_override.toml @@ -0,0 +1,4 @@ +[stellar_core_config] +network="pubnet" +captive_core_toml_path = "test/captive-core-test.cfg" +stellar_core_binary_path = "test/stellar-core" diff --git a/exp/services/ledgerexporter/internal/test/valid_captive_core_override_archives.toml b/exp/services/ledgerexporter/internal/test/valid_captive_core_override_archives.toml new file mode 100644 index 0000000000..9aebc153c2 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/valid_captive_core_override_archives.toml @@ -0,0 +1,4 @@ +[stellar_core_config] +network="pubnet" +history_archive_urls = ["http://testarchive"] +stellar_core_binary_path = "test/stellar-core" diff --git a/exp/services/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml b/exp/services/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml new file mode 100644 index 0000000000..cb1c3c5c52 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml @@ -0,0 +1,4 @@ +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "pubnet" + diff --git a/exp/services/ledgerexporter/internal/test/validate_start_end.toml b/exp/services/ledgerexporter/internal/test/validate_start_end.toml new file mode 100644 index 0000000000..8cbd9f37a9 --- /dev/null +++ b/exp/services/ledgerexporter/internal/test/validate_start_end.toml @@ -0,0 +1,6 @@ +[datastore_config.schema] +ledgers_per_file = 1 + +[stellar_core_config] +stellar_core_binary_path = "test/stellar-core" +network = "pubnet" \ No newline at end of file diff --git a/exp/services/ledgerexporter/internal/uploader.go b/exp/services/ledgerexporter/internal/uploader.go new file mode 100644 index 0000000000..6d35d2920f --- /dev/null +++ b/exp/services/ledgerexporter/internal/uploader.go @@ -0,0 +1,167 @@ +package ledgerexporter + +import ( + "context" + "io" + "strconv" + "time" + + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + + "github.com/stellar/go/support/compressxdr" + "github.com/stellar/go/support/datastore" +) + +// Uploader is responsible for uploading data to a storage destination. +type Uploader struct { + dataStore datastore.DataStore + queue UploadQueue + uploadDurationMetric *prometheus.SummaryVec + objectSizeMetrics *prometheus.SummaryVec + latestLedgerMetric prometheus.Gauge +} + +// NewUploader constructs a new Uploader instance +func NewUploader( + destination datastore.DataStore, + queue UploadQueue, + prometheusRegistry *prometheus.Registry, +) Uploader { + uploadDurationMetric := prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: "ledger_exporter", Subsystem: "uploader", Name: "put_duration_seconds", + Help: "duration for uploading a ledger batch, sliding window = 10m", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }, + []string{"already_exists", "ledgers"}, + ) + objectSizeMetrics := prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Namespace: "ledger_exporter", Subsystem: "uploader", Name: "object_size_bytes", + Help: "size of a ledger batch in bytes, sliding window = 10m", + Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001}, + }, + []string{"ledgers", "already_exists", "compression"}, + ) + latestLedgerMetric := prometheus.NewGauge(prometheus.GaugeOpts{ + Namespace: "ledger_exporter", Subsystem: "uploader", Name: "latest_ledger", + Help: "sequence number of the latest ledger uploaded", + }) + prometheusRegistry.MustRegister(uploadDurationMetric, objectSizeMetrics, latestLedgerMetric) + return Uploader{ + dataStore: destination, + queue: queue, + uploadDurationMetric: uploadDurationMetric, + objectSizeMetrics: objectSizeMetrics, + latestLedgerMetric: latestLedgerMetric, + } +} + +type writerRecorder struct { + io.Writer + count *int64 +} + +func (r writerRecorder) Write(p []byte) (int, error) { + total, err := r.Writer.Write(p) + *r.count += int64(total) + return total, err +} + +type writerToRecorder struct { + io.WriterTo + totalCompressed int64 + totalUncompressed int64 +} + +func (r *writerToRecorder) WriteTo(w io.Writer) (int64, error) { + uncompressedCount, err := r.WriterTo.WriteTo(writerRecorder{ + Writer: w, + count: &r.totalCompressed, + }) + r.totalUncompressed += uncompressedCount + return uncompressedCount, err +} + +// Upload uploads the serialized binary data of ledger TxMeta to the specified destination. +func (u Uploader) Upload(ctx context.Context, metaArchive *LedgerMetaArchive) error { + logger.Infof("Uploading: %s", metaArchive.ObjectKey) + startTime := time.Now() + numLedgers := strconv.FormatUint(uint64(len(metaArchive.Data.LedgerCloseMetas)), 10) + + xdrEncoder := compressxdr.NewXDREncoder(compressxdr.DefaultCompressor, &metaArchive.Data) + + writerTo := &writerToRecorder{ + WriterTo: xdrEncoder, + } + ok, err := u.dataStore.PutFileIfNotExists(ctx, metaArchive.ObjectKey, writerTo, metaArchive.metaData.ToMap()) + if err != nil { + return errors.Wrapf(err, "error uploading %s", metaArchive.ObjectKey) + } + + logger.Infof("Uploaded %s successfully", metaArchive.ObjectKey) + alreadyExists := strconv.FormatBool(!ok) + + u.uploadDurationMetric.With(prometheus.Labels{ + "ledgers": numLedgers, + "already_exists": alreadyExists, + }).Observe(time.Since(startTime).Seconds()) + u.objectSizeMetrics.With(prometheus.Labels{ + "compression": "none", + "ledgers": numLedgers, + "already_exists": alreadyExists, + }).Observe(float64(writerTo.totalUncompressed)) + u.objectSizeMetrics.With(prometheus.Labels{ + "compression": xdrEncoder.Compressor.Name(), + "ledgers": numLedgers, + "already_exists": alreadyExists, + }).Observe(float64(writerTo.totalCompressed)) + u.latestLedgerMetric.Set(float64(metaArchive.Data.EndSequence)) + return nil +} + +// Run starts the uploader, continuously listening for LedgerMetaArchive objects to upload. +func (u Uploader) Run(ctx context.Context, shutdownDelayTime time.Duration) error { + uploadCtx, cancel := context.WithCancel(context.Background()) + defer cancel() + + go func() { + select { + case <-uploadCtx.Done(): + // if uploadCtx is cancelled that means we have exited Run() + // and therefore there are no remaining uploads + return + case <-ctx.Done(): + logger.Info("Received shutdown signal, waiting for remaining uploads to complete...") + } + + select { + case <-time.After(shutdownDelayTime): + // wait for some time to upload remaining objects from + // the upload queue + logger.Info("Timeout reached, canceling remaining uploads...") + cancel() + case <-uploadCtx.Done(): + // if uploadCtx is cancelled that means we have exited Run() + // and therefore there are no remaining uploads + return + } + }() + + for { + metaObject, ok, err := u.queue.Dequeue(uploadCtx) + if err != nil { + return err + } + if !ok { + logger.Info("Meta archive channel closed, stopping uploader") + return nil + } + + // Upload the received LedgerMetaArchive. + if err = u.Upload(uploadCtx, metaObject); err != nil { + return err + } + } +} diff --git a/exp/services/ledgerexporter/internal/uploader_test.go b/exp/services/ledgerexporter/internal/uploader_test.go new file mode 100644 index 0000000000..612c9e8740 --- /dev/null +++ b/exp/services/ledgerexporter/internal/uploader_test.go @@ -0,0 +1,326 @@ +package ledgerexporter + +import ( + "bytes" + "context" + "fmt" + "io" + "strconv" + "testing" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" + + "github.com/stellar/go/support/compressxdr" + "github.com/stellar/go/support/datastore" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +var testShutdownDelayTime = 300 * time.Millisecond + +func TestUploaderSuite(t *testing.T) { + suite.Run(t, new(UploaderSuite)) +} + +// UploaderSuite is a test suite for the Uploader. +type UploaderSuite struct { + suite.Suite + ctx context.Context + mockDataStore datastore.MockDataStore +} + +func (s *UploaderSuite) SetupTest() { + s.ctx = context.Background() + s.mockDataStore = datastore.MockDataStore{} +} + +func (s *UploaderSuite) TearDownTest() { + s.mockDataStore.AssertExpectations(s.T()) +} + +func (s *UploaderSuite) TestUpload() { + s.testUpload(false) + s.testUpload(true) +} + +func (s *UploaderSuite) TestUploadWithMetadata() { + key, start, end := "test-1-100", uint32(1), uint32(100) + archive := NewLedgerMetaArchive(key, start, end) + for i := start; i <= end; i++ { + _ = archive.Data.AddLedger(createLedgerCloseMeta(i)) + } + metadata := datastore.MetaData{ + StartLedger: start, + EndLedger: end, + StartLedgerCloseTime: 123456789, + EndLedgerCloseTime: 987654321, + ProtocolVersion: 3, + CoreVersion: "v1.2.3", + NetworkPassPhrase: "testnet", + CompressionType: "gzip", + Version: "1.0.0", + } + archive.metaData = metadata + var capturedBuf bytes.Buffer + s.mockDataStore.On("PutFileIfNotExists", mock.Anything, key, mock.Anything, metadata.ToMap()). + Run(func(args mock.Arguments) { + _ = args.Get(1).(string) + _, err := args.Get(2).(io.WriterTo).WriteTo(&capturedBuf) + s.Require().NoError(err) + }).Return(true, nil).Once() + + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + dataUploader := NewUploader(&s.mockDataStore, queue, registry) + s.Require().NoError(dataUploader.Upload(context.Background(), archive)) + +} + +func (s *UploaderSuite) testUpload(putOkReturnVal bool) { + key, start, end := "test-1-100", uint32(1), uint32(100) + archive := NewLedgerMetaArchive(key, start, end) + for i := start; i <= end; i++ { + _ = archive.Data.AddLedger(createLedgerCloseMeta(i)) + } + + var capturedBuf bytes.Buffer + var capturedKey string + s.mockDataStore.On("PutFileIfNotExists", mock.Anything, key, mock.Anything, datastore.MetaData{}.ToMap()). + Run(func(args mock.Arguments) { + capturedKey = args.Get(1).(string) + _, err := args.Get(2).(io.WriterTo).WriteTo(&capturedBuf) + s.Require().NoError(err) + }).Return(putOkReturnVal, nil).Once() + + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + dataUploader := NewUploader(&s.mockDataStore, queue, registry) + s.Require().NoError(dataUploader.Upload(context.Background(), archive)) + + expectedCompressedLength := capturedBuf.Len() + var decodedArchive LedgerMetaArchive + xdrDecoder := compressxdr.NewXDRDecoder(compressxdr.DefaultCompressor, &decodedArchive.Data) + + decoder := xdrDecoder + _, err := decoder.ReadFrom(&capturedBuf) + s.Require().NoError(err) + + // require that the decoded data matches the original test data + s.Require().Equal(key, capturedKey) + s.Require().Equal(archive.Data, decodedArchive.Data) + + alreadyExists := !putOkReturnVal + metric, err := dataUploader.uploadDurationMetric.MetricVec.GetMetricWith(prometheus.Labels{ + "ledgers": "100", + "already_exists": strconv.FormatBool(alreadyExists), + }) + s.Require().NoError(err) + s.Require().Equal( + uint64(1), + getMetricValue(metric).GetSummary().GetSampleCount(), + ) + s.Require().Positive(getMetricValue(metric).GetSummary().GetSampleSum()) + metric, err = dataUploader.uploadDurationMetric.MetricVec.GetMetricWith(prometheus.Labels{ + "ledgers": "100", + "already_exists": strconv.FormatBool(!alreadyExists), + }) + s.Require().NoError(err) + s.Require().Equal( + uint64(0), + getMetricValue(metric).GetSummary().GetSampleCount(), + ) + + metric, err = dataUploader.objectSizeMetrics.MetricVec.GetMetricWith(prometheus.Labels{ + "ledgers": "100", + "compression": decoder.Compressor.Name(), + "already_exists": strconv.FormatBool(alreadyExists), + }) + s.Require().NoError(err) + s.Require().Equal( + uint64(1), + getMetricValue(metric).GetSummary().GetSampleCount(), + ) + s.Require().Equal( + float64(expectedCompressedLength), + getMetricValue(metric).GetSummary().GetSampleSum(), + ) + metric, err = dataUploader.objectSizeMetrics.MetricVec.GetMetricWith(prometheus.Labels{ + "ledgers": "100", + "compression": decoder.Compressor.Name(), + "already_exists": strconv.FormatBool(!alreadyExists), + }) + s.Require().NoError(err) + s.Require().Equal( + uint64(0), + getMetricValue(metric).GetSummary().GetSampleCount(), + ) + + metric, err = dataUploader.objectSizeMetrics.MetricVec.GetMetricWith(prometheus.Labels{ + "ledgers": "100", + "compression": "none", + "already_exists": strconv.FormatBool(alreadyExists), + }) + s.Require().NoError(err) + s.Require().Equal( + uint64(1), + getMetricValue(metric).GetSummary().GetSampleCount(), + ) + uncompressedPayload, err := decodedArchive.Data.MarshalBinary() + s.Require().NoError(err) + s.Require().Equal( + float64(len(uncompressedPayload)), + getMetricValue(metric).GetSummary().GetSampleSum(), + ) + metric, err = dataUploader.objectSizeMetrics.MetricVec.GetMetricWith(prometheus.Labels{ + "ledgers": "100", + "compression": "none", + "already_exists": strconv.FormatBool(!alreadyExists), + }) + s.Require().NoError(err) + s.Require().Equal( + uint64(0), + getMetricValue(metric).GetSummary().GetSampleCount(), + ) + + s.Require().Equal( + float64(100), + getMetricValue(dataUploader.latestLedgerMetric).GetGauge().GetValue(), + ) +} + +func (s *UploaderSuite) TestUploadPutError() { + s.testUploadPutError(true) + s.testUploadPutError(false) +} + +func (s *UploaderSuite) testUploadPutError(putOkReturnVal bool) { + key, start, end := "test-1-100", uint32(1), uint32(100) + archive := NewLedgerMetaArchive(key, start, end) + + s.mockDataStore.On("PutFileIfNotExists", context.Background(), key, + mock.Anything, datastore.MetaData{}.ToMap()).Return(putOkReturnVal, errors.New("error in PutFileIfNotExists")).Once() + + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + dataUploader := NewUploader(&s.mockDataStore, queue, registry) + err := dataUploader.Upload(context.Background(), archive) + s.Require().Equal(fmt.Sprintf("error uploading %s: error in PutFileIfNotExists", key), err.Error()) + + for _, alreadyExists := range []string{"true", "false"} { + metric, err := dataUploader.uploadDurationMetric.MetricVec.GetMetricWith(prometheus.Labels{ + "ledgers": "100", + "already_exists": alreadyExists, + }) + s.Require().NoError(err) + s.Require().Equal( + uint64(0), + getMetricValue(metric).GetSummary().GetSampleCount(), + ) + + for _, compression := range []string{compressxdr.DefaultCompressor.Name(), "none"} { + metric, err = dataUploader.objectSizeMetrics.MetricVec.GetMetricWith(prometheus.Labels{ + "ledgers": "100", + "compression": compression, + "already_exists": alreadyExists, + }) + s.Require().NoError(err) + s.Require().Equal( + uint64(0), + getMetricValue(metric).GetSummary().GetSampleCount(), + ) + } + + s.Require().Equal( + float64(0), + getMetricValue(dataUploader.latestLedgerMetric).GetGauge().GetValue(), + ) + } +} + +func (s *UploaderSuite) TestRunUntilQueueClose() { + var prev *mock.Call + for i := 1; i <= 100; i++ { + key := fmt.Sprintf("test-%d", i) + cur := s.mockDataStore.On("PutFileIfNotExists", mock.Anything, + key, mock.Anything, mock.Anything).Return(true, nil).Once() + if prev != nil { + cur.NotBefore(prev) + } + prev = cur + } + + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + go func() { + for i := uint32(1); i <= uint32(100); i++ { + key := fmt.Sprintf("test-%d", i) + s.Require().NoError(queue.Enqueue(s.ctx, NewLedgerMetaArchive(key, i, i))) + } + queue.Close() + }() + + dataUploader := NewUploader(&s.mockDataStore, queue, registry) + s.Require().NoError(dataUploader.Run(context.Background(), testShutdownDelayTime)) + + s.Require().Equal( + float64(100), + getMetricValue(dataUploader.latestLedgerMetric).GetGauge().GetValue(), + ) +} + +func (s *UploaderSuite) TestRunContextCancel() { + ctx, cancel := context.WithCancel(context.Background()) + registry := prometheus.NewRegistry() + queue := NewUploadQueue(1, registry) + + first := s.mockDataStore.On("PutFileIfNotExists", mock.Anything, "test", mock.Anything, datastore.MetaData{}.ToMap()). + Return(true, nil).Once().Run(func(args mock.Arguments) { + cancel() + }) + s.mockDataStore.On("PutFileIfNotExists", mock.Anything, "test1", mock.Anything, datastore.MetaData{}.ToMap()). + Return(true, nil).Once().NotBefore(first).Run(func(args mock.Arguments) { + ctxArg := args.Get(0).(context.Context) + s.Require().NoError(ctxArg.Err()) + }) + + go func() { + s.Require().NoError(queue.Enqueue(s.ctx, NewLedgerMetaArchive("test", 1, 1))) + s.Require().NoError(queue.Enqueue(s.ctx, NewLedgerMetaArchive("test1", 2, 2))) + }() + + dataUploader := NewUploader(&s.mockDataStore, queue, registry) + s.Require().EqualError(dataUploader.Run(ctx, testShutdownDelayTime), "context canceled") + s.Require().Equal( + float64(2), + getMetricValue(dataUploader.latestLedgerMetric).GetGauge().GetValue(), + ) +} + +func (s *UploaderSuite) TestRunUploadError() { + registry := prometheus.NewRegistry() + queue := NewUploadQueue(2, registry) + + s.Require().NoError(queue.Enqueue(s.ctx, NewLedgerMetaArchive("test", 1, 1))) + s.Require().NoError(queue.Enqueue(s.ctx, NewLedgerMetaArchive("test1", 2, 2))) + + s.mockDataStore.On("PutFileIfNotExists", mock.Anything, "test", + mock.Anything, mock.Anything).Return(false, errors.New("Put error")).Once() + + dataUploader := NewUploader(&s.mockDataStore, queue, registry) + err := dataUploader.Run(context.Background(), testShutdownDelayTime) + s.Require().Equal("error uploading test: Put error", err.Error()) +} + +func NewLedgerMetaArchive(key string, startSeq uint32, endSeq uint32) *LedgerMetaArchive { + return &LedgerMetaArchive{ + ObjectKey: key, + Data: xdr.LedgerCloseMetaBatch{ + StartSequence: xdr.Uint32(startSeq), + EndSequence: xdr.Uint32(endSeq), + }, + metaData: datastore.MetaData{}, + } +} diff --git a/exp/services/ledgerexporter/main.go b/exp/services/ledgerexporter/main.go new file mode 100644 index 0000000000..6d38c69df9 --- /dev/null +++ b/exp/services/ledgerexporter/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "os" + + exporter "github.com/stellar/go/exp/services/ledgerexporter/internal" +) + +func main() { + err := exporter.Execute() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} From 9d07efbc0c758de100c19650e871e1ac93a32cc4 Mon Sep 17 00:00:00 2001 From: Urvi Date: Fri, 19 Jul 2024 10:05:37 -0700 Subject: [PATCH 2/4] Relocate --- Makefile | 2 +- services/ledgerexporter/CHANGELOG.md | 0 .../ledgerexporter/DEVELOPER_GUIDE.md | 0 {exp/services => services}/ledgerexporter/Makefile | 8 ++++---- {exp/services => services}/ledgerexporter/README.md | 0 .../ledgerexporter/architecture.png | Bin .../ledgerexporter/config.example.toml | 0 .../ledgerexporter/docker/Dockerfile | 2 +- .../ledgerexporter/docker/config.test.toml | 0 .../ledgerexporter/internal/app.go | 0 .../ledgerexporter/internal/app_test.go | 0 .../ledgerexporter/internal/config.go | 0 .../ledgerexporter/internal/config_test.go | 0 .../ledgerexporter/internal/exportmanager.go | 0 .../ledgerexporter/internal/exportmanager_test.go | 0 .../ledgerexporter/internal/integration_test.go | 0 .../ledgerexporter/internal/ledger_meta_archive.go | 0 .../internal/ledger_meta_archive_test.go | 0 .../ledgerexporter/internal/main.go | 0 .../ledgerexporter/internal/main_test.go | 0 .../ledgerexporter/internal/queue.go | 0 .../ledgerexporter/internal/queue_test.go | 0 .../ledgerexporter/internal/test/10perfile.toml | 0 .../ledgerexporter/internal/test/15perfile.toml | 0 .../ledgerexporter/internal/test/1perfile.toml | 0 .../ledgerexporter/internal/test/64perfile.toml | 0 .../internal/test/captive-core-test.cfg | 0 .../internal/test/integration_captive_core.cfg | 0 .../internal/test/integration_config_template.toml | 0 .../test/invalid_captive_core_toml_path.toml | 0 .../ledgerexporter/internal/test/invalid_empty.toml | 0 .../test/invalid_preconfigured_network.toml | 0 .../ledgerexporter/internal/test/no_core_bin.toml | 0 .../ledgerexporter/internal/test/test.toml | 0 .../ledgerexporter/internal/test/useragent.toml | 0 .../internal/test/valid_captive_core_manual.toml | 0 .../internal/test/valid_captive_core_override.toml | 0 .../test/valid_captive_core_override_archives.toml | 0 .../test/valid_captive_core_preconfigured.toml | 0 .../internal/test/validate_start_end.toml | 0 .../ledgerexporter/internal/uploader.go | 0 .../ledgerexporter/internal/uploader_test.go | 0 {exp/services => services}/ledgerexporter/main.go | 2 +- 43 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 services/ledgerexporter/CHANGELOG.md rename {exp/services => services}/ledgerexporter/DEVELOPER_GUIDE.md (100%) rename {exp/services => services}/ledgerexporter/Makefile (84%) rename {exp/services => services}/ledgerexporter/README.md (100%) rename {exp/services => services}/ledgerexporter/architecture.png (100%) rename {exp/services => services}/ledgerexporter/config.example.toml (100%) rename {exp/services => services}/ledgerexporter/docker/Dockerfile (93%) rename {exp/services => services}/ledgerexporter/docker/config.test.toml (100%) rename {exp/services => services}/ledgerexporter/internal/app.go (100%) rename {exp/services => services}/ledgerexporter/internal/app_test.go (100%) rename {exp/services => services}/ledgerexporter/internal/config.go (100%) rename {exp/services => services}/ledgerexporter/internal/config_test.go (100%) rename {exp/services => services}/ledgerexporter/internal/exportmanager.go (100%) rename {exp/services => services}/ledgerexporter/internal/exportmanager_test.go (100%) rename {exp/services => services}/ledgerexporter/internal/integration_test.go (100%) rename {exp/services => services}/ledgerexporter/internal/ledger_meta_archive.go (100%) rename {exp/services => services}/ledgerexporter/internal/ledger_meta_archive_test.go (100%) rename {exp/services => services}/ledgerexporter/internal/main.go (100%) rename {exp/services => services}/ledgerexporter/internal/main_test.go (100%) rename {exp/services => services}/ledgerexporter/internal/queue.go (100%) rename {exp/services => services}/ledgerexporter/internal/queue_test.go (100%) rename {exp/services => services}/ledgerexporter/internal/test/10perfile.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/15perfile.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/1perfile.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/64perfile.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/captive-core-test.cfg (100%) rename {exp/services => services}/ledgerexporter/internal/test/integration_captive_core.cfg (100%) rename {exp/services => services}/ledgerexporter/internal/test/integration_config_template.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/invalid_empty.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/invalid_preconfigured_network.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/no_core_bin.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/test.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/useragent.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/valid_captive_core_manual.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/valid_captive_core_override.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/valid_captive_core_override_archives.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml (100%) rename {exp/services => services}/ledgerexporter/internal/test/validate_start_end.toml (100%) rename {exp/services => services}/ledgerexporter/internal/uploader.go (100%) rename {exp/services => services}/ledgerexporter/internal/uploader_test.go (100%) rename {exp/services => services}/ledgerexporter/main.go (67%) diff --git a/Makefile b/Makefile index 69d46f68c3..63a9e94b6b 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ horizon: $(MAKE) -C services/horizon/ binary-build ledger-exporter: - $(MAKE) -C exp/services/ledgerexporter/ docker-build + $(MAKE) -C services/ledgerexporter/ docker-build webauth: $(MAKE) -C exp/services/webauth/ docker-build diff --git a/services/ledgerexporter/CHANGELOG.md b/services/ledgerexporter/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exp/services/ledgerexporter/DEVELOPER_GUIDE.md b/services/ledgerexporter/DEVELOPER_GUIDE.md similarity index 100% rename from exp/services/ledgerexporter/DEVELOPER_GUIDE.md rename to services/ledgerexporter/DEVELOPER_GUIDE.md diff --git a/exp/services/ledgerexporter/Makefile b/services/ledgerexporter/Makefile similarity index 84% rename from exp/services/ledgerexporter/Makefile rename to services/ledgerexporter/Makefile index 6561c4f24c..eeca66de27 100644 --- a/exp/services/ledgerexporter/Makefile +++ b/services/ledgerexporter/Makefile @@ -6,11 +6,11 @@ VERSION ?= $(shell git rev-parse --short HEAD) DOCKER_IMAGE := stellar/ledger-exporter docker-build: - cd ../../../ && \ + cd ../../ && \ $(SUDO) docker build --platform linux/amd64 --pull --label org.opencontainers.image.created="$(BUILD_DATE)" \ - --build-arg GOFLAGS="-ldflags=-X=github.com/stellar/go/exp/services/ledgerexporter/internal.version=$(VERSION)" \ + --build-arg GOFLAGS="-ldflags=-X=github.com/stellar/go/services/ledgerexporter/internal.version=$(VERSION)" \ $(if $(STELLAR_CORE_VERSION), --build-arg STELLAR_CORE_VERSION=$(STELLAR_CORE_VERSION)) \ - -f exp/services/ledgerexporter/docker/Dockerfile \ + -f services/ledgerexporter/docker/Dockerfile \ -t $(DOCKER_IMAGE):$(VERSION) \ -t $(DOCKER_IMAGE):latest . @@ -33,7 +33,7 @@ docker-test-fake-gcs: docker-clean # Run the ledger-exporter $(SUDO) docker run --platform linux/amd64 -t --network test-network\ - -v ${PWD}/exp/services/ledgerexporter/docker/config.test.toml:/config.toml \ + -v ${PWD}/services/ledgerexporter/docker/config.test.toml:/config.toml \ -e STORAGE_EMULATOR_HOST=http://fake-gcs-server:4443 \ $(DOCKER_IMAGE):$(VERSION) \ scan-and-fill --start 1000 --end 2000 diff --git a/exp/services/ledgerexporter/README.md b/services/ledgerexporter/README.md similarity index 100% rename from exp/services/ledgerexporter/README.md rename to services/ledgerexporter/README.md diff --git a/exp/services/ledgerexporter/architecture.png b/services/ledgerexporter/architecture.png similarity index 100% rename from exp/services/ledgerexporter/architecture.png rename to services/ledgerexporter/architecture.png diff --git a/exp/services/ledgerexporter/config.example.toml b/services/ledgerexporter/config.example.toml similarity index 100% rename from exp/services/ledgerexporter/config.example.toml rename to services/ledgerexporter/config.example.toml diff --git a/exp/services/ledgerexporter/docker/Dockerfile b/services/ledgerexporter/docker/Dockerfile similarity index 93% rename from exp/services/ledgerexporter/docker/Dockerfile rename to services/ledgerexporter/docker/Dockerfile index 7144800d87..fea21d86c5 100644 --- a/exp/services/ledgerexporter/docker/Dockerfile +++ b/services/ledgerexporter/docker/Dockerfile @@ -10,7 +10,7 @@ RUN go mod download COPY . ./ ARG GOFLAGS -RUN go install github.com/stellar/go/exp/services/ledgerexporter +RUN go install github.com/stellar/go/services/ledgerexporter FROM ubuntu:22.04 ARG STELLAR_CORE_VERSION diff --git a/exp/services/ledgerexporter/docker/config.test.toml b/services/ledgerexporter/docker/config.test.toml similarity index 100% rename from exp/services/ledgerexporter/docker/config.test.toml rename to services/ledgerexporter/docker/config.test.toml diff --git a/exp/services/ledgerexporter/internal/app.go b/services/ledgerexporter/internal/app.go similarity index 100% rename from exp/services/ledgerexporter/internal/app.go rename to services/ledgerexporter/internal/app.go diff --git a/exp/services/ledgerexporter/internal/app_test.go b/services/ledgerexporter/internal/app_test.go similarity index 100% rename from exp/services/ledgerexporter/internal/app_test.go rename to services/ledgerexporter/internal/app_test.go diff --git a/exp/services/ledgerexporter/internal/config.go b/services/ledgerexporter/internal/config.go similarity index 100% rename from exp/services/ledgerexporter/internal/config.go rename to services/ledgerexporter/internal/config.go diff --git a/exp/services/ledgerexporter/internal/config_test.go b/services/ledgerexporter/internal/config_test.go similarity index 100% rename from exp/services/ledgerexporter/internal/config_test.go rename to services/ledgerexporter/internal/config_test.go diff --git a/exp/services/ledgerexporter/internal/exportmanager.go b/services/ledgerexporter/internal/exportmanager.go similarity index 100% rename from exp/services/ledgerexporter/internal/exportmanager.go rename to services/ledgerexporter/internal/exportmanager.go diff --git a/exp/services/ledgerexporter/internal/exportmanager_test.go b/services/ledgerexporter/internal/exportmanager_test.go similarity index 100% rename from exp/services/ledgerexporter/internal/exportmanager_test.go rename to services/ledgerexporter/internal/exportmanager_test.go diff --git a/exp/services/ledgerexporter/internal/integration_test.go b/services/ledgerexporter/internal/integration_test.go similarity index 100% rename from exp/services/ledgerexporter/internal/integration_test.go rename to services/ledgerexporter/internal/integration_test.go diff --git a/exp/services/ledgerexporter/internal/ledger_meta_archive.go b/services/ledgerexporter/internal/ledger_meta_archive.go similarity index 100% rename from exp/services/ledgerexporter/internal/ledger_meta_archive.go rename to services/ledgerexporter/internal/ledger_meta_archive.go diff --git a/exp/services/ledgerexporter/internal/ledger_meta_archive_test.go b/services/ledgerexporter/internal/ledger_meta_archive_test.go similarity index 100% rename from exp/services/ledgerexporter/internal/ledger_meta_archive_test.go rename to services/ledgerexporter/internal/ledger_meta_archive_test.go diff --git a/exp/services/ledgerexporter/internal/main.go b/services/ledgerexporter/internal/main.go similarity index 100% rename from exp/services/ledgerexporter/internal/main.go rename to services/ledgerexporter/internal/main.go diff --git a/exp/services/ledgerexporter/internal/main_test.go b/services/ledgerexporter/internal/main_test.go similarity index 100% rename from exp/services/ledgerexporter/internal/main_test.go rename to services/ledgerexporter/internal/main_test.go diff --git a/exp/services/ledgerexporter/internal/queue.go b/services/ledgerexporter/internal/queue.go similarity index 100% rename from exp/services/ledgerexporter/internal/queue.go rename to services/ledgerexporter/internal/queue.go diff --git a/exp/services/ledgerexporter/internal/queue_test.go b/services/ledgerexporter/internal/queue_test.go similarity index 100% rename from exp/services/ledgerexporter/internal/queue_test.go rename to services/ledgerexporter/internal/queue_test.go diff --git a/exp/services/ledgerexporter/internal/test/10perfile.toml b/services/ledgerexporter/internal/test/10perfile.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/10perfile.toml rename to services/ledgerexporter/internal/test/10perfile.toml diff --git a/exp/services/ledgerexporter/internal/test/15perfile.toml b/services/ledgerexporter/internal/test/15perfile.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/15perfile.toml rename to services/ledgerexporter/internal/test/15perfile.toml diff --git a/exp/services/ledgerexporter/internal/test/1perfile.toml b/services/ledgerexporter/internal/test/1perfile.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/1perfile.toml rename to services/ledgerexporter/internal/test/1perfile.toml diff --git a/exp/services/ledgerexporter/internal/test/64perfile.toml b/services/ledgerexporter/internal/test/64perfile.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/64perfile.toml rename to services/ledgerexporter/internal/test/64perfile.toml diff --git a/exp/services/ledgerexporter/internal/test/captive-core-test.cfg b/services/ledgerexporter/internal/test/captive-core-test.cfg similarity index 100% rename from exp/services/ledgerexporter/internal/test/captive-core-test.cfg rename to services/ledgerexporter/internal/test/captive-core-test.cfg diff --git a/exp/services/ledgerexporter/internal/test/integration_captive_core.cfg b/services/ledgerexporter/internal/test/integration_captive_core.cfg similarity index 100% rename from exp/services/ledgerexporter/internal/test/integration_captive_core.cfg rename to services/ledgerexporter/internal/test/integration_captive_core.cfg diff --git a/exp/services/ledgerexporter/internal/test/integration_config_template.toml b/services/ledgerexporter/internal/test/integration_config_template.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/integration_config_template.toml rename to services/ledgerexporter/internal/test/integration_config_template.toml diff --git a/exp/services/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml b/services/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml rename to services/ledgerexporter/internal/test/invalid_captive_core_toml_path.toml diff --git a/exp/services/ledgerexporter/internal/test/invalid_empty.toml b/services/ledgerexporter/internal/test/invalid_empty.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/invalid_empty.toml rename to services/ledgerexporter/internal/test/invalid_empty.toml diff --git a/exp/services/ledgerexporter/internal/test/invalid_preconfigured_network.toml b/services/ledgerexporter/internal/test/invalid_preconfigured_network.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/invalid_preconfigured_network.toml rename to services/ledgerexporter/internal/test/invalid_preconfigured_network.toml diff --git a/exp/services/ledgerexporter/internal/test/no_core_bin.toml b/services/ledgerexporter/internal/test/no_core_bin.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/no_core_bin.toml rename to services/ledgerexporter/internal/test/no_core_bin.toml diff --git a/exp/services/ledgerexporter/internal/test/test.toml b/services/ledgerexporter/internal/test/test.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/test.toml rename to services/ledgerexporter/internal/test/test.toml diff --git a/exp/services/ledgerexporter/internal/test/useragent.toml b/services/ledgerexporter/internal/test/useragent.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/useragent.toml rename to services/ledgerexporter/internal/test/useragent.toml diff --git a/exp/services/ledgerexporter/internal/test/valid_captive_core_manual.toml b/services/ledgerexporter/internal/test/valid_captive_core_manual.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/valid_captive_core_manual.toml rename to services/ledgerexporter/internal/test/valid_captive_core_manual.toml diff --git a/exp/services/ledgerexporter/internal/test/valid_captive_core_override.toml b/services/ledgerexporter/internal/test/valid_captive_core_override.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/valid_captive_core_override.toml rename to services/ledgerexporter/internal/test/valid_captive_core_override.toml diff --git a/exp/services/ledgerexporter/internal/test/valid_captive_core_override_archives.toml b/services/ledgerexporter/internal/test/valid_captive_core_override_archives.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/valid_captive_core_override_archives.toml rename to services/ledgerexporter/internal/test/valid_captive_core_override_archives.toml diff --git a/exp/services/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml b/services/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml rename to services/ledgerexporter/internal/test/valid_captive_core_preconfigured.toml diff --git a/exp/services/ledgerexporter/internal/test/validate_start_end.toml b/services/ledgerexporter/internal/test/validate_start_end.toml similarity index 100% rename from exp/services/ledgerexporter/internal/test/validate_start_end.toml rename to services/ledgerexporter/internal/test/validate_start_end.toml diff --git a/exp/services/ledgerexporter/internal/uploader.go b/services/ledgerexporter/internal/uploader.go similarity index 100% rename from exp/services/ledgerexporter/internal/uploader.go rename to services/ledgerexporter/internal/uploader.go diff --git a/exp/services/ledgerexporter/internal/uploader_test.go b/services/ledgerexporter/internal/uploader_test.go similarity index 100% rename from exp/services/ledgerexporter/internal/uploader_test.go rename to services/ledgerexporter/internal/uploader_test.go diff --git a/exp/services/ledgerexporter/main.go b/services/ledgerexporter/main.go similarity index 67% rename from exp/services/ledgerexporter/main.go rename to services/ledgerexporter/main.go index 6d38c69df9..04cb23c637 100644 --- a/exp/services/ledgerexporter/main.go +++ b/services/ledgerexporter/main.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - exporter "github.com/stellar/go/exp/services/ledgerexporter/internal" + exporter "github.com/stellar/go/services/ledgerexporter/internal" ) func main() { From d7fa59587348823d3933956ebef5c78c8a9a1db3 Mon Sep 17 00:00:00 2001 From: Urvi Date: Fri, 19 Jul 2024 10:13:32 -0700 Subject: [PATCH 3/4] delete files --- .github/workflows/galexie-release.yml | 59 --------------------------- .github/workflows/galexie.yml | 45 -------------------- 2 files changed, 104 deletions(-) delete mode 100644 .github/workflows/galexie-release.yml delete mode 100644 .github/workflows/galexie.yml diff --git a/.github/workflows/galexie-release.yml b/.github/workflows/galexie-release.yml deleted file mode 100644 index 45e8152690..0000000000 --- a/.github/workflows/galexie-release.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Galexie Release - -on: - push: - tags: ['galexie-v*'] - -jobs: - - publish-docker: - name: Test and push docker image - runs-on: ubuntu-latest - env: - GALEXIE_INTEGRATION_TESTS_ENABLED: "true" - GALEXIE_INTEGRATION_TESTS_CAPTIVE_CORE_BIN: /usr/bin/stellar-core - # this pins to a version of quickstart:testing that has the same version as STELLAR_CORE_VERSION - # this is the multi-arch index sha, get it by 'docker buildx imagetools inspect stellar/quickstart:testing' - GALEXIE_INTEGRATION_TESTS_QUICKSTART_IMAGE: docker.io/stellar/quickstart:testing@sha256:03c6679f838a92b1eda4cd3a9e2bdee4c3586e278a138a0acf36a9bc99a0041f - GALEXIE_INTEGRATION_TESTS_QUICKSTART_IMAGE_PULL: "false" - STELLAR_CORE_VERSION: 21.1.0-1921.b3aeb14cc.focal - steps: - - name: Set VERSION - run: | - echo "VERSION=${GITHUB_REF_NAME#galexie-v}" >> $GITHUB_ENV - - - uses: actions/checkout@v3 - with: - ref: ${{ github.sha }} - - name: Pull Quickstart image - shell: bash - run: | - docker pull "$GALEXIE_INTEGRATION_TESTS_QUICKSTART_IMAGE" - - name: Install captive core - run: | - # Workaround for https://github.com/actions/virtual-environments/issues/5245, - # libc++1-8 won't be installed if another version is installed (but apt won't give you a helpul - # message about why the installation fails) - sudo apt list --installed | grep libc++ - sudo apt-get remove -y libc++1-* libc++abi1-* || true - - sudo wget -qO - https://apt.stellar.org/SDF.asc | APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=true sudo apt-key add - - sudo bash -c 'echo "deb https://apt.stellar.org focal unstable" > /etc/apt/sources.list.d/SDF-unstable.list' - sudo apt-get update && sudo apt-get install -y stellar-core="$STELLAR_CORE_VERSION" - echo "Using stellar core version $(stellar-core version)" - - - name: Run tests - run: go test -v -race -run TestGalexieTestSuite ./exp/services/galexie/... - - - name: Build docker - run: make -C exp/services/galexie docker-build - - # Push images - - name: Login to DockerHub - uses: docker/login-action@bb984efc561711aaa26e433c32c3521176eae55b - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Push to DockerHub - run: make -C exp/services/galexie docker-push diff --git a/.github/workflows/galexie.yml b/.github/workflows/galexie.yml deleted file mode 100644 index 458f23ca37..0000000000 --- a/.github/workflows/galexie.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Galexie - -on: - push: - branches: [master] - pull_request: - -jobs: - galexie: - name: Test - runs-on: ubuntu-latest - env: - CAPTIVE_CORE_DEBIAN_PKG_VERSION: 21.1.0-1921.b3aeb14cc.focal - GALEXIE_INTEGRATION_TESTS_ENABLED: "true" - GALEXIE_INTEGRATION_TESTS_CAPTIVE_CORE_BIN: /usr/bin/stellar-core - # this pins to a version of quickstart:testing that has the same version as GALEXIE_INTEGRATION_TESTS_CAPTIVE_CORE_BIN - # this is the multi-arch index sha, get it by 'docker buildx imagetools inspect stellar/quickstart:testing' - GALEXIE_INTEGRATION_TESTS_QUICKSTART_IMAGE: docker.io/stellar/quickstart:testing@sha256:5c8186f53cc98571749054dd782dce33b0aca2d1a622a7610362f7c15b79b1bf - GALEXIE_INTEGRATION_TESTS_QUICKSTART_IMAGE_PULL: "false" - steps: - - name: Install captive core - run: | - # Workaround for https://github.com/actions/virtual-environments/issues/5245, - # libc++1-8 won't be installed if another version is installed (but apt won't give you a helpul - # message about why the installation fails) - sudo apt list --installed | grep libc++ - sudo apt-get remove -y libc++1-* libc++abi1-* || true - - sudo wget -qO - https://apt.stellar.org/SDF.asc | APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=true sudo apt-key add - - sudo bash -c 'echo "deb https://apt.stellar.org focal unstable" > /etc/apt/sources.list.d/SDF-unstable.list' - sudo apt-get update && sudo apt-get install -y stellar-core="$CAPTIVE_CORE_DEBIAN_PKG_VERSION" - echo "Using stellar core version $(stellar-core version)" - - - name: Pull Quickstart image - shell: bash - run: | - docker pull "$GALEXIE_INTEGRATION_TESTS_QUICKSTART_IMAGE" - - - uses: actions/checkout@v3 - with: - # For pull requests, build and test the PR head not a merge of the PR with the destination. - ref: ${{ github.event.pull_request.head.sha || github.ref }} - - - name: Run test - run: go test -v -race -run TestGalexieTestSuite ./services/galexie/... From 758ef12a2d5658ab2c8141c390f057905aa94160 Mon Sep 17 00:00:00 2001 From: Urvi Date: Fri, 19 Jul 2024 10:21:49 -0700 Subject: [PATCH 4/4] Fix gh workflow --- .github/workflows/ledgerexporter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ledgerexporter.yml b/.github/workflows/ledgerexporter.yml index ac1e265582..ff970ae96e 100644 --- a/.github/workflows/ledgerexporter.yml +++ b/.github/workflows/ledgerexporter.yml @@ -43,4 +43,4 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.ref }} - name: Run Ledger Exporter test - run: go test -v -race -run TestLedgerExporterTestSuite ./exp/services/ledgerexporter/... + run: go test -v -race -run TestLedgerExporterTestSuite ./services/ledgerexporter/...