Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ Also EnableSolanaAddressLookupTable feature flag should be set.
"MempoolCongestionThreshold": 3000,
```

* Public DNS is introduced as an alternative to public IP. It will be used when public IP field is empty.
```
"PublicIP": "",
"PublicDNS": "my.zetaclient.com",
```

### Features

* [4274](https://github.com/zeta-chain/node/pull/4274) - multiple evm calls in single tx
Expand All @@ -42,6 +48,7 @@ Also EnableSolanaAddressLookupTable feature flag should be set.
* [4323](https://github.com/zeta-chain/node/pull/4323) - add dry-wrappers to zetacore client
* [4328](https://github.com/zeta-chain/node/pull/4328) - missing fields in msg hash for solana outbounds
* [4348](https://github.com/zeta-chain/node/pull/4348) - add mode option in ZetaClient configuration
* [4254](https://github.com/zeta-chain/node/pull/4254) - add additional support for zetaclient public DNS name

### Tests

Expand Down
5 changes: 4 additions & 1 deletion cmd/zetaclientd/initconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type initializeConfigOptions struct {

peer string
publicIP string
publicDNS string
logFormat string
logSampler bool
preParamsPath string
Expand Down Expand Up @@ -57,10 +58,11 @@ func setupInitializeConfigOptions() {
f.Uint8Var((*uint8)(&cfg.mode), "mode", uint8(mode.StandardMode), usageMode)
f.StringVar(&cfg.peer, "peer", "", usagePeer)
f.StringVar(&cfg.publicIP, "public-ip", "", "public ip address")
f.StringVar(&cfg.publicDNS, "public-dns", "", "public dns name (alternative to public-ip)")
f.StringVar(&cfg.preParamsPath, "pre-params", "~/preParams.json", "pre-params file path")
f.StringVar(&cfg.chainID, "chain-id", "athens_7001-1", "chain id")
f.StringVar(&cfg.zetacoreURL, "zetacore-url", "127.0.0.1", "zetacore node URL")
f.StringVar(&cfg.authzGranter, "operator", "", "granter for the authorization , this should be operator address")
f.StringVar(&cfg.authzGranter, "operator", "", "granter for the authorization, this should be operator address")
f.StringVar(&cfg.authzHotkey, "hotkey", "hotkey", usageHotKey)
f.Int8Var(&cfg.level, "log-level", int8(zerolog.InfoLevel), usageLogLevel)
f.StringVar(&cfg.logFormat, "log-format", "json", "log format (json, test)")
Expand Down Expand Up @@ -99,6 +101,7 @@ func InitializeConfig(_ *cobra.Command, _ []string) error {
configData.ClientMode = opts.mode
configData.Peer = initializeConfigOpts.peer
configData.PublicIP = opts.publicIP
configData.PublicDNS = opts.publicDNS
configData.PreParamsPath = opts.preParamsPath
configData.ChainID = opts.chainID
configData.ZetaCoreURL = opts.zetacoreURL
Expand Down
1 change: 1 addition & 0 deletions cmd/zetaclientd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ func startTelemetry(ctx context.Context, cfg config.Config) (*metrics.TelemetryS
// 3. Init telemetry server
telemetry := metrics.NewTelemetryServer()
telemetry.SetIPAddress(cfg.PublicIP)
telemetry.SetDNSName(cfg.PublicDNS)

// 4. Add services to the process
graceful.AddStarter(ctx, pprofServer)
Expand Down
8 changes: 8 additions & 0 deletions contrib/localnet/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ services:
networks:
mynetwork:
ipv4_address: 172.20.0.21
extra_hosts:
- "zetaclient0.com:172.20.0.21"
entrypoint: /root/start-zetaclientd.sh
environment:
- ETHDEV_ENDPOINT=http://eth:8545
Expand All @@ -127,6 +129,8 @@ services:
networks:
mynetwork:
ipv4_address: 172.20.0.22
extra_hosts:
- "zetaclient1.com:172.20.0.22"
entrypoint: /root/start-zetaclientd.sh
environment:
- ETHDEV_ENDPOINT=http://eth:8545
Expand All @@ -147,6 +151,8 @@ services:
networks:
mynetwork:
ipv4_address: 172.20.0.23
extra_hosts:
- "zetaclient2.com:172.20.0.23"
entrypoint: /root/start-zetaclientd.sh
environment:
- HOTKEY_BACKEND=file
Expand All @@ -165,6 +171,8 @@ services:
networks:
mynetwork:
ipv4_address: 172.20.0.24
extra_hosts:
- "zetaclient3.com:172.20.0.24"
entrypoint: /root/start-zetaclientd.sh
environment:
- HOTKEY_BACKEND=file
Expand Down
6 changes: 5 additions & 1 deletion contrib/localnet/scripts/start-zetaclientd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ if [[ $HOSTNAME != "zetaclient0" && ! -f ~/.zetacored/config/zetaclient_config.j
num=$(echo $HOSTNAME | tr -dc '0-9')
node="zetacore$num"
fi
zetaclientd init --zetacore-url "$node" --chain-id athens_101-1 --operator "$operatorAddress" --log-format=text --public-ip "$MYIP" --log-level 1 --keyring-backend "$BACKEND" --pre-params "$PREPARAMS_PATH"

# use alternative DNS name (instead of IP) for other zetaclients (DNS should work as well)
zetaclientd init --zetacore-url "$node" --chain-id athens_101-1 \
--operator "$operatorAddress" --log-format=text --public-dns "$HOSTNAME.com" \
--keyring-backend "$BACKEND" --pre-params "$PREPARAMS_PATH"

# import relayer private key for zetaclient{$num}
import_relayer_key "${num}"
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ require (
github.com/showa-93/go-mask v0.6.2
github.com/test-go/testify v1.1.4
github.com/tonkeeper/tongo v1.16.4
github.com/zeta-chain/go-tss v0.6.3
github.com/zeta-chain/go-tss v0.6.4
github.com/zeta-chain/protocol-contracts-solana/go-idl v0.0.0-20250409230544-d88f214f6f46
go.uber.org/mock v0.5.2
)
Expand All @@ -320,6 +320,7 @@ require (
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
github.com/allegro/bigcache v1.2.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/bytedance/sonic v1.13.2 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
Expand Down Expand Up @@ -1961,8 +1963,8 @@ github.com/zeta-chain/evm v0.0.0-20250821154530-f0addce1e5ac h1:OQYitaQxJqWzyGvX
github.com/zeta-chain/evm v0.0.0-20250821154530-f0addce1e5ac/go.mod h1:WfvV0raMAIEEa5MX6kp8VyELvkwBTNw8JNVlAXtKAXA=
github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4 h1:FmO3HfVdZ7LzxBUfg6sVzV7ilKElQU2DZm8PxJ7KcYI=
github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4/go.mod h1:TBv5NY/CqWYIfUstXO1fDWrt4bDoqgCw79yihqBspg8=
github.com/zeta-chain/go-tss v0.6.3 h1:c/zSEvI0h7MJ+xxu42M58uBdEWrlzfD3NI1kP/FlWBE=
github.com/zeta-chain/go-tss v0.6.3/go.mod h1:xLssidNiAP/fcdcw+cUPA2VS7Td2bnPMS/8x0jnde8w=
github.com/zeta-chain/go-tss v0.6.4 h1:GuzpCyCrxKqjCQCeUH/+MDGc5MJukJ64i/YrS49lx5s=
github.com/zeta-chain/go-tss v0.6.4/go.mod h1:xLssidNiAP/fcdcw+cUPA2VS7Td2bnPMS/8x0jnde8w=
github.com/zeta-chain/protocol-contracts v0.0.0-20250909184950-6034c08e5870 h1:G0l52EwS5U7f5eOcQR0kD2tNE2BJtUsKlk9hFtYW7nc=
github.com/zeta-chain/protocol-contracts v0.0.0-20250909184950-6034c08e5870/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w=
github.com/zeta-chain/protocol-contracts-solana/go-idl v0.0.0-20250409230544-d88f214f6f46 h1:xbgrVDXWkZaWhMAuD3Q5A13jmRKYQbjZMPBaCkv3cns=
Expand Down
34 changes: 31 additions & 3 deletions zetaclient/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"
"sync"

"github.com/asaskevich/govalidator"
"github.com/fsnotify/fsnotify"
"github.com/pkg/errors"
"github.com/rs/zerolog"
Expand All @@ -29,6 +30,11 @@ const folder string = "config"

// Save saves ZetaClient config
func Save(config *Config, path string) error {
// validate config
if err := Validate(*config); err != nil {
return err
}

folderPath := filepath.Join(path, folder)
err := os.MkdirAll(folderPath, 0o750)
if err != nil {
Expand Down Expand Up @@ -76,18 +82,40 @@ func Load(basePath string) (Config, error) {
if cfg.KeyringBackend == KeyringBackendUndefined {
cfg.KeyringBackend = KeyringBackendTest
}
if cfg.KeyringBackend != KeyringBackendFile && cfg.KeyringBackend != KeyringBackendTest {
return Config{}, fmt.Errorf("invalid keyring backend %s", cfg.KeyringBackend)
}

// fields sanitization
cfg.TssPath = GetPath(cfg.TssPath)
cfg.PreParamsPath = GetPath(cfg.PreParamsPath)
cfg.ZetaCoreHome = basePath

// validate config
if err := Validate(cfg); err != nil {
return Config{}, err
}

return cfg, nil
}

// Validate performs basic validation on the config fields
// TODO: add more validation for other fields
// https://github.com/zeta-chain/node/issues/4352
func Validate(cfg Config) error {
// go-tss requires a valid IPv4 address
if cfg.PublicIP != "" && !govalidator.IsIPv4(cfg.PublicIP) {
return fmt.Errorf("invalid public IP %s", cfg.PublicIP)
}

if cfg.PublicDNS != "" && !govalidator.IsDNSName(cfg.PublicDNS) {
return fmt.Errorf("invalid public DNS %s", cfg.PublicDNS)
}

if cfg.KeyringBackend != KeyringBackendFile && cfg.KeyringBackend != KeyringBackendTest {
return fmt.Errorf("invalid keyring backend %s", cfg.KeyringBackend)
}

return nil
}

// SetRestrictedAddressesFromConfig loads compliance data (restricted addresses) from config.
func SetRestrictedAddressesFromConfig(cfg Config) {
restrictedAddressBook = cfg.GetRestrictedAddressBook()
Expand Down
57 changes: 57 additions & 0 deletions zetaclient/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,63 @@ import (
"github.com/zeta-chain/node/zetaclient/config"
)

func TestValidate(t *testing.T) {
tests := []struct {
name string
config config.Config
expectError bool
errorMsg string
}{
{
name: "valid config with default fields",
config: func() config.Config {
cfg := config.New(false)
cfg.KeyringBackend = "test"
return cfg
}(),
},
{
name: "invalid public IP address",
config: func() config.Config {
cfg := config.New(false)
cfg.PublicIP = "192.168.1"
return cfg
}(),
errorMsg: "invalid public IP 192.168.1",
},
{
name: "invalid DNS name",
config: func() config.Config {
cfg := config.New(false)
cfg.PublicDNS = "invalid..dns"
return cfg
}(),
errorMsg: "invalid public DNS invalid..dns",
},
{
name: "invalid keyring backend",
config: func() config.Config {
cfg := config.New(false)
cfg.KeyringBackend = "invalid"
return cfg
}(),
errorMsg: "invalid keyring backend invalid",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := config.Validate(tt.config)

if tt.errorMsg != "" {
require.ErrorContains(t, err, tt.errorMsg)
return
}
require.NoError(t, err, "expected no error, got %v", err)
})
}
}

func Test_LoadRestrictedAddressesConfig(t *testing.T) {
// Create test addresses
testAddresses := []string{
Expand Down
1 change: 1 addition & 0 deletions zetaclient/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type Config struct {

Peer string `json:"Peer"`
PublicIP string `json:"PublicIP"`
PublicDNS string `json:"PublicDNS"`
LogFormat string `json:"LogFormat"`
LogLevel int8 `json:"LogLevel"`
LogSampler bool `json:"LogSampler"`
Expand Down
22 changes: 22 additions & 0 deletions zetaclient/metrics/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type TelemetryServer struct {
lastStartTimestamp time.Time
status types.Status
ipAddress string
dnsName string
HotKeyBurnRate *BurnRate
connectedPeers []peer.AddrInfo
rtt map[peer.ID]int64
Expand Down Expand Up @@ -107,6 +108,20 @@ func (t *TelemetryServer) GetIPAddress() string {
return t.ipAddress
}

// SetDNSName sets p2p dns name
func (t *TelemetryServer) SetDNSName(dns string) {
t.mu.Lock()
defer t.mu.Unlock()
t.dnsName = dns
}

// GetDNSName gets p2p dns name
func (t *TelemetryServer) GetDNSName() string {
t.mu.Lock()
defer t.mu.Unlock()
return t.dnsName
}

// GetLastStartTimestamp returns last start timestamp
func (t *TelemetryServer) GetLastStartTimestamp() time.Time {
t.mu.Lock()
Expand Down Expand Up @@ -180,6 +195,7 @@ func (t *TelemetryServer) Handlers() http.Handler {
router.Handle("/lastcoreblock", http.HandlerFunc(t.lastCoreBlockHandler)).Methods(http.MethodGet)
router.Handle("/status", http.HandlerFunc(t.statusHandler)).Methods(http.MethodGet)
router.Handle("/ip", http.HandlerFunc(t.ipHandler)).Methods(http.MethodGet)
router.Handle("/dns", http.HandlerFunc(t.dnsHandler)).Methods(http.MethodGet)
router.Handle("/hotkeyburnrate", http.HandlerFunc(t.hotKeyFeeBurnRate)).Methods(http.MethodGet)
router.Handle("/connectedpeers", http.HandlerFunc(t.connectedPeersHandler)).Methods(http.MethodGet)
router.Handle("/pingrtt", http.HandlerFunc(t.pingRTTHandler)).Methods(http.MethodGet)
Expand Down Expand Up @@ -232,6 +248,12 @@ func (t *TelemetryServer) ipHandler(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintf(w, "%s", t.GetIPAddress())
}

// dnsHandler returns the dns name
func (t *TelemetryServer) dnsHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "%s", t.GetDNSName())
}

func (t *TelemetryServer) lastScannedBlockHandler(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")

Expand Down
5 changes: 3 additions & 2 deletions zetaclient/tss/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ func NewServer(
return nil, errors.New("tss password is empty")
case privateKey == nil:
return nil, errors.New("private key is nil")
case cfg.PublicIP == "":
logger.Warn().Msg("public IP is empty")
case cfg.PublicIP == "" && cfg.PublicDNS == "":
logger.Warn().Msg("no public IP or DNS is provided")
}

tssPath, err := resolveTSSPath(cfg.TssPath, logger)
Expand All @@ -225,6 +225,7 @@ func NewServer(
PreParamTimeout: 5 * time.Minute,
},
ExternalIP: cfg.PublicIP,
ExternalDNS: cfg.PublicDNS,
Port: Port,
BootstrapPeers: bootstrapPeers,
WhitelistedPeers: whitelistPeers,
Expand Down