func CLI() *cli.App {
	app := cli.NewApp()
	app.Name = "drand"
	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Fprintf(output, "drand %v (date %v, commit %v) by nikkolasg\n", version, buildDate, gitCommit)
	}
	app.ExitErrHandler = func(context *cli.Context, err error) {
	}
	app.Version = version
	app.Usage = "distributed randomness service"
	app.Commands = appCommands
	app.Flags = toArray(verboseFlag, folderFlag)
	app.Before = testWindows
	return app
}
CLI runs the drand app
package main
import (
	"bufio"
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	gonet "net"
	"github.com/BurntSushi/toml"
	"github.com/drand/drand/chain/boltdb"
	"github.com/drand/drand/core"
	"github.com/drand/drand/fs"
	"github.com/drand/drand/key"
	"github.com/drand/drand/log"
	"github.com/drand/drand/net"
	"github.com/drand/drand/protobuf/drand"
	"github.com/iotaledger/goshimmer/client"
	"github.com/urfave/cli/v2"
)
var output io.Writer = os.Stdout
var (
	version   = "master"
	gitCommit = "none"
	buildDate = "unknown"
)
const defaultPort = "8000"
func banner() {
	fmt.Fprintf(output, "drand %v (date %v, commit %v) by IOTA\n", version, buildDate, gitCommit)
}
var folderFlag = &cli.StringFlag{
	Name:  "folder",
	Value: core.DefaultConfigFolder(),
	Usage: "Folder to keep all drand cryptographic information, with absolute path.",
}
var verboseFlag = &cli.BoolFlag{
	Name:  "verbose",
	Usage: "If set, verbosity is at the debug level",
}
var tlsCertFlag = &cli.StringFlag{
	Name: "tls-cert",
	Usage: "Set the TLS certificate chain (in PEM format) for this drand node. " +
		"The certificates have to be specified as a list of whitespace-separated file paths. " +
		"This parameter is required by default and can only be omitted if the --tls-disable flag is used.",
}
var tlsKeyFlag = &cli.StringFlag{
	Name: "tls-key",
	Usage: "Set the TLS private key (in PEM format) for this drand node. " +
		"The key has to be specified as a file path. " +
		"This parameter is required by default and can only be omitted if the --tls-disable flag is used.",
}
var insecureFlag = &cli.BoolFlag{
	Name:  "tls-disable",
	Usage: "Disable TLS for all communications (not recommended).",
}
var controlFlag = &cli.StringFlag{
	Name:  "control",
	Usage: "Set the port you want to listen to for control port commands. If not specified, we will use the default port 8888.",
}
var metricsFlag = &cli.StringFlag{
	Name:  "metrics",
	Usage: "Launch a metrics server at the specified (host:)port.",
}
var privListenFlag = &cli.StringFlag{
	Name:  "private-listen",
	Usage: "Set the listening (binding) address of the private API. Useful if you have some kind of proxy.",
}
var pubListenFlag = &cli.StringFlag{
	Name:  "public-listen",
	Usage: "Set the listening (binding) address of the public API. Useful if you have some kind of proxy.",
}
var nodeFlag = &cli.StringFlag{
	Name:  "nodes",
	Usage: "Contact the nodes at the given list of whitespace-separated addresses which have to be present in group.toml.",
}
var roundFlag = &cli.IntFlag{
	Name: "round",
	Usage: "Request the public randomness generated at round num. If the drand beacon does not have the requested value," +
		" it returns an error. If not specified, the current randomness is returned.",
}
var certsDirFlag = &cli.StringFlag{
	Name:  "certs-dir",
	Usage: "directory containing trusted certificates (PEM format). Useful for testing and self signed certificates",
}
var outFlag = &cli.StringFlag{
	Name:  "out",
	Usage: "save the group file into a separate file instead of stdout",
}
var periodFlag = &cli.StringFlag{
	Name:  "period",
	Usage: "period to set when doing a setup",
}
var catchupPeriodFlag = &cli.StringFlag{
	Name:  "catchup-period",
	Usage: "Minimum period while in catchup. Set only by the leader of share / reshares",
	Value: "0s",
}
var thresholdFlag = &cli.IntFlag{
	Name:  "threshold",
	Usage: "threshold to use for the DKG",
}
var shareNodeFlag = &cli.IntFlag{
	Name:  "nodes",
	Usage: "number of nodes expected",
}
var transitionFlag = &cli.BoolFlag{
	Name: "transition",
	Usage: "When set, this flag indicates the share operation is a resharing. " +
		"The node will use the currently stored group as the basis for the resharing",
}
var forceFlag = &cli.BoolFlag{
	Name:  "force, f",
	Usage: "When set, this flag forces the daemon to start a new reshare operation." + "By default, it does not allow to restart one",
}
var secretFlag = &cli.StringFlag{
	Name:     "secret",
	EnvVars:  []string{"DRAND_SHARE_SECRET"},
	Required: true,
	Usage: "Specify the secret to use when doing the share so the leader knows you are an eligible potential participant." +
		" must be at least 32 characters.",
}
var connectFlag = &cli.StringFlag{
	Name:  "connect",
	Usage: "Address of the coordinator that will assemble the public keys and start the DKG",
}
var leaderFlag = &cli.BoolFlag{
	Name:  "leader",
	Usage: "Specify if this node should act as the leader for setting up the group",
}
var beaconOffset = &cli.IntFlag{
	Name: "beacon-delay",
	Usage: "Leader uses this flag to specify the genesis time or transition time as a delay from when " +
		" group is ready to run the share protocol",
}
var oldGroupFlag = &cli.StringFlag{
	Name: "from",
	Usage: "Old group.toml path to specify when a new node wishes to participate " +
		"in a resharing protocol. This flag is optional in case a node is already" +
		"included in the current DKG.",
}
var skipValidationFlag = &cli.BoolFlag{
	Name:  "skipValidation",
	Usage: "skips bls verification of beacon rounds for faster catchup.",
}
var timeoutFlag = &cli.StringFlag{
	Name:  "timeout",
	Usage: fmt.Sprintf("Timeout to use during the DKG, in string format. Default is %s", core.DefaultDKGTimeout),
}
var pushFlag = &cli.BoolFlag{
	Name: "push",
	Usage: "Push mode forces the daemon to start making beacon requests to the other node, " +
		"instead of waiting the other nodes contact it to catch-up on the round",
}
var sourceFlag = &cli.StringFlag{
	Name:  "source",
	Usage: "Source flag allows to provide an executable which output will be used as additional entropy during resharing step.",
}
var userEntropyOnlyFlag = &cli.BoolFlag{
	Name: "user-source-only",
	Usage: "user-source-only flag used with the source flag allows to only use the user's entropy to pick the dkg secret " +
		"(won't be mixed with crypto/rand). Should be used for reproducibility and debbuging purposes.",
}
var groupFlag = &cli.StringFlag{
	Name:  "group",
	Usage: "Test connections to nodes listed in the group",
}
var enablePrivateRand = &cli.BoolFlag{
	Name:  "private-rand",
	Usage: "Enables the private randomness feature on the daemon. By default, this feature is disabled.",
}
var hashOnly = &cli.BoolFlag{
	Name:  "hash",
	Usage: "Only print the hash of the group file",
}
var hashInfoFlag = &cli.StringFlag{
	Name:     "chain-hash",
	Usage:    "The hash of the chain info",
	Required: true,
}
var syncNodeFlag = &cli.StringFlag{
	Name:     "sync-nodes",
	Usage:    "<ADDRESS:PORT>,<...> of (multiple) reachable drand daemon(s)",
	Required: true,
}
var upToFlag = &cli.IntFlag{
	Name:  "up-to",
	Usage: "Specify a round to which the drand daemon will stop following the chain",
	Value: 0,
}
var appCommands = []*cli.Command{
	{
		Name:  "start",
		Usage: "Start the drand daemon.",
		Flags: toArray(folderFlag, tlsCertFlag, tlsKeyFlag,
			insecureFlag, controlFlag, privListenFlag, pubListenFlag, metricsFlag,
			certsDirFlag, pushFlag, verboseFlag, enablePrivateRand, oldGroupFlag, skipValidationFlag,
			goshimmerAPIurl, instanceID),
		Action: func(c *cli.Context) error {
			banner()
			return startCmd(c)
		},
	},
	{
		Name:  "stop",
		Usage: "Stop the drand daemon.\n",
		Flags: toArray(controlFlag),
		Action: func(c *cli.Context) error {
			banner()
			return stopDaemon(c)
		},
	},
	{
		Name:  "share",
		Usage: "Launch a sharing protocol.",
		Flags: toArray(insecureFlag, controlFlag, oldGroupFlag,
			timeoutFlag, sourceFlag, userEntropyOnlyFlag, secretFlag,
			periodFlag, shareNodeFlag, thresholdFlag, connectFlag, outFlag,
			leaderFlag, beaconOffset, transitionFlag, forceFlag, catchupPeriodFlag),
		Action: func(c *cli.Context) error {
			banner()
			return shareCmd(c)
		},
	},
	{
		Name:  "follow",
		Usage: "follow and store a randomness chain",
		Flags: toArray(folderFlag, controlFlag, hashInfoFlag, syncNodeFlag,
			tlsCertFlag, insecureFlag, upToFlag),
		Action: followCmd,
	},
	{
		Name: "generate-keypair",
		Usage: "Generate the longterm keypair (drand.private, drand.public)" +
			"for this node.\n",
		ArgsUsage: "<address> is the address other nodes will be able to contact this node on (specified as 'private-listen' to the daemon)",
		Flags:     toArray(folderFlag, insecureFlag),
		Action: func(c *cli.Context) error {
			banner()
			return keygenCmd(c)
		},
	},
	{
		Name: "get",
		Usage: "get allows for public information retrieval from a remote " +
			"drand node.\n",
		Subcommands: []*cli.Command{
			{
				Name: "private",
				Usage: "Get private randomness from the drand beacon as " +
					"specified in group.toml. Only one node is contacted by " +
					"default. Requests are ECIES-encrypted towards the public " +
					"key of the contacted node. This command attempts to connect " +
					"to the drand beacon via TLS and falls back to " +
					"plaintext communication if the contacted node has not " +
					"activated TLS in which case it prints a warning.\n",
				ArgsUsage: "<group.toml> provides the group informations of " +
					"the nodes that we are trying to contact.",
				Flags:  toArray(insecureFlag, tlsCertFlag, nodeFlag),
				Action: getPrivateCmd,
			},
			{
				Name: "public",
				Usage: "Get the latest public randomness from the drand " +
					"beacon and verify it against the collective public key " +
					"as specified in group.toml. Only one node is contacted by " +
					"default. This command attempts to connect to the drand " +
					"beacon via TLS and falls back to plaintext communication " +
					"if the contacted node has not activated TLS in which case " +
					"it prints a warning.\n",
				Flags:  toArray(tlsCertFlag, insecureFlag, roundFlag, nodeFlag),
				Action: getPublicRandomness,
			},
			{
				Name:      "chain-info",
				Usage:     "Get the binding chain information that this nodes participates to",
				ArgsUsage: "`ADDRESS1` `ADDRESS2` ... provides the addresses of the node to try to contact to.",
				Flags:     toArray(tlsCertFlag, insecureFlag, hashOnly),
				Action:    getChainInfo,
			},
		},
	},
	{
		Name:  "util",
		Usage: "Multiple commands of utility functions, such as reseting a state, checking the connection of a peer...",
		Subcommands: []*cli.Command{
			{
				Name: "check",
				Usage: "Check node at the given `ADDRESS` (you can put multiple ones)" +
					" in the group for accessibility over the gRPC communication. If the node " +
					" is not running behind TLS, you need to pass the tls-disable flag. You can " +
					"also check a whole group's connectivity with the group flag.",
				Flags:  toArray(groupFlag, certsDirFlag, insecureFlag, verboseFlag),
				Action: checkConnection,
			},
			{
				Name:   "ping",
				Usage:  "pings the daemon checking its state\n",
				Flags:  toArray(controlFlag),
				Action: pingpongCmd,
			},
			{
				Name:   "reset",
				Usage:  "Resets the local distributed information (share, group file and random beacons). It KEEPS the private/public key pair.",
				Flags:  toArray(folderFlag, controlFlag),
				Action: resetCmd,
			},
			{
				Name: "del-beacon",
				Usage: "Delete all beacons from the given `ROUND` number until the head of the chain. " +
					" You MUST restart the daemon after that command.",
				Flags:  toArray(folderFlag),
				Action: deleteBeaconCmd,
			},
			{
				Name:   "self-sign",
				Usage:  "Signs the public identity of this node. Needed for backward compatibility with previous versions.",
				Flags:  toArray(folderFlag),
				Action: selfSign,
			},
		},
	},
	{
		Name: "show",
		Usage: "local information retrieval about the node's cryptographic " +
			"material. Show prints the information about the collective " +
			"public key (drand.cokey), the group details (group.toml), the " +
			"long-term private key (drand.private), the long-term public key " +
			"(drand.public), or the private key share (drand.share), " +
			"respectively.\n",
		Flags: toArray(folderFlag, controlFlag),
		Subcommands: []*cli.Command{
			{
				Name:   "share",
				Usage:  "shows the private share\n",
				Flags:  toArray(controlFlag),
				Action: showShareCmd,
			},
			{
				Name: "group",
				Usage: "shows the current group.toml used. The group.toml " +
					"may contain the distributed public key if the DKG has been " +
					"ran already.\n",
				Flags:  toArray(outFlag, controlFlag, hashOnly),
				Action: showGroupCmd,
			},
			{
				Name:   "chain-info",
				Usage:  "shows the chain information this node is participating to",
				Flags:  toArray(controlFlag, hashOnly),
				Action: showChainInfo,
			},
			{
				Name:   "private",
				Usage:  "shows the long-term private key of a node.\n",
				Flags:  toArray(controlFlag),
				Action: showPrivateCmd,
			},
			{
				Name:   "public",
				Usage:  "shows the long-term public key of a node.\n",
				Flags:  toArray(controlFlag),
				Action: showPublicCmd,
			},
		},
	},
}