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
4 changes: 2 additions & 2 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ jobs:
steps:
- uses: actions/setup-go@v5
with:
go-version: 1.24.2
go-version: 1.25.3

- uses: actions/checkout@v4

- name: golangci-lint
uses: golangci/golangci-lint-action@v7
with:
version: v2.1.6
version: v2.12.2
args: --timeout=5m0s
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ============================ Build Stage ============================
FROM --platform=$BUILDPLATFORM golang:1.24.2-alpine3.20 AS build
FROM --platform=$BUILDPLATFORM golang:1.25.3-alpine3.21 AS build

LABEL org.opencontainers.image.source="https://github.com/bandprotocol/falcon"

Expand Down
23 changes: 7 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ sudo apt-get update && \
sudo apt-get upgrade -y && \
sudo apt-get install -y build-essential curl wget jq
```
- Install Go 1.24.2
- Install Go 1.25.3
```shell
# Install Go 1.24.2
wget https://go.dev/dl/go1.24.2.linux-amd64.tar.gz
tar xf go1.24.2.linux-amd64.tar.gz
# Install Go 1.25.3
wget https://go.dev/dl/go1.25.3.linux-amd64.tar.gz
tar xf go1.25.3.linux-amd64.tar.gz
sudo mv go /usr/local/go

# Set Go path to $PATH variable
Expand Down Expand Up @@ -247,38 +247,30 @@ Enter your private key
If you already have a mnemonic and want to retrieve key from it, you can choose `Mnemonic` option.
```
Enter your mnemonic
>

Enter a coin type
Coin type number for HD derivation (default: 60; leave empty to use default)
>

Enter an account
Account number in the HD derivation path (default: 0; leave empty to use default)
>

Enter an index
Index number for the specific address within an account in the HD derivation path (default: 0; leave empty to use default)
>
```
Comment thread
RogerKSI marked this conversation as resolved.

If you want to generate a new address, choose the `Generate new address` option.
```
Enter a coin type
Coin type number for HD derivation (default: 60; leave empty to use default)
>

Enter an account
Account number in the HD derivation path (default: 0; leave empty to use default)
>

Enter an index
Index number for the specific address within an account in the HD derivation path (default: 0; leave empty to use default)
>
```

### 7. Check that the keys for the configured chains are funded

You can query the balance of each configured key by running:
``` shell
falcon q balance testkey
Expand All @@ -288,15 +280,14 @@ Starts all tunnels that `falcon query tunnels` can query
``` shell
falcon start
```
> NOTE: You can choose which tunnels do you want to relay.
NOTE: You can choose which tunnels do you want to relay.
``` shell
falcon start 1 2 3
```

## Generate Go Protobuf Code
Falcon uses gRPC and Protocol Buffers for its internal APIs.
If you modify any `.proto` files under the `proto/` directory, regenerate the Go code by running:

```sh
make proto
```
Expand All @@ -320,8 +311,8 @@ go install github.com/pressly/goose/v3/cmd/goose@latest
```

#### Run
> Use `-dir` before the driver/DSN.
> Supported drivers: `postgres`, `sqlite`.
Use `-dir` before the driver/DSN.
Supported drivers: `postgres`, `sqlite`.

