wormhole/node/cmd/guardiand/adminnodes.go

206 lines
4.8 KiB
Go
Raw Normal View History

package guardiand
import (
"context"
"fmt"
"log"
"os"
"sort"
"strings"
"text/tabwriter"
"time"
publicrpcv1 "github.com/certusone/wormhole/node/pkg/proto/publicrpc/v1"
"github.com/spf13/cobra"
"github.com/wormhole-foundation/wormhole/sdk/vaa"
)
// How to test in container:
// kubectl exec guardian-0 -- /guardiand admin list-nodes --socket /tmp/admin.sock
var (
showDetails bool
only []string
)
func init() {
AdminClientListNodes.Flags().BoolVar(&showDetails, "showDetails", false, "Show error counter and contract addresses")
AdminClientListNodes.Flags().StringSliceVar(&only, "only", nil, "Show only networks with the given name")
}
var AdminClientListNodes = &cobra.Command{
Use: "list-nodes",
Short: "Fetches an aggregated list of guardian nodes",
Run: runListNodes,
}
func runListNodes(cmd *cobra.Command, args []string) {
ctx := context.Background()
Chain governor (#1277) * Rebase * Reload from db on start up Change-Id: I1deac9db28ad1157ea7e0c84af41c35b38497f4e * Console commands Change-Id: Ic242038312b7c837443a2df8823f100b3cdffd77 * Query prices from CoinGecko Change-Id: I9a8c282ba374d32ef7045d11979a27ede3c52827 * Move chain config to separate file Change-Id: I6a790eca765bce1f2caf48134e225df5c4daff15 * More code cleanup Change-Id: Id12affa78cdc2d394d6dab0c53bb7ad06df8007e * Few minor tweaks Change-Id: I6cb511599d669e0b3d716d9f314ac0f26935ee92 * Create separate tests for different packages Change-Id: Idb4da6817c9daad2a7420abc11bdaa702ae056dc * Fix lint errors Change-Id: I137c9e7e4574aee9c9fec22e91e19eee0e86a349 * Simplify chainlock message tests * Add more governor db test coverage * Next batch of review rework Change-Id: Ife54852fca6c6990d1ffb3d60a8dd7f49d526f0a * Still more rework Change-Id: I43a8aa7fa4e1a7cea4d7fde68c963123c1ca8d53 * More rework Change-Id: I9382412af4ffeda74967a834a6b0195a9d28b720 * Fix lint errors Change-Id: Idaafce9b0314192557b7207911375d000bac5ae2 * Add rest and prometheus support Change-Id: Ib870ed7eb305ef1ebbf6a7cedabc665c37c19171 * Add separate configs for testnet and devnet Change-Id: I76b11d8940a8dc9935b3f276a008ed20ef60b850 * Update mainnet tokens to fix decimals Change-Id: Iab018827766bc7748038b7be2f51342afb79b87c * Let small enqueued VAAs go out when big ones can't Change-Id: I7d3ef88d4579702d0c6ff4eaf5a8524799610ff6 * Tweak testnet config parameters Change-Id: Id2c54151a7183ab3fb4af8060929198f6021ba4e * Rework / enhancements from testnet testing Change-Id: I1387b1d22667fa6ffe0bb1832dbc0b31196505d3 * Use known emitter maps Change-Id: If330ee9d30ac3c2d1c6dca674f7777dc759de230 * Fix typo and out of date comments Change-Id: I54a19792104ccc6ca023020303a710ef3ba18f74 Co-authored-by: claudijd <jclaudius@jumptrading.com>
2022-07-19 11:08:06 -07:00
conn, c, err := getPublicRPCServiceClient(ctx, *clientSocketPath)
if err != nil {
log.Fatalf("failed to get publicrpc client: %v", err)
}
Chain governor (#1277) * Rebase * Reload from db on start up Change-Id: I1deac9db28ad1157ea7e0c84af41c35b38497f4e * Console commands Change-Id: Ic242038312b7c837443a2df8823f100b3cdffd77 * Query prices from CoinGecko Change-Id: I9a8c282ba374d32ef7045d11979a27ede3c52827 * Move chain config to separate file Change-Id: I6a790eca765bce1f2caf48134e225df5c4daff15 * More code cleanup Change-Id: Id12affa78cdc2d394d6dab0c53bb7ad06df8007e * Few minor tweaks Change-Id: I6cb511599d669e0b3d716d9f314ac0f26935ee92 * Create separate tests for different packages Change-Id: Idb4da6817c9daad2a7420abc11bdaa702ae056dc * Fix lint errors Change-Id: I137c9e7e4574aee9c9fec22e91e19eee0e86a349 * Simplify chainlock message tests * Add more governor db test coverage * Next batch of review rework Change-Id: Ife54852fca6c6990d1ffb3d60a8dd7f49d526f0a * Still more rework Change-Id: I43a8aa7fa4e1a7cea4d7fde68c963123c1ca8d53 * More rework Change-Id: I9382412af4ffeda74967a834a6b0195a9d28b720 * Fix lint errors Change-Id: Idaafce9b0314192557b7207911375d000bac5ae2 * Add rest and prometheus support Change-Id: Ib870ed7eb305ef1ebbf6a7cedabc665c37c19171 * Add separate configs for testnet and devnet Change-Id: I76b11d8940a8dc9935b3f276a008ed20ef60b850 * Update mainnet tokens to fix decimals Change-Id: Iab018827766bc7748038b7be2f51342afb79b87c * Let small enqueued VAAs go out when big ones can't Change-Id: I7d3ef88d4579702d0c6ff4eaf5a8524799610ff6 * Tweak testnet config parameters Change-Id: Id2c54151a7183ab3fb4af8060929198f6021ba4e * Rework / enhancements from testnet testing Change-Id: I1387b1d22667fa6ffe0bb1832dbc0b31196505d3 * Use known emitter maps Change-Id: If330ee9d30ac3c2d1c6dca674f7777dc759de230 * Fix typo and out of date comments Change-Id: I54a19792104ccc6ca023020303a710ef3ba18f74 Co-authored-by: claudijd <jclaudius@jumptrading.com>
2022-07-19 11:08:06 -07:00
defer conn.Close()
lastHeartbeats, err := c.GetLastHeartbeats(ctx, &publicrpcv1.GetLastHeartbeatsRequest{})
if err != nil {
log.Fatalf("failed to list nodes: %v", err)
}
gs, err := c.GetCurrentGuardianSet(ctx, &publicrpcv1.GetCurrentGuardianSetRequest{})
if err != nil {
log.Fatalf("failed to list current guardian get: %v", err)
}
log.Printf("current guardian set index: %d (%d guardians)",
gs.GuardianSet.Index, len(gs.GuardianSet.Addresses))
nodes := lastHeartbeats.Entries
sort.Slice(nodes, func(i, j int) bool {
if nodes[i].RawHeartbeat == nil || nodes[j].RawHeartbeat == nil {
return false
}
return nodes[i].RawHeartbeat.NodeName < nodes[j].RawHeartbeat.NodeName
})
log.Printf("%d nodes in guardian state set", len(nodes))
w := tabwriter.NewWriter(os.Stdout, 0, 8, 2, ' ', 0)
headers := []string{
"Node key",
"Guardian key",
"Node name",
"Version",
"Last seen",
}
if showDetails {
headers = append(headers, "Uptime")
}
type network struct {
string
vaa.ChainID
}
networks := []network{
{"Solana", vaa.ChainIDSolana},
{"Ethereum", vaa.ChainIDEthereum},
{"Terra", vaa.ChainIDTerra},
{"BSC", vaa.ChainIDBSC},
{"Polygon", vaa.ChainIDPolygon},
{"Avalanche", vaa.ChainIDAvalanche},
2022-04-29 12:56:08 -07:00
{"Algorand", vaa.ChainIDAlgorand},
{"Aptos", vaa.ChainIDAptos},
{"Sui", vaa.ChainIDSui},
{"Oasis", vaa.ChainIDOasis},
2022-04-09 05:06:10 -07:00
{"Aurora", vaa.ChainIDAurora},
{"Fantom", vaa.ChainIDFantom},
{"Karura", vaa.ChainIDKarura},
2022-06-02 09:18:44 -07:00
{"Acala", vaa.ChainIDAcala},
{"Klaytn", vaa.ChainIDKlaytn},
2022-05-12 09:12:40 -07:00
{"Celo", vaa.ChainIDCelo},
{"Near", vaa.ChainIDNear},
2022-06-22 07:29:21 -07:00
{"Terra2", vaa.ChainIDTerra2},
{"Pythnet", vaa.ChainIDPythNet},
{"Moonbeam", vaa.ChainIDMoonbeam},
{"Arbitrum", vaa.ChainIDArbitrum},
{"Optimism", vaa.ChainIDOptimism},
{"Xpla", vaa.ChainIDXpla},
{"Btc", vaa.ChainIDBtc},
{"Injective", vaa.ChainIDInjective},
{"Neon", vaa.ChainIDNeon},
{"Wormchain", vaa.ChainIDWormchain},
}
if len(only) > 0 {
var filtered []network
for _, network := range networks {
for _, name := range only {
if strings.EqualFold(network.string, name) {
filtered = append(filtered, network)
}
}
}
networks = filtered
}
for _, k := range networks {
headers = append(headers, k.string)
}
for _, header := range headers {
_, _ = fmt.Fprintf(w, "%s\t", header)
}
_, _ = fmt.Fprintln(w)
for _, h := range nodes {
if h.RawHeartbeat == nil {
continue
}
last := time.Unix(0, h.RawHeartbeat.Timestamp)
boot := time.Unix(0, h.RawHeartbeat.BootTimestamp)
heights := map[vaa.ChainID]int64{}
truncAddrs := make(map[vaa.ChainID]string)
errors := map[vaa.ChainID]uint64{}
for _, n := range h.RawHeartbeat.Networks {
heights[vaa.ChainID(n.Id)] = n.Height
errors[vaa.ChainID(n.Id)] = n.ErrorCount
if len(n.ContractAddress) >= 16 {
truncAddrs[vaa.ChainID(n.Id)] = n.ContractAddress[:16]
} else {
truncAddrs[vaa.ChainID(n.Id)] = "INVALID"
}
}
fields := []string{
h.P2PNodeAddr,
h.RawHeartbeat.GuardianAddr,
h.RawHeartbeat.NodeName,
h.RawHeartbeat.Version,
time.Since(last).String(),
}
if showDetails {
fields = append(fields, time.Since(boot).String())
}
for _, n := range networks {
if showDetails {
fields = append(fields, fmt.Sprintf("%s %d (%d)",
truncAddrs[n.ChainID], heights[n.ChainID], errors[n.ChainID]))
} else {
fields = append(fields, fmt.Sprintf("%d", heights[n.ChainID]))
}
}
for _, field := range fields {
_, _ = fmt.Fprintf(w, "%s\t", field)
}
_, _ = fmt.Fprintln(w)
}
w.Flush()
fmt.Print("\n")
for _, addr := range gs.GuardianSet.Addresses {
var found bool
for _, h := range nodes {
if h.VerifiedGuardianAddr == addr {
found = true
}
}
if !found {
fmt.Printf("Missing guardian: %s\n", addr)
}
}
fmt.Println("\n[do not parse - use the gRPC or REST API for scripting]")
}