// Copyright (c) 2017-2026 Lethean (https://lt.hn) // SPDX-License-Identifier: EUPL-1.2 package node import ( "bytes" "io" "net/http" ) // info, err := node.GetChainInfo(LetheanMainnetDaemon) // pools := node.DiscoverPools(LetheanTestnetDaemon) const ( LetheanTestnetDaemon = "http://127.0.0.1:46941" LetheanMainnetDaemon = "http://127.0.0.1:36941" LetheanTestnetPool = "stratum+tcp://pool.lthn.io:5555" LetheanMainnetPool = "stratum+tcp://pool.lthn.io:3333" ) // info, err := node.GetChainInfo("http://127.0.0.1:46941") // if info.Synced { log("height:", info.Height, "aliases:", info.AliasCount) } type ChainInfo struct { Height uint64 `json:"height"` AliasCount int `json:"alias_count"` Synced bool `json:"synced"` PoolSize int `json:"tx_pool_size"` Difficulty uint64 `json:"difficulty"` } // pools := node.DiscoverPools("http://127.0.0.1:46941") // for _, pool := range pools { log(pool.Name, pool.Endpoint) } type PoolGateway struct { Name string `json:"name"` Address string `json:"address"` Capabilities string `json:"caps"` Endpoint string `json:"endpoint"` } // info, err := node.GetChainInfo("http://127.0.0.1:46941") // if err == nil && info.Synced { log("chain height:", info.Height) } func GetChainInfo(daemonURL string) (*ChainInfo, error) { requestBody := `{"jsonrpc":"2.0","id":"0","method":"getinfo","params":{}}` response, err := http.Post(daemonURL+"/json_rpc", "application/json", bytes.NewReader([]byte(requestBody))) if err != nil { return nil, err } defer response.Body.Close() responseBody, _ := io.ReadAll(response.Body) var rpcResponse struct { Result ChainInfo `json:"result"` } if err := UnmarshalJSON(responseBody, &rpcResponse); err != nil { return nil, err } rpcResponse.Result.Synced = rpcResponse.Result.Height > 0 return &rpcResponse.Result, nil } // pools := node.DiscoverPools("http://127.0.0.1:46941") // for _, pool := range pools { log(pool.Name, pool.Endpoint) } func DiscoverPools(daemonURL string) []PoolGateway { requestBody := `{"jsonrpc":"2.0","id":"0","method":"get_all_alias_details","params":{}}` response, err := http.Post(daemonURL+"/json_rpc", "application/json", bytes.NewReader([]byte(requestBody))) if err != nil { return nil } defer response.Body.Close() responseBody, _ := io.ReadAll(response.Body) var rpcResponse struct { Result struct { Aliases []struct { Alias string `json:"alias"` Address string `json:"address"` Comment string `json:"comment"` } `json:"aliases"` } `json:"result"` } UnmarshalJSON(responseBody, &rpcResponse) //nolint:errcheck var pools []PoolGateway for _, alias := range rpcResponse.Result.Aliases { if !bytes.Contains([]byte(alias.Comment), []byte("pool")) { continue } commentFields := parseComment(alias.Comment) pools = append(pools, PoolGateway{ Name: alias.Alias, Address: alias.Address, Capabilities: commentFields["cap"], Endpoint: "stratum+tcp://" + alias.Alias + ".lthn:5555", }) } return pools } // gateways := node.DiscoverGateways("http://127.0.0.1:46941") // for _, gateway := range gateways { log(gateway.Name, gateway.Endpoint) } func DiscoverGateways(daemonURL string) []PoolGateway { requestBody := `{"jsonrpc":"2.0","id":"0","method":"get_all_alias_details","params":{}}` response, err := http.Post(daemonURL+"/json_rpc", "application/json", bytes.NewReader([]byte(requestBody))) if err != nil { return nil } defer response.Body.Close() responseBody, _ := io.ReadAll(response.Body) var rpcResponse struct { Result struct { Aliases []struct { Alias string `json:"alias"` Address string `json:"address"` Comment string `json:"comment"` } `json:"aliases"` } `json:"result"` } UnmarshalJSON(responseBody, &rpcResponse) //nolint:errcheck var gateways []PoolGateway for _, alias := range rpcResponse.Result.Aliases { if !bytes.Contains([]byte(alias.Comment), []byte("type=gateway")) { continue } commentFields := parseComment(alias.Comment) gateways = append(gateways, PoolGateway{ Name: alias.Alias, Address: alias.Address, Capabilities: commentFields["cap"], Endpoint: alias.Alias + ".lthn", }) } return gateways } // parsed := parseComment("cap=pool;endpoint=stratum+tcp://pool.lthn.io:3333") // parsed["cap"] // "pool" // parsed["endpoint"] // "stratum+tcp://pool.lthn.io:3333" func parseComment(comment string) map[string]string { fields := make(map[string]string) for _, segment := range bytes.Split([]byte(comment), []byte(";")) { separatorIndex := bytes.IndexByte(segment, '=') if separatorIndex > 0 { fields[string(segment[:separatorIndex])] = string(segment[separatorIndex+1:]) } } return fields }