package cmd import ( "fmt" "os" "time" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/services/omnirpc/modules/confirmedtofinalized" "github.com/synapsecns/sanguine/services/omnirpc/modules/harmonyproxy" "github.com/synapsecns/sanguine/services/omnirpc/modules/receiptsbackup" "github.com/phayes/freeport" "github.com/synapsecns/sanguine/core" rpcConfig "github.com/synapsecns/sanguine/services/omnirpc/config" "github.com/synapsecns/sanguine/services/omnirpc/debug" "github.com/synapsecns/sanguine/services/omnirpc/proxy" "github.com/synapsecns/sanguine/services/omnirpc/rpcinfo" "github.com/urfave/cli/v2" ) var latencyCommand = &cli.Command{ Name: "check-latency", Usage: "checks latency for all rpc endpoints known for a chain id", Flags: []cli.Flag{chainIDFlag}, Action: func(c *cli.Context) error { rConfig, err := rpcConfig.GetPublicRPCConfig() if err != nil { return fmt.Errorf("could not get rpc map: %w", err) } chainConfig, ok := rConfig.Chains[uint32(c.Int(chainIDFlag.Name))] if !ok { return fmt.Errorf("could not get chain config for chain %d", c.Int(chainIDFlag.Name)) } res := rpcinfo.GetRPCLatency(c.Context, time.Second*5, chainConfig.RPCs, metrics.Get()) DisplayLatency(res) return nil }, } var chainListCommand = &cli.Command{ Name: "chainlist-server", Usage: "runs a chainlist proxy server", Flags: []cli.Flag{portFlag}, Action: func(c *cli.Context) error { // Create a large heap allocation of 10 GiB // See: https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i-learnt-to-stop-worrying-and-love-the-heap/ _ = make([]byte, 10<<30) rConfig, err := rpcConfig.GetPublicRPCConfig() if err != nil { return fmt.Errorf("could not get rpc map: %w", err) } if c.Int(portFlag.Name) != 0 { rConfig.Port = uint16(c.Int(portFlag.Name)) } if rConfig.Port == 0 { rConfig.Port = uint16(freeport.GetPort()) } server := proxy.NewProxy(rConfig, metrics.Get()) server.Run(c.Context) return nil }, } var publicConfigCommand = &cli.Command{ Name: "public-config", Usage: "output a public config file from chainlist.org", Flags: []cli.Flag{outputFlag}, Action: func(c *cli.Context) error { rConfig, err := rpcConfig.GetPublicRPCConfig() if err != nil { return fmt.Errorf("could not get rpc map: %w", err) } output, err := rConfig.Marshall() if err != nil { return fmt.Errorf("could not get rpc map: %w", err) } outputConfig, err := os.Create(core.ExpandOrReturnPath(c.String(outputFlag.Name))) if err != nil { return fmt.Errorf("could not create config file: %w", err) } defer func() { _ = outputConfig.Close() }() _, err = outputConfig.Write(output) if err != nil { return fmt.Errorf("could not write to file: %w", err) } fmt.Printf("written to %s \n", c.String(outputFlag.Name)) return nil }, } var serverCommand = &cli.Command{ Name: "server", Usage: "run a server from a config", Flags: []cli.Flag{ configFlag, portFlag, }, Action: func(c *cli.Context) error { // Create a large heap allocation of 10 GiB // See: https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i-learnt-to-stop-worrying-and-love-the-heap/ _ = make([]byte, 10<<30) fileContents, err := os.ReadFile(core.ExpandOrReturnPath(c.String(configFlag.Name))) if err != nil { return fmt.Errorf("could not read file %s: %w", c.String(configFlag.Name), err) } rConfig, err := rpcConfig.UnmarshallConfig(fileContents) if err != nil { return fmt.Errorf("could not unmarshall config: %w", err) } if c.Int(portFlag.Name) != 0 { rConfig.Port = uint16(c.Int(portFlag.Name)) } if rConfig.Port == 0 { rConfig.Port = uint16(freeport.GetPort()) } server := proxy.NewProxy(rConfig, metrics.Get()) server.Run(c.Context) return nil }, } var debugResponse = &cli.Command{ Name: "debug-response", Usage: "used for debugging responses and finding diff between rpcs", Flags: []cli.Flag{ fileFlag, }, Action: func(c *cli.Context) error { diffFile, err := os.ReadFile(c.String(fileFlag.Name)) if err != nil { return fmt.Errorf("could not read file: %w", err) } //nolint:wrapcheck return debug.HashDiff(diffFile) }, } // latestRewrite rewrites latest block numbers for a single rpc url. var latestRewrite = &cli.Command{ Name: "latest-rewrite", Usage: "A simple rpc proxy for one-off integration tests. Rewrites block queries that use \"latest\" to \"finalized\"", Flags: []cli.Flag{ rpcFlag, portFlag, maxSubmitAhead, chainIDFlag, }, Action: func(c *cli.Context) error { simpleProxy := confirmedtofinalized.NewProxy(c.String(rpcFlag.Name), metrics.Get(), c.Int(portFlag.Name), c.Int(maxSubmitAhead.Name), c.Int(chainIDFlag.Name)) err := simpleProxy.Run(c.Context) if err != nil { return fmt.Errorf("return err: %w", err) } return nil }, } var harmonyProxy = &cli.Command{ Name: "harmony-confirm", Usage: "An experimental harmony confirmation client", Flags: []cli.Flag{ rpcFlag, portFlag, }, Action: func(c *cli.Context) error { simpleProxy := harmonyproxy.NewHarmonyProxy(c.String(rpcFlag.Name), metrics.Get(), c.Int(portFlag.Name)) err := simpleProxy.Run(c.Context) if err != nil { return fmt.Errorf("return err: %w", err) } return nil }, } var receiptsProxy = &cli.Command{ Name: "receipts-backup", Usage: "A rpc proxy for using backup RPC with hanging receipt requests", Flags: []cli.Flag{ rpcFlag, backupRPCFlag, portFlag, chainIDFlag, recieptsTimeoutFlag, }, Action: func(c *cli.Context) error { simpleProxy := receiptsbackup.NewProxy(c.String(rpcFlag.Name), c.String(backupRPCFlag.Name), c.Duration(recieptsTimeoutFlag.Name), metrics.Get(), c.Int(portFlag.Name), c.Int(chainIDFlag.Name)) err := simpleProxy.Run(c.Context) if err != nil { return fmt.Errorf("return err: %w", err) } return nil }, }