Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ require (
)

require (
github.com/aws/aws-sdk-go-v2 v1.36.5
github.com/aws/aws-sdk-go-v2/config v1.29.17
github.com/aws/aws-sdk-go-v2/credentials v1.17.70
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.83
github.com/aws/aws-sdk-go-v2/service/s3 v1.83.0
github.com/aws/smithy-go v1.22.4
github.com/cenkalti/backoff/v4 v4.3.0
github.com/creachadair/jrpc2 v1.2.0
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da
Expand All @@ -73,6 +79,19 @@ require (
cloud.google.com/go/longrunning v0.5.7 // indirect
cloud.google.com/go/pubsub v1.38.0 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/log v0.1.0 // indirect
Expand Down
38 changes: 38 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,44 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W
github.com/aws/aws-sdk-go v1.33.2/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.45.27 h1:b+zOTPkAG4i2RvqPdHxkJZafmhhVaVHBp4r41Tu4I6U=
github.com/aws/aws-sdk-go v1.45.27/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY=
github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=
github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=
github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.83 h1:08otkOELsIi0toRRGMytlJhOctcN8xfKfKFR2NXz3kE=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.83/go.mod h1:dGsGb2wI8JDWeMAhjVPP+z+dqvYjL6k6o+EujcRNk5c=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 h1:GMYy2EOWfzdP3wfVAGXBNKY5vK4K8vMET4sYOYltmqs=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36/go.mod h1:gDhdAV6wL3PmPqBhiPbnlS447GoWs8HTTOYef9/9Inw=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 h1:nAP2GYbfh8dd2zGZqFRSMlq+/F6cMPBUuCsGAMkN074=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4/go.mod h1:LT10DsiGjLWh4GbjInf9LQejkYEhBgBCjLG5+lvk4EE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U=
github.com/aws/aws-sdk-go-v2/service/s3 v1.83.0 h1:5Y75q0RPQoAbieyOuGLhjV9P3txvYgXv2lg0UwJOfmE=
github.com/aws/aws-sdk-go-v2/service/s3 v1.83.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=
github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
Expand Down
4 changes: 4 additions & 0 deletions services/galexie/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
All notable changes to this project will be documented in this
file. This project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

- Add implementation for S3 and S3-compatible data storage.

## [v1.0.0]

- 🎉 First release!
20 changes: 15 additions & 5 deletions services/galexie/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Galexie Developer Guide
Galexie is a tool to export Stellar network transaction data to cloud storage in a way that is easy to access.

Expand All @@ -15,7 +14,7 @@ The goal of Galexie is to build an easy-to-use tool to export Stellar network le
To achieve its goals, Galexie 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.
- The cloud storage plugin writes to the cloud storage. This supports multiple storage backends including Google Cloud Storage (GCS), Amazon S3, and S3-compatible storage services.


![Architecture](./architecture.png)
Expand All @@ -29,8 +28,19 @@ To achieve its goals, Galexie uses the following architecture, which consists of
- 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.
- Galexie 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.
Galexie implements a pluggable data storage architecture through the `DataStore` interface. This plugin is located in the [support](https://github.com/stellar/go/tree/master/support/datastore) package and supports multiple storage backends:

### 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 validation.

### Amazon S3 and S3-Compatible Storage
- The [S3 plugin](https://github.com/stellar/go/blob/master/support/datastore/s3_datastore.go) supports AWS S3 and S3-compatible storage services such as:
- Amazon S3
- Cloudflare R2
- MinIO
- DigitalOcean Spaces
- Any other S3-compatible object storage
- Features include conditional puts using `If-None-Match` headers, metadata storage, CRC32C checksum validation, and automatic retry mechanisms.

## Build and Run using Docker
The Dockerfile contains all the necessary dependencies (e.g., Stellar-core) required to run Galexie.
Expand Down Expand Up @@ -59,7 +69,7 @@ $ GALEXIE_INTEGRATION_TESTS_ENABLED=true go test -v -race -run TestGalexieTestSu
```

## 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:
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, 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
Expand Down
13 changes: 12 additions & 1 deletion services/galexie/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@ admin_port = 6061

# Datastore Configuration
[datastore_config]
# Specifies the type of datastore. Currently, only Google Cloud Storage (GCS) is supported.
# Specifies the type of datastore. Currently, Google Cloud Storage (GCS) and s3-compatible storage (S3) are supported.
type = "GCS"

[datastore_config.params]
# params required for GCS storage
# The Google Cloud Storage bucket path for storing data, with optional subpaths for organization.
destination_bucket_path = "your-bucket-name/<optional_subpath1>/<optional_subpath2>/"

# params required for S3-compatible storage
# Check https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#the-shared-credentials-file for more information on how to set up credentials.
# The S3 bucket path for storing data, with optional subpaths for organization.
#destination_bucket_path = "your-bucket-name/<optional_subpath1>/<optional_subpath2>/"
# The region where the S3 bucket is located.
#region = "us-west-1" # Example region, change as needed.
# The endpoint URL for the S3-compatible storage. If you are using Amazon S3, you can leave this commented out.
# The below example is for Cloudflare R2, but you can replace it with your S3-compatible storage endpoint.
#endpoint_url = "https://00000000000000000000000000000000.cloudflarestorage.com"

[datastore_config.schema]
# Configuration for data organization
ledgers_per_file = 1 # Number of ledgers stored in each file.
Expand Down
9 changes: 4 additions & 5 deletions support/datastore/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@ type DataStore interface {
func NewDataStore(ctx context.Context, datastoreConfig DataStoreConfig) (DataStore, error) {
switch datastoreConfig.Type {
case "GCS":
destinationBucketPath, ok := datastoreConfig.Params["destination_bucket_path"]
if !ok {
return nil, errors.Errorf("Invalid GCS config, no destination_bucket_path")
}
return NewGCSDataStore(ctx, destinationBucketPath, datastoreConfig.Schema)
return NewGCSDataStore(ctx, datastoreConfig)
case "S3":
return NewS3DataStore(ctx, datastoreConfig)

default:
return nil, errors.Errorf("Invalid datastore type %v, not supported", datastoreConfig.Type)
}
Expand Down
9 changes: 7 additions & 2 deletions support/datastore/gcs_datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,18 @@ type GCSDataStore struct {
schema DataStoreSchema
}

func NewGCSDataStore(ctx context.Context, bucketPath string, schema DataStoreSchema) (DataStore, error) {
func NewGCSDataStore(ctx context.Context, dataStoreConfig DataStoreConfig) (DataStore, error) {
destinationBucketPath, ok := dataStoreConfig.Params["destination_bucket_path"]
if !ok {
return nil, errors.New("invalid GCS config, no destination_bucket_path")
}

client, err := storage.NewClient(ctx)
if err != nil {
return nil, err
}

return FromGCSClient(ctx, client, bucketPath, schema)
return FromGCSClient(ctx, client, destinationBucketPath, dataStoreConfig.Schema)
}

func FromGCSClient(ctx context.Context, client *storage.Client, bucketPath string, schema DataStoreSchema) (DataStore, error) {
Expand Down
8 changes: 0 additions & 8 deletions support/datastore/gcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,3 @@ func TestGCSGetFileValidatesCRC32C(t *testing.T) {
_, err = io.Copy(&buf, reader)
require.EqualError(t, err, "storage: bad CRC on read: got 985946173, want 2601510353")
}

func requireReaderContentEquals(t *testing.T, reader io.ReadCloser, expected []byte) {
var buf bytes.Buffer
_, err := io.Copy(&buf, reader)
require.NoError(t, err)
require.NoError(t, reader.Close())
require.Equal(t, expected, buf.Bytes())
}
18 changes: 18 additions & 0 deletions support/datastore/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package datastore

import (
"bytes"
"io"
"testing"

"github.com/stretchr/testify/require"

Check failure on line 8 in support/datastore/helpers_test.go

View workflow job for this annotation

GitHub Actions / golangci

import 'github.com/stretchr/testify/require' is not allowed from list 'Main' (depguard)
)

// requireReaderContentEquals is a helper function to assert reader content.
func requireReaderContentEquals(t *testing.T, reader io.ReadCloser, expected []byte) {
var buf bytes.Buffer
_, err := io.Copy(&buf, reader)
require.NoError(t, err)
require.NoError(t, reader.Close())
require.Equal(t, expected, buf.Bytes())
}
Loading
Loading