Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
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
34 changes: 17 additions & 17 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,56 +247,56 @@ 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)
>
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
>
Comment thread
RogerKSI marked this conversation as resolved.
Outdated
```
### 8. Start to relay packet
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,16 +320,16 @@ 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
# Postgres
goose -dir relayer/db/migrations/postgres postgres "postgres://user:password@localhost:5432/falcon?sslmode=disable" up

# SQLite
goose -dir relayer/db/migrations/sqlite sqlite "gorm.db" up
> # SQLite
> goose -dir relayer/db/migrations/sqlite sqlite "gorm.db" up
```

##### Down (revert one step)
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