##### Up (apply all pending)
```sh
Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/bandprotocol/falcon

go 1.24.3
go 1.25.3

Comment on lines 1 to 4
require (
cosmossdk.io/math v1.4.0
Expand Down Expand Up @@ -30,7 +30,7 @@ require (
go.uber.org/mock v0.6.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.46.0
google.golang.org/grpc v1.77.0
google.golang.org/grpc v1.79.3
google.golang.org/protobuf v1.36.11
gorm.io/driver/postgres v1.6.0
gorm.io/driver/sqlite v1.6.0
Expand Down Expand Up @@ -156,7 +156,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
github.com/jackc/pgx/v5 v5.9.0 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
Expand Down Expand Up @@ -241,9 +241,9 @@ require (
go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel v1.39.0 // indirect
go.opentelemetry.io/otel/metric v1.39.0 // indirect
go.opentelemetry.io/otel/trace v1.39.0 // indirect
go.opentelemetry.io/otel v1.41.0 // indirect
go.opentelemetry.io/otel/metric v1.41.0 // indirect
go.opentelemetry.io/otel/trace v1.41.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/net v0.48.0 // indirect
Expand Down
24 changes: 12 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
github.com/jackc/pgx/v5 v5.9.0 h1:T/dI+2TvmI2H8s/KH1/lXIbz1CUFk3gn5oTjr0/mBsE=
github.com/jackc/pgx/v5 v5.9.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
Expand Down Expand Up @@ -1094,16 +1094,16 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
Expand Down Expand Up @@ -1488,8 +1488,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
Expand Down
53 changes: 38 additions & 15 deletions relayer/chains/evm/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ type Client interface {

// Client is the struct that handles interactions with the EVM chain.
type client struct {
ChainName string
Endpoints []string
QueryTimeout time.Duration
ExecuteTimeout time.Duration
ChainName string
Endpoints []string
QueryTimeout time.Duration
ExecuteTimeout time.Duration
BlockConfirmation uint64

Log logger.Logger

Expand Down Expand Up @@ -90,13 +91,14 @@ func dialEVMEndpoint(ctx context.Context, endpoint string) (*ethclient.Client, e
// NewClient creates a new EVM client from config file and load keys.
func NewClient(chainName string, cfg *EVMChainProviderConfig, log logger.Logger, alert alert.Alert) *client {
return &client{
ChainName: chainName,
Endpoints: cfg.Endpoints,
QueryTimeout: cfg.QueryTimeout,
ExecuteTimeout: cfg.ExecuteTimeout,
Log: log.With("chain_name", chainName),
alert: alert,
clients: NewEVMClients(),
ChainName: chainName,
Endpoints: cfg.Endpoints,
QueryTimeout: cfg.QueryTimeout,
ExecuteTimeout: cfg.ExecuteTimeout,
BlockConfirmation: cfg.BlockConfirmation,
Log: log.With("chain_name", chainName),
alert: alert,
clients: NewEVMClients(),
}
}

Expand Down Expand Up @@ -504,7 +506,10 @@ func (c *client) BroadcastTx(ctx context.Context, tx *gethtypes.Transaction) (st
return tx.Hash().Hex(), nil
}

// getClientWithMaxHeight connects to the endpoint that has the highest block height.
// getClientWithMaxHeight selects an endpoint by config order within the confirmed
// block range. It collects block heights from all endpoints in parallel, then
// picks the first endpoint (in config order) whose block height is within
// [maxHeight - BlockConfirmation, maxHeight].
func (c *client) getClientWithMaxHeight(ctx context.Context) (ClientConnectionResult, error) {
ch := make(chan ClientConnectionResult, len(c.Endpoints))

Expand Down Expand Up @@ -554,16 +559,34 @@ func (c *client) getClientWithMaxHeight(ctx context.Context) (ClientConnectionRe
}(endpoint)
}

var result ClientConnectionResult
// Collect all results into a map and track the maximum block height.
resultMap := make(map[string]ClientConnectionResult, len(c.Endpoints))
var maxHeight uint64
for i := 0; i < len(c.Endpoints); i++ {
r := <-ch
if r.Client != nil {
if r.BlockHeight > result.BlockHeight || (r.Endpoint == c.clients.GetSelectedEndpoint() && r.BlockHeight == result.BlockHeight) {
result = r
resultMap[r.Endpoint] = r
if r.BlockHeight > maxHeight {
maxHeight = r.BlockHeight
}
}
}

// Determine the minimum acceptable block height based on BlockConfirmation.
var minHeight uint64
if maxHeight >= c.BlockConfirmation {
minHeight = maxHeight - c.BlockConfirmation
}

// Pick the first endpoint in config order that is within the confirmed range.
var result ClientConnectionResult
for _, endpoint := range c.Endpoints {
if r, ok := resultMap[endpoint]; ok && r.BlockHeight >= minHeight {
result = r
break
}
}

if result.Client == nil {
alert.HandleAlert(
c.alert,
Expand Down
57 changes: 40 additions & 17 deletions relayer/chains/flow/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ var _ Client = (*client)(nil)

// client is the concrete implementation that handles Flow HTTP interactions.
type client struct {
ChainName string
Endpoints []string
QueryTimeout time.Duration
ExecuteTimeout time.Duration
ChainName string
Endpoints []string
QueryTimeout time.Duration
ExecuteTimeout time.Duration
BlockConfirmation uint64

Log logger.Logger
alert alert.Alert
Expand All @@ -61,17 +62,19 @@ type client struct {
// NewClient creates a new Flow client from config.
func NewClient(chainName string, cfg *FlowChainProviderConfig, log logger.Logger, a alert.Alert) Client {
return &client{
ChainName: chainName,
Endpoints: cfg.Endpoints,
QueryTimeout: cfg.QueryTimeout,
ExecuteTimeout: cfg.ExecuteTimeout,
Log: log.With("chain_name", chainName),
alert: a,
clients: NewFlowClients(),
ChainName: chainName,
Endpoints: cfg.Endpoints,
QueryTimeout: cfg.QueryTimeout,
ExecuteTimeout: cfg.ExecuteTimeout,
BlockConfirmation: 5,
Log: log.With("chain_name", chainName),
alert: a,
clients: NewFlowClients(),
Comment thread
RogerKSI marked this conversation as resolved.
}
Comment thread
RogerKSI marked this conversation as resolved.
}

// Connect connects to all endpoints and selects the one with the highest block height.
// Connect connects to all endpoints and selects the first eligible one by config order
// within the confirmed block range.
func (c *client) Connect(_ context.Context) error {
var wg sync.WaitGroup
for _, endpoint := range c.Endpoints {
Expand Down Expand Up @@ -123,7 +126,10 @@ func (c *client) Connect(_ context.Context) error {
return nil
}

// getClientWithMaxHeight selects the endpoint with the highest sealed block height.
// getClientWithMaxHeight selects an endpoint by config order within the confirmed
// block range. It collects block heights from all endpoints in parallel, then
// picks the first endpoint (in config order) whose block height is within
// [maxHeight - BlockConfirmation, maxHeight].
func (c *client) getClientWithMaxHeight() (ClientConnectionResult, error) {
ch := make(chan ClientConnectionResult, len(c.Endpoints))

Expand Down Expand Up @@ -163,17 +169,34 @@ func (c *client) getClientWithMaxHeight() (ClientConnectionResult, error) {
}(endpoint)
}

var result ClientConnectionResult
// Collect all results into a map and track the maximum block height.
resultMap := make(map[string]ClientConnectionResult, len(c.Endpoints))
var maxHeight uint64
for range c.Endpoints {
r := <-ch
if r.Client != nil {
if r.BlockHeight > result.BlockHeight ||
(r.Endpoint == c.clients.GetSelectedEndpoint() && r.BlockHeight == result.BlockHeight) {
result = r
resultMap[r.Endpoint] = r
if r.BlockHeight > maxHeight {
maxHeight = r.BlockHeight
}
}
}

// Determine the minimum acceptable block height based on BlockConfirmation.
var minHeight uint64
if maxHeight >= c.BlockConfirmation {
minHeight = maxHeight - c.BlockConfirmation
}

// Pick the first endpoint in config order that is within the confirmed range.
var result ClientConnectionResult
for _, endpoint := range c.Endpoints {
if r, ok := resultMap[endpoint]; ok && r.BlockHeight >= minHeight {
result = r
break
}
}

if result.Client == nil {
alert.HandleAlert(
c.alert,
Expand Down
Loading
Loading