Skip to content

Commit

Permalink
Merge pull request #252 from ava-labs/redis-support
Browse files Browse the repository at this point in the history
Redis support
  • Loading branch information
cam-schultz authored Apr 3, 2024
2 parents c18e494 + 41a637a commit b437c73
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 3 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ The relayer binary accepts a path to a JSON configuration file as the sole argum

### Configuration

The relayer is configured via a JSON file, the path to which is passed in via the `--config-file` command line argument. The following configuration options are available:
The relayer is configured via a JSON file, the path to which is passed in via the `--config-file` command line argument. Top level configuration options are also able to be set via environment variable. To get the environment variable corresponding to a key, upper case the key and change the delimiter from "-" to "_". For example, `LOG_LEVEL` sets the `"log-level"` JSON key. The following configuration options are available:

`"log-level": "verbo" | "debug" | "info" | "warn" | "error" | "fatal" | "panic"`

Expand Down Expand Up @@ -133,6 +133,10 @@ The relayer is configured via a JSON file, the path to which is passed in via th

- The path to the directory in which the relayer will store its state. Defaults to `./awm-relayer-storage`.

`"redis-url": string`

- The URL of the Redis server to use to manage state. This URL should specify the user, password, host, port, DB index, and protocol version. For example, `"redis://user:password@localhost:6379/0?protocol=3"`. Overrides `storage-location` if provided.

`"process-missed-blocks": boolean`

- Whether or not to process missed blocks after restarting. Defaults to `true`. If set to false, the relayer will start processing blocks from the chain head.
Expand Down
2 changes: 2 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ type Config struct {
PChainAPIURL string `mapstructure:"p-chain-api-url" json:"p-chain-api-url"`
InfoAPIURL string `mapstructure:"info-api-url" json:"info-api-url"`
StorageLocation string `mapstructure:"storage-location" json:"storage-location"`
RedisURL string `mapstructure:"redis-url" json:"redis-url"`
APIPort uint16 `mapstructure:"api-port" json:"api-port"`
MetricsPort uint16 `mapstructure:"metrics-port" json:"metrics-port"`

Expand Down Expand Up @@ -174,6 +175,7 @@ func BuildConfig(v *viper.Viper) (Config, bool, error) {
cfg.PChainAPIURL = v.GetString(PChainAPIURLKey)
cfg.InfoAPIURL = v.GetString(InfoAPIURLKey)
cfg.StorageLocation = v.GetString(StorageLocationKey)
cfg.RedisURL = v.GetString(RedisURLKey)
cfg.ProcessMissedBlocks = v.GetBool(ProcessMissedBlocksKey)
cfg.APIPort = v.GetUint16(APIPortKey)
cfg.MetricsPort = v.GetUint16(MetricsPortKey)
Expand Down
1 change: 1 addition & 0 deletions config/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
DestinationBlockchainsKey = "destination-blockchains"
AccountPrivateKeyKey = "account-private-key"
StorageLocationKey = "storage-location"
RedisURLKey = "redis-url"
ProcessMissedBlocksKey = "process-missed-blocks"
ManualWarpMessagesKey = "manual-warp-messages"
)
26 changes: 26 additions & 0 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"strings"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/awm-relayer/config"
"github.com/ava-labs/awm-relayer/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/pkg/errors"
"go.uber.org/zap"
)

var (
Expand Down Expand Up @@ -45,6 +47,30 @@ type RelayerDatabase interface {
Put(relayerID common.Hash, key DataKey, value []byte) error
}

func NewDatabase(logger logging.Logger, cfg *config.Config) (RelayerDatabase, error) {
if cfg.RedisURL != "" {
db, err := NewRedisDatabase(logger, cfg.RedisURL, GetConfigRelayerIDs(cfg))
if err != nil {
logger.Error(
"Failed to create Redis database",
zap.Error(err),
)
return nil, err
}
return db, nil
} else {
db, err := NewJSONFileStorage(logger, cfg.StorageLocation, GetConfigRelayerIDs(cfg))
if err != nil {
logger.Error(
"Failed to create JSON database",
zap.Error(err),
)
return nil, err
}
return db, nil
}
}

// Returns true if an error returned by a RelayerDatabase indicates the requested key was not found
func IsKeyNotFoundError(err error) bool {
return errors.Is(err, ErrRelayerIDNotFound) || errors.Is(err, ErrKeyNotFound)
Expand Down
78 changes: 78 additions & 0 deletions database/redis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (C) 2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package database

import (
"context"
"strings"

"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ethereum/go-ethereum/common"
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
)

var _ RelayerDatabase = &RedisDatabase{}

type RedisDatabase struct {
logger logging.Logger
client *redis.Client
}

func NewRedisDatabase(logger logging.Logger, redisURL string, relayerIDs []RelayerID) (*RedisDatabase, error) {
opts, err := redis.ParseURL(redisURL)
if err != nil {
logger.Error(
"Failed to parse Redis URL",
zap.String("url", redisURL),
zap.Error(err),
)
return nil, err
}

// Create a new Redis client.
// The server address, password, db index, and protocol version are extracted from the URL
// If not provided in the URL, request timeouts use the default value of 3 seconds
client := redis.NewClient(opts)
return &RedisDatabase{
logger: logger,
client: client,
}, nil
}

func (r *RedisDatabase) Get(relayerID common.Hash, key DataKey) ([]byte, error) {
ctx := context.Background()
compositeKey := constructCompositeKey(relayerID, key)
val, err := r.client.Get(ctx, compositeKey).Result()
if err != nil {
r.logger.Debug("Error retrieving key from Redis",
zap.String("key", compositeKey),
zap.Error(err))
if err == redis.Nil {
return nil, ErrKeyNotFound
}
return nil, err
}
return []byte(val), nil
}

func (r *RedisDatabase) Put(relayerID common.Hash, key DataKey, value []byte) error {
ctx := context.Background()
compositeKey := constructCompositeKey(relayerID, key)

// Persistently store the value in Redis
err := r.client.Set(ctx, compositeKey, value, 0).Err()
if err != nil {
r.logger.Error("Error storing key in Redis",
zap.String("key", compositeKey),
zap.Error(err))
return err
}
return nil
}

func constructCompositeKey(relayerID common.Hash, key DataKey) string {
const keyDelimiter = "-"
return strings.Join([]string{relayerID.Hex(), key.String()}, keyDelimiter)
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ require (
github.com/cockroachdb/redact v1.1.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 // indirect
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
Expand Down Expand Up @@ -73,6 +74,7 @@ require (
github.com/mitchellh/pointerstructure v1.2.0 // indirect
github.com/otiai10/copy v1.11.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/redis/go-redis/v9 v9.5.1 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/afero v1.9.5 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2U
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
Expand Down Expand Up @@ -520,6 +522,8 @@ github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSz
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
Expand Down
4 changes: 2 additions & 2 deletions main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func main() {
}

// Initialize the database
db, err := database.NewJSONFileStorage(logger, cfg.StorageLocation, database.GetConfigRelayerIDs(&cfg))
db, err := database.NewDatabase(logger, &cfg)
if err != nil {
logger.Error(
"Failed to create database",
Expand Down Expand Up @@ -267,7 +267,7 @@ func runRelayer(
cfg,
)
if err != nil {
return fmt.Errorf("Failed to create relayer instance: %w", err)
return fmt.Errorf("failed to create relayer instance: %w", err)
}
logger.Info(
"Created relayer",
Expand Down

0 comments on commit b437c73

Please sign in to comment.