Skip to content

Commit fb0d36f

Browse files
authored
feat: add support for zetaclient external DNS name (#4254)
* add support for zetaclient external DNS name * add changelog entry * point to go-tss tag; fix changelog PR # and add zetaclient config description * add zetaclient config file validation method
1 parent 099d3ac commit fb0d36f

File tree

12 files changed

+145
-10
lines changed

12 files changed

+145
-10
lines changed

changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ Also EnableSolanaAddressLookupTable feature flag should be set.
2929
"MempoolCongestionThreshold": 3000,
3030
```
3131

32+
* Public DNS is introduced as an alternative to public IP. It will be used when public IP field is empty.
33+
```
34+
"PublicIP": "",
35+
"PublicDNS": "my.zetaclient.com",
36+
```
37+
3238
### Features
3339

3440
* [4274](https://github.com/zeta-chain/node/pull/4274) - multiple evm calls in single tx
@@ -42,6 +48,7 @@ Also EnableSolanaAddressLookupTable feature flag should be set.
4248
* [4323](https://github.com/zeta-chain/node/pull/4323) - add dry-wrappers to zetacore client
4349
* [4328](https://github.com/zeta-chain/node/pull/4328) - missing fields in msg hash for solana outbounds
4450
* [4348](https://github.com/zeta-chain/node/pull/4348) - add mode option in ZetaClient configuration
51+
* [4254](https://github.com/zeta-chain/node/pull/4254) - add additional support for zetaclient public DNS name
4552
* [4342](https://github.com/zeta-chain/node/pull/4342) - add metrics for monitoring inbound voting through blockscan and trackers
4653

4754
### Tests

cmd/zetaclientd/initconfig.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type initializeConfigOptions struct {
1717

1818
peer string
1919
publicIP string
20+
publicDNS string
2021
logFormat string
2122
logSampler bool
2223
preParamsPath string
@@ -57,10 +58,11 @@ func setupInitializeConfigOptions() {
5758
f.Uint8Var((*uint8)(&cfg.mode), "mode", uint8(mode.StandardMode), usageMode)
5859
f.StringVar(&cfg.peer, "peer", "", usagePeer)
5960
f.StringVar(&cfg.publicIP, "public-ip", "", "public ip address")
61+
f.StringVar(&cfg.publicDNS, "public-dns", "", "public dns name (alternative to public-ip)")
6062
f.StringVar(&cfg.preParamsPath, "pre-params", "~/preParams.json", "pre-params file path")
6163
f.StringVar(&cfg.chainID, "chain-id", "athens_7001-1", "chain id")
6264
f.StringVar(&cfg.zetacoreURL, "zetacore-url", "127.0.0.1", "zetacore node URL")
63-
f.StringVar(&cfg.authzGranter, "operator", "", "granter for the authorization , this should be operator address")
65+
f.StringVar(&cfg.authzGranter, "operator", "", "granter for the authorization, this should be operator address")
6466
f.StringVar(&cfg.authzHotkey, "hotkey", "hotkey", usageHotKey)
6567
f.Int8Var(&cfg.level, "log-level", int8(zerolog.InfoLevel), usageLogLevel)
6668
f.StringVar(&cfg.logFormat, "log-format", "json", "log format (json, test)")
@@ -99,6 +101,7 @@ func InitializeConfig(_ *cobra.Command, _ []string) error {
99101
configData.ClientMode = opts.mode
100102
configData.Peer = initializeConfigOpts.peer
101103
configData.PublicIP = opts.publicIP
104+
configData.PublicDNS = opts.publicDNS
102105
configData.PreParamsPath = opts.preParamsPath
103106
configData.ChainID = opts.chainID
104107
configData.ZetaCoreURL = opts.zetacoreURL

cmd/zetaclientd/start.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ func startTelemetry(ctx context.Context, cfg config.Config) (*metrics.TelemetryS
225225
// 3. Init telemetry server
226226
telemetry := metrics.NewTelemetryServer()
227227
telemetry.SetIPAddress(cfg.PublicIP)
228+
telemetry.SetDNSName(cfg.PublicDNS)
228229

229230
// 4. Add services to the process
230231
graceful.AddStarter(ctx, pprofServer)

contrib/localnet/docker-compose.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ services:
106106
networks:
107107
mynetwork:
108108
ipv4_address: 172.20.0.21
109+
extra_hosts:
110+
- "zetaclient0.com:172.20.0.21"
109111
entrypoint: /root/start-zetaclientd.sh
110112
environment:
111113
- ETHDEV_ENDPOINT=http://eth:8545
@@ -127,6 +129,8 @@ services:
127129
networks:
128130
mynetwork:
129131
ipv4_address: 172.20.0.22
132+
extra_hosts:
133+
- "zetaclient1.com:172.20.0.22"
130134
entrypoint: /root/start-zetaclientd.sh
131135
environment:
132136
- ETHDEV_ENDPOINT=http://eth:8545
@@ -151,6 +155,8 @@ services:
151155
networks:
152156
mynetwork:
153157
ipv4_address: 172.20.0.23
158+
extra_hosts:
159+
- "zetaclient2.com:172.20.0.23"
154160
entrypoint: /root/start-zetaclientd.sh
155161
environment:
156162
- HOTKEY_BACKEND=file
@@ -173,6 +179,8 @@ services:
173179
networks:
174180
mynetwork:
175181
ipv4_address: 172.20.0.24
182+
extra_hosts:
183+
- "zetaclient3.com:172.20.0.24"
176184
entrypoint: /root/start-zetaclientd.sh
177185
environment:
178186
- HOTKEY_BACKEND=file

contrib/localnet/scripts/start-zetaclientd.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ if [[ $HOSTNAME != "zetaclient0" && ! -f ~/.zetacored/config/zetaclient_config.j
112112
num=$(echo $HOSTNAME | tr -dc '0-9')
113113
node="zetacore$num"
114114
fi
115-
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"
115+
116+
# use alternative DNS name (instead of IP) for other zetaclients (DNS should work as well)
117+
zetaclientd init --zetacore-url "$node" --chain-id athens_101-1 \
118+
--operator "$operatorAddress" --log-format=text --public-dns "$HOSTNAME.com" \
119+
--keyring-backend "$BACKEND" --pre-params "$PREPARAMS_PATH"
116120

117121
# import relayer private key for zetaclient{$num}
118122
import_relayer_key "${num}"

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ require (
306306
github.com/showa-93/go-mask v0.6.2
307307
github.com/test-go/testify v1.1.4
308308
github.com/tonkeeper/tongo v1.16.4
309-
github.com/zeta-chain/go-tss v0.6.3
309+
github.com/zeta-chain/go-tss v0.6.4
310310
github.com/zeta-chain/protocol-contracts-solana/go-idl v0.0.0-20250409230544-d88f214f6f46
311311
go.uber.org/mock v0.5.2
312312
)
@@ -320,6 +320,7 @@ require (
320320
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
321321
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
322322
github.com/allegro/bigcache v1.2.1 // indirect
323+
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
323324
github.com/bytedance/sonic v1.13.2 // indirect
324325
github.com/bytedance/sonic/loader v0.2.4 // indirect
325326
github.com/cloudwego/base64x v0.1.5 // indirect

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
719719
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
720720
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
721721
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
722+
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
723+
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
722724
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
723725
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
724726
github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
@@ -1961,8 +1963,8 @@ github.com/zeta-chain/evm v0.0.0-20250821154530-f0addce1e5ac h1:OQYitaQxJqWzyGvX
19611963
github.com/zeta-chain/evm v0.0.0-20250821154530-f0addce1e5ac/go.mod h1:WfvV0raMAIEEa5MX6kp8VyELvkwBTNw8JNVlAXtKAXA=
19621964
github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4 h1:FmO3HfVdZ7LzxBUfg6sVzV7ilKElQU2DZm8PxJ7KcYI=
19631965
github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4/go.mod h1:TBv5NY/CqWYIfUstXO1fDWrt4bDoqgCw79yihqBspg8=
1964-
github.com/zeta-chain/go-tss v0.6.3 h1:c/zSEvI0h7MJ+xxu42M58uBdEWrlzfD3NI1kP/FlWBE=
1965-
github.com/zeta-chain/go-tss v0.6.3/go.mod h1:xLssidNiAP/fcdcw+cUPA2VS7Td2bnPMS/8x0jnde8w=
1966+
github.com/zeta-chain/go-tss v0.6.4 h1:GuzpCyCrxKqjCQCeUH/+MDGc5MJukJ64i/YrS49lx5s=
1967+
github.com/zeta-chain/go-tss v0.6.4/go.mod h1:xLssidNiAP/fcdcw+cUPA2VS7Td2bnPMS/8x0jnde8w=
19661968
github.com/zeta-chain/protocol-contracts v0.0.0-20250909184950-6034c08e5870 h1:G0l52EwS5U7f5eOcQR0kD2tNE2BJtUsKlk9hFtYW7nc=
19671969
github.com/zeta-chain/protocol-contracts v0.0.0-20250909184950-6034c08e5870/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w=
19681970
github.com/zeta-chain/protocol-contracts-solana/go-idl v0.0.0-20250409230544-d88f214f6f46 h1:xbgrVDXWkZaWhMAuD3Q5A13jmRKYQbjZMPBaCkv3cns=

zetaclient/config/config.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111
"sync"
1212

13+
"github.com/asaskevich/govalidator"
1314
"github.com/fsnotify/fsnotify"
1415
"github.com/pkg/errors"
1516
"github.com/rs/zerolog"
@@ -29,6 +30,11 @@ const folder string = "config"
2930

3031
// Save saves ZetaClient config
3132
func Save(config *Config, path string) error {
33+
// validate config
34+
if err := Validate(*config); err != nil {
35+
return err
36+
}
37+
3238
folderPath := filepath.Join(path, folder)
3339
err := os.MkdirAll(folderPath, 0o750)
3440
if err != nil {
@@ -76,18 +82,40 @@ func Load(basePath string) (Config, error) {
7682
if cfg.KeyringBackend == KeyringBackendUndefined {
7783
cfg.KeyringBackend = KeyringBackendTest
7884
}
79-
if cfg.KeyringBackend != KeyringBackendFile && cfg.KeyringBackend != KeyringBackendTest {
80-
return Config{}, fmt.Errorf("invalid keyring backend %s", cfg.KeyringBackend)
81-
}
8285

8386
// fields sanitization
8487
cfg.TssPath = GetPath(cfg.TssPath)
8588
cfg.PreParamsPath = GetPath(cfg.PreParamsPath)
8689
cfg.ZetaCoreHome = basePath
8790

91+
// validate config
92+
if err := Validate(cfg); err != nil {
93+
return Config{}, err
94+
}
95+
8896
return cfg, nil
8997
}
9098

99+
// Validate performs basic validation on the config fields
100+
// TODO: add more validation for other fields
101+
// https://github.com/zeta-chain/node/issues/4352
102+
func Validate(cfg Config) error {
103+
// go-tss requires a valid IPv4 address
104+
if cfg.PublicIP != "" && !govalidator.IsIPv4(cfg.PublicIP) {
105+
return fmt.Errorf("invalid public IP %s", cfg.PublicIP)
106+
}
107+
108+
if cfg.PublicDNS != "" && !govalidator.IsDNSName(cfg.PublicDNS) {
109+
return fmt.Errorf("invalid public DNS %s", cfg.PublicDNS)
110+
}
111+
112+
if cfg.KeyringBackend != KeyringBackendFile && cfg.KeyringBackend != KeyringBackendTest {
113+
return fmt.Errorf("invalid keyring backend %s", cfg.KeyringBackend)
114+
}
115+
116+
return nil
117+
}
118+
91119
// SetRestrictedAddressesFromConfig loads compliance data (restricted addresses) from config.
92120
func SetRestrictedAddressesFromConfig(cfg Config) {
93121
restrictedAddressBook = cfg.GetRestrictedAddressBook()

zetaclient/config/config_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,63 @@ import (
1313
"github.com/zeta-chain/node/zetaclient/config"
1414
)
1515

16+
func TestValidate(t *testing.T) {
17+
tests := []struct {
18+
name string
19+
config config.Config
20+
expectError bool
21+
errorMsg string
22+
}{
23+
{
24+
name: "valid config with default fields",
25+
config: func() config.Config {
26+
cfg := config.New(false)
27+
cfg.KeyringBackend = "test"
28+
return cfg
29+
}(),
30+
},
31+
{
32+
name: "invalid public IP address",
33+
config: func() config.Config {
34+
cfg := config.New(false)
35+
cfg.PublicIP = "192.168.1"
36+
return cfg
37+
}(),
38+
errorMsg: "invalid public IP 192.168.1",
39+
},
40+
{
41+
name: "invalid DNS name",
42+
config: func() config.Config {
43+
cfg := config.New(false)
44+
cfg.PublicDNS = "invalid..dns"
45+
return cfg
46+
}(),
47+
errorMsg: "invalid public DNS invalid..dns",
48+
},
49+
{
50+
name: "invalid keyring backend",
51+
config: func() config.Config {
52+
cfg := config.New(false)
53+
cfg.KeyringBackend = "invalid"
54+
return cfg
55+
}(),
56+
errorMsg: "invalid keyring backend invalid",
57+
},
58+
}
59+
60+
for _, tt := range tests {
61+
t.Run(tt.name, func(t *testing.T) {
62+
err := config.Validate(tt.config)
63+
64+
if tt.errorMsg != "" {
65+
require.ErrorContains(t, err, tt.errorMsg)
66+
return
67+
}
68+
require.NoError(t, err, "expected no error, got %v", err)
69+
})
70+
}
71+
}
72+
1673
func Test_LoadRestrictedAddressesConfig(t *testing.T) {
1774
// Create test addresses
1875
testAddresses := []string{

zetaclient/config/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ type Config struct {
100100

101101
Peer string `json:"Peer"`
102102
PublicIP string `json:"PublicIP"`
103+
PublicDNS string `json:"PublicDNS"`
103104
LogFormat string `json:"LogFormat"`
104105
LogLevel int8 `json:"LogLevel"`
105106
LogSampler bool `json:"LogSampler"`

0 commit comments

Comments
 (0)