Skip to content

Commit

Permalink
docs: add basic documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
PhearZero committed Dec 17, 2024
1 parent f1be0a2 commit 2d48fed
Show file tree
Hide file tree
Showing 57 changed files with 395 additions and 206 deletions.
27 changes: 21 additions & 6 deletions cmd/node/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,30 @@ import (
"os/exec"
)

// DebugInfo represents diagnostic information about
// the Algod service, path availability, and related metadata.
type DebugInfo struct {
InPath bool `json:"inPath"`
IsRunning bool `json:"isRunning"`
IsService bool `json:"isService"`
IsInstalled bool `json:"isInstalled"`
Algod string `json:"algod"`
Data []string `json:"data"`

// InPath indicates whether the `algod` command-line tool is available in the system's executable path.
InPath bool `json:"inPath"`

// IsRunning indicates whether the `algod` process is currently running on the host system, returning true if active.
IsRunning bool `json:"isRunning"`

// IsService indicates whether the Algorand software is configured as a system service on the current operating system.
IsService bool `json:"isService"`

// IsInstalled indicates whether the Algorand software is installed on the system by checking its presence and configuration.
IsInstalled bool `json:"isInstalled"`

// Algod holds the path to the `algod` executable if found on the system, or an empty string if not found.
Algod string `json:"algod"`

// Data contains a list of string entries providing additional paths or diagnostic information about the `algod` service.
Data []string `json:"data"`
}

// debugCmd defines the "debug" command used to display diagnostic information for developers, including debug data.
var debugCmd = &cobra.Command{
Use: "debug",
Short: "Display debug information for developers",
Expand Down
4 changes: 4 additions & 0 deletions cmd/node/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import (
"time"
)

// InstallMsg is a constant string used to indicate the start of the Algorand installation process with a specific message.
const InstallMsg = "Installing Algorand"

// InstallExistsMsg is a constant string used to indicate that the Algod is already installed on the system.
const InstallExistsMsg = "algod is already installed"

// installCmd is a Cobra command that installs the Algorand daemon on the local machine, ensuring the service is operational.
var installCmd = &cobra.Command{
Use: "install",
Short: "Install the algorand daemon",
Expand Down
19 changes: 16 additions & 3 deletions cmd/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,32 @@ import (
"github.com/spf13/cobra"
)

// SudoWarningMsg is a constant string displayed to warn users that they may be prompted for their password during execution.
const SudoWarningMsg = "(You may be prompted for your password)"

// PermissionErrorMsg is a constant string that indicates a command requires super-user privileges (sudo) to be executed.
const PermissionErrorMsg = "this command must be run with super-user privileges (sudo)"

// NotInstalledErrorMsg is the error message displayed when the algod software is not installed on the system.
const NotInstalledErrorMsg = "algod is not installed. please run the *node install* command"

// RunningErrorMsg represents the error message displayed when algod is running and needs to be stopped before proceeding.
const RunningErrorMsg = "algod is running, please run the *node stop* command"

// NotRunningErrorMsg is the error message displayed when the algod service is not currently running on the system.
const NotRunningErrorMsg = "algod is not running"

var (
force bool = false
)
// force indicates whether actions should be performed forcefully, bypassing checks or confirmations.
var force bool = false

// Cmd represents the root command for managing an Algorand node, providing subcommands for installation, control, and upgrades.
var Cmd = &cobra.Command{
Use: "node",
Short: "Node Management",
Long: style.Purple(style.BANNER) + "\n" + style.LightBlue("Manage your Algorand node"),
}

// NeedsToBeRunning ensures the Algod software is installed and running before executing the associated Cobra command.
func NeedsToBeRunning(cmd *cobra.Command, args []string) {
if force {
return
Expand All @@ -34,6 +45,7 @@ func NeedsToBeRunning(cmd *cobra.Command, args []string) {
}
}

// NeedsToBeStopped ensures the operation halts if Algod is not installed or is currently running, unless forced.
func NeedsToBeStopped(cmd *cobra.Command, args []string) {
if force {
return
Expand All @@ -46,6 +58,7 @@ func NeedsToBeStopped(cmd *cobra.Command, args []string) {
}
}

// init initializes the root command by adding subcommands for managing the Algorand node, such as install, start, stop, etc.
func init() {
Cmd.AddCommand(installCmd)
Cmd.AddCommand(startCmd)
Expand Down
2 changes: 2 additions & 0 deletions cmd/node/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"
)

// startCmd is a Cobra command used to start the Algod service on the system, ensuring necessary checks are performed beforehand.
var startCmd = &cobra.Command{
Use: "start",
Short: "Start Algod",
Expand All @@ -25,6 +26,7 @@ var startCmd = &cobra.Command{
},
}

// init initializes the `force` flag for the `start` command, allowing the node to start forcefully when specified.
func init() {
startCmd.Flags().BoolVarP(&force, "force", "f", false, style.Yellow.Render("forcefully start the node"))
}
21 changes: 13 additions & 8 deletions cmd/node/stop.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package node

import (
"fmt"
"github.com/algorandfoundation/algorun-tui/internal/algod"
"github.com/algorandfoundation/algorun-tui/ui/style"
"github.com/charmbracelet/log"
Expand All @@ -10,8 +9,15 @@ import (
"github.com/spf13/cobra"
)

// StopTimeout defines the duration to wait after attempting to stop the Algod process to ensure it has fully shut down.
const StopTimeout = 5 * time.Second
const StopSuccessMsg = "Algod stopped successfully"

const StoppingAlgodMsg = "Stopping Algod 😢"

// StopSuccessMsg is a constant string message indicating that Algod has been stopped successfully.
const StopSuccessMsg = "Algorand stopped successfully 🎉"

// StopFailureMsg is a constant string used as an error message when the Algod process fails to stop.
const StopFailureMsg = "failed to stop Algod"

var stopCmd = &cobra.Command{
Expand All @@ -20,23 +26,22 @@ var stopCmd = &cobra.Command{
Long: "Stop the Algod process on your system.",
SilenceUsage: true,
PersistentPreRun: NeedsToBeRunning,
RunE: func(cmd *cobra.Command, args []string) error {
log.Info(style.Green.Render("Stopping Algod 😢"))
Run: func(cmd *cobra.Command, args []string) {
log.Info(style.Green.Render(StoppingAlgodMsg))
// Warn user for prompt
log.Warn(style.Yellow.Render(SudoWarningMsg))

err := algod.Stop()
if err != nil {
return fmt.Errorf(StopFailureMsg)
log.Fatal(StopFailureMsg)
}
time.Sleep(StopTimeout)

if algod.IsRunning() {
return fmt.Errorf(StopFailureMsg)
log.Fatal(StopFailureMsg)
}

log.Info(style.Green.Render("Algorand stopped successfully 🎉"))
return nil
log.Info(style.Green.Render(StopSuccessMsg))
},
}

Expand Down
19 changes: 14 additions & 5 deletions cmd/node/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,43 @@ import (
"github.com/spf13/viper"
)

// syncEndpoint is a string variable used to store the algod API endpoint address for communication with the node.
var syncEndpoint string

// syncToken is a string flag used to store the admin token required for authenticating with the Algod API.
var syncToken string

// defaultLag represents the default minimum catchup delay in milliseconds for the Fast Catchup process.
var defaultLag int = 30_000

// syncCmd is a Cobra command used to check the node's sync status and initiate a fast catchup when necessary.
var syncCmd = utils.WithAlgodFlags(&cobra.Command{
Use: "sync",
Short: "Fast Catchup",
Long: "Checks if the node is caught up and if not, starts catching up.",
SilenceUsage: true,
PersistentPreRun: NeedsToBeRunning,
Run: func(cmd *cobra.Command, args []string) {
// Load configuration
err := utils.InitConfig()
if err != nil {
log.Fatal(err)
}
ep := viper.GetString("algod-endpoint")
t := viper.GetString("algod-token")
if ep == "" {

endpoint := viper.GetString("algod-endpoint")
token := viper.GetString("algod-token")
if endpoint == "" {
log.Fatal("algod-endpoint is required")
}
if t == "" {
if token == "" {
log.Fatal("algod-token is required")
}
// TODO: Perf testing as a dedicated cmd (node perf catchup with exit 0 or 1)
// NOTE: we do not want to pollute this command with perf testing
// just allow it to post it's minimum requirements and preform a fast catchup if necessary.
ctx := context.Background()
httpPkg := new(api.HttpPkg)
client, err := algod.GetClient(viper.GetString("algod-endpoint"), viper.GetString("algod-token"))
client, err := algod.GetClient(endpoint, token)
cobra.CheckErr(err)

status, _, err := algod.NewStatus(ctx, client, httpPkg)
Expand Down
3 changes: 3 additions & 0 deletions cmd/node/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"github.com/spf13/cobra"
)

// UninstallWarningMsg provides a warning message to inform users they may be prompted for their password during uninstallation.
const UninstallWarningMsg = "(You may be prompted for your password to uninstall)"

// uninstallCmd defines a Cobra command used to uninstall the Algorand node (Algod) and related binaries from the system.
var uninstallCmd = &cobra.Command{
Use: "uninstall",
Short: "Uninstall Algorand node (Algod)",
Expand All @@ -29,6 +31,7 @@ var uninstallCmd = &cobra.Command{
},
}

// init initializes the uninstall command's flags, including the "force" flag for forced uninstallation.
func init() {
uninstallCmd.Flags().BoolVarP(&force, "force", "f", false, style.Yellow.Render("forcefully uninstall the node"))
}
2 changes: 2 additions & 0 deletions cmd/node/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import (
"time"
)

// UpgradeMsg is a constant string used to indicate the start of the Algod upgrade process.
const UpgradeMsg = "Upgrading Algod"

// upgradeCmd is a Cobra command used to upgrade Algod, utilizing the OS-specific package manager if applicable.
var upgradeCmd = &cobra.Command{
Use: "upgrade",
Short: "Upgrade Algod",
Expand Down
7 changes: 7 additions & 0 deletions cmd/utils/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"strings"
)

// InitConfig initializes and loads the application's configuration from multiple sources,
// including environment variables and files.
func InitConfig() error {
// Find home directory.
home, err := os.UserHomeDir()
Expand Down Expand Up @@ -63,6 +65,8 @@ type DaemonConfig struct {
Token string `json:"token"`
}

// MergeAlgorandData loads and merges Algorand configuration data either from environment settings or provided parameters.
// It reads the configuration from the `ALGORAND_DATA` directory if available or uses the provided endpoint and token.
func MergeAlgorandData(endpoint string, token string) (DaemonConfig, error) {
result := DaemonConfig{
DataDirectoryPath: "",
Expand Down Expand Up @@ -149,12 +153,15 @@ func MergeAlgorandData(endpoint string, token string) (DaemonConfig, error) {
return result, nil
}

// replaceEndpointUrl replaces newline characters and wildcard IP addresses in a URL with a specific local address.
func replaceEndpointUrl(s string) string {
s = strings.Replace(s, "\n", "", 1)
s = strings.Replace(s, "0.0.0.0", "127.0.0.1", 1)
s = strings.Replace(s, "[::]", "127.0.0.1", 1)
return s
}

// hasWildcardEndpointUrl checks if the given string contains wildcard IP addresses ("0.0.0.0" or "::").
func hasWildcardEndpointUrl(s string) bool {
return strings.Contains(s, "0.0.0.0") || strings.Contains(s, "::")
}
5 changes: 5 additions & 0 deletions cmd/utils/explanations/explanations.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/charmbracelet/lipgloss"
)

// NodeNotFound is a styled message explaining that the node could not be automatically found and describes how to configure it.
var NodeNotFound = lipgloss.NewStyle().
PaddingTop(1).
PaddingBottom(1).
Expand All @@ -21,8 +22,12 @@ var NodeNotFound = lipgloss.NewStyle().
" environment variable to the algod data directory, ",
style.Bold("e.g. /var/lib/algorand"),
))

// Unreachable is an error message indicating inability to connect to algod, suggesting to verify algod is running and configured.
var Unreachable = "\n\nExplanation: Could not reach algod. Check that algod is running and the provided connection arguments.\n"

// TokenInvalid provides an error message indicating the administrative token for algod is invalid or missing.
var TokenInvalid = "\n\nExplanation: algod token is invalid. Algorun requires the " + style.BoldUnderline("admin token") + " for algod. You can find this in the algod.admin.token file in the algod data directory.\n"

// TokenNotAdmin is an explanatory message shown when the provided token lacks admin privileges for the algod node.
var TokenNotAdmin = "\n\nExplanation: algorun requires the " + style.BoldUnderline("admin token") + " for algod. You can find this in the algod.admin.token file in the algod data directory.\n"
1 change: 1 addition & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/spf13/viper"
)

// WithAlgodFlags enhances a cobra.Command with flags for Algod endpoint and token configuration.
func WithAlgodFlags(cmd *cobra.Command, algodEndpoint *string, token *string) *cobra.Command {
cmd.Flags().StringVarP(algodEndpoint, "algod-endpoint", "a", "", style.LightBlue("algod endpoint address URI, including http[s]"))
cmd.Flags().StringVarP(token, "algod-token", "t", "", lipgloss.JoinHorizontal(
Expand Down
8 changes: 8 additions & 0 deletions internal/algod/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ func ParticipationKeysToAccounts(keys []api.ParticipationKey) map[string]Account
return accounts
}

// Merge updates the Account instance with data from the provided api.Account and returns the updated Account.
// It updates fields such as Status, Balance, Participation, and IncentiveEligible based on the rpcAccount values.
func (a Account) Merge(rpcAccount api.Account) Account {
a.Status = rpcAccount.Status
a.Balance = rpcAccount.Amount / 1000000
Expand All @@ -111,13 +113,18 @@ func (a Account) Merge(rpcAccount api.Account) Account {
return a
}

// GetExpiresTime calculates the expiration time of the account's participation key based on round differences and duration.
// Returns nil if the account has no participation or if the expiration time cannot be determined.
func (a Account) GetExpiresTime(t system.Time, lastRound int, roundTime time.Duration) *time.Time {
if a.Participation == nil {
return nil
}
return utils.GetExpiresTime(t, lastRound, roundTime, a.Participation.VoteLastValid)
}

// UpdateExpiredTime updates the account's expiration time and identifies if the account has a non-resident participation key.
// It checks if the account is offline or if its local participation key matches one of the provided keys.
// The method recalculates the expiration time based on the last round and round duration.
func (a Account) UpdateExpiredTime(t system.Time, keys []api.ParticipationKey, lastRound int, roundTime time.Duration) Account {
var nonResidentKey = true
for _, key := range keys {
Expand All @@ -131,6 +138,7 @@ func (a Account) UpdateExpiredTime(t system.Time, keys []api.ParticipationKey, l
return a
}

// ValidateAddress checks the validity of an Algorand address by decoding it. Returns true for valid addresses, false otherwise.
func ValidateAddress(address string) bool {
_, err := types.DecodeAddress(address)
if err != nil {
Expand Down
Loading

0 comments on commit 2d48fed

Please sign in to comment.