Skip to content

Commit

Permalink
feat(gnodev): add balances & keybase support (#1938)
Browse files Browse the repository at this point in the history
  • Loading branch information
gfanton authored Apr 25, 2024
1 parent 06e8783 commit cc207f8
Show file tree
Hide file tree
Showing 30 changed files with 1,627 additions and 756 deletions.
11 changes: 8 additions & 3 deletions contribs/gnodev/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
GNOROOT_DIR ?= $(abspath $(lastword $(MAKEFILE_LIST))/../../../)
GOBUILD_FLAGS ?= -ldflags "-X github.com/gnolang/gno/gnovm/pkg/gnoenv._GNOROOT=$(GNOROOT_DIR)"

GOBUILD_FLAGS := -ldflags "-X github.com/gnolang/gno/gnovm/pkg/gnoenv._GNOROOT=$(GNOROOT_DIR)"
rundep := go run -modfile ../../misc/devdeps/go.mod
golangci_lint := $(rundep) github.com/golangci/golangci-lint/cmd/golangci-lint

install:
go install $(GOBUILD_FLAGS) .
go install $(GOBUILD_FLAGS) ./cmd/gnodev

build:
go build $(GOBUILD_FLAGS) -o build/gnodev ./cmd/gno
go build $(GOBUILD_FLAGS) -o build/gnodev ./cmd/gnodev

lint:
$(golangci_lint) --config ../../.github/golangci.yml run ./...
148 changes: 148 additions & 0 deletions contribs/gnodev/cmd/gnodev/accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package main

import (
"fmt"
"log/slog"
"os"
"strings"
"text/tabwriter"

"github.com/gnolang/gno/contribs/gnodev/pkg/address"
"github.com/gnolang/gno/contribs/gnodev/pkg/dev"
"github.com/gnolang/gno/gno.land/pkg/gnoland"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/bft/rpc/client"
"github.com/gnolang/gno/tm2/pkg/std"
)

type varPremineAccounts map[string]std.Coins // name or bech32 to coins.

func (va *varPremineAccounts) Set(value string) error {
if *va == nil {
*va = map[string]std.Coins{}
}
accounts := *va

user, amount, found := strings.Cut(value, "=")
accounts[user] = nil
if !found {
return nil
}

coins, err := std.ParseCoins(amount)
if err != nil {
return fmt.Errorf("unable to parse coins from %q: %w", user, err)
}

// Add the parsed amount to the user.
accounts[user] = coins
return nil
}

func (va varPremineAccounts) String() string {
accs := make([]string, 0, len(va))
for user, balance := range va {
accs = append(accs, fmt.Sprintf("%s(%s)", user, balance.String()))
}

return strings.Join(accs, ",")
}

func generateBalances(bk *address.Book, cfg *devCfg) (gnoland.Balances, error) {
bls := gnoland.NewBalances()
premineBalance := std.Coins{std.NewCoin("ugnot", 10e12)}

entries := bk.List()

// Automatically set every key from keybase to unlimited fund.
for _, entry := range entries {
address := entry.Address

// Check if a predefined amount has been set for this key.

// Check for address
if preDefinedFound, ok := cfg.premineAccounts[address.String()]; ok && preDefinedFound != nil {
bls[address] = gnoland.Balance{Amount: preDefinedFound, Address: address}
continue
}

// Check for name
found := premineBalance
for _, name := range entry.Names {
if preDefinedFound, ok := cfg.premineAccounts[name]; ok && preDefinedFound != nil {
found = preDefinedFound
break
}
}

bls[address] = gnoland.Balance{Amount: found, Address: address}
}

if cfg.balancesFile == "" {
return bls, nil
}

// Load balance file

file, err := os.Open(cfg.balancesFile)
if err != nil {
return nil, fmt.Errorf("unable to open balance file %q: %w", cfg.balancesFile, err)
}

blsFile, err := gnoland.GetBalancesFromSheet(file)
if err != nil {
return nil, fmt.Errorf("unable to read balances file %q: %w", cfg.balancesFile, err)
}

// Add balance address to AddressBook
for addr := range blsFile {
bk.Add(addr, "")
}

// Left merge keybase balance into loaded file balance.
// TL;DR: balance file override every balance at the end
blsFile.LeftMerge(bls)
return blsFile, nil
}

func logAccounts(logger *slog.Logger, book *address.Book, _ *dev.Node) error {
var tab strings.Builder
tabw := tabwriter.NewWriter(&tab, 0, 0, 2, ' ', tabwriter.TabIndent)

entries := book.List()

fmt.Fprintln(tabw, "KeyName\tAddress\tBalance") // Table header.

for _, entry := range entries {
address := entry.Address.String()
qres, err := client.NewLocal().ABCIQuery("auth/accounts/"+address, []byte{})
if err != nil {
return fmt.Errorf("unable to query account %q: %w", address, err)
}

var qret struct{ BaseAccount std.BaseAccount }
if err = amino.UnmarshalJSON(qres.Response.Data, &qret); err != nil {
return fmt.Errorf("unable to unmarshal query response: %w", err)
}

if len(entry.Names) == 0 {
// Insert row with name, address, and balance amount.
fmt.Fprintf(tabw, "%s\t%s\t%s\n", "_", address, qret.BaseAccount.GetCoins().String())
continue
}

for _, name := range entry.Names {
// Insert row with name, address, and balance amount.
fmt.Fprintf(tabw, "%s\t%s\t%s\n", name,
address,
qret.BaseAccount.GetCoins().String())
}
}

// Flush table.
tabw.Flush()

headline := fmt.Sprintf("(%d) known keys", len(entries))
logger.Info(headline, "table", tab.String())
return nil
}
35 changes: 35 additions & 0 deletions contribs/gnodev/cmd/gnodev/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"io"
"log/slog"

"github.com/charmbracelet/lipgloss"
"github.com/gnolang/gno/contribs/gnodev/pkg/logger"
gnolog "github.com/gnolang/gno/gno.land/pkg/log"
"github.com/muesli/termenv"
)

func setuplogger(cfg *devCfg, out io.Writer) *slog.Logger {
level := slog.LevelInfo
if cfg.verbose {
level = slog.LevelDebug
}

if cfg.serverMode {
zaplogger := logger.NewZapLogger(out, level)
return gnolog.ZapLoggerToSlog(zaplogger)
}

// Detect term color profile
colorProfile := termenv.DefaultOutput().Profile
clogger := logger.NewColumnLogger(out, level, colorProfile)

// Register well known group color with system colors
clogger.RegisterGroupColor(NodeLogName, lipgloss.Color("3"))
clogger.RegisterGroupColor(WebLogName, lipgloss.Color("4"))
clogger.RegisterGroupColor(KeyPressLogName, lipgloss.Color("5"))
clogger.RegisterGroupColor(EventServerLogName, lipgloss.Color("6"))

return slog.New(clogger)
}
Loading

0 comments on commit cc207f8

Please sign in to comment.