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
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
* [4342](https://github.com/zeta-chain/node/pull/4342) - add metrics for monitoring inbound voting through blockscan and trackers

### 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 @@ -151,6 +155,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 @@ -173,6 +179,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