Skip to content
Snippets Groups Projects
bfa_client.go 5.06 KiB
Newer Older
package main

import (
	"../bfa"
	"../util"
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"sort"
	"strconv"
	"strings"
)

const (
	DefaultURL = "http://localhost:8545"
	latest = -1
type Node = bfa.Node

var (
	url         string
	json        bool
	help        bool
	flags       flag.FlagSet
	command     string
	description string
)

func setFlags() {
	flags.BoolVar(&json, "json", false, "Produce salida en formato json")
	flags.StringVar(&url, "url", "", "URL para conexión con geth. Ejemplo: '/home/bfa/bfa/network/node/geth.ipc' o 'http://localhost:8545'")
	flags.BoolVar(&help, "h", false, "")
	flags.BoolVar(&help, "help", false, "Muestra esta ayuda")
}

func updateURL(url string) (updated string) {
	const (
		defaultIPC  = "/home/bfa/bfa/network/node/geth.ipc"
		defaultHTTP = "http://localhost:8545"
	)
	if url != "" { // We accept the user selected URL
		return
	}
	// First, we try IPC
	updated = defaultIPC
	if bfaNetworkDir := os.Getenv("BFANETWORKDIR"); bfaNetworkDir != "" {
		updated = bfaNetworkDir + "/node/get.ipc"
	}
	if fileInfo, err := os.Stat(updated); err == nil && (fileInfo.Mode()&os.ModeSocket) != 0 {
		return
	}
	updated = defaultHTTP
	return
}

func usage(errorCode int) {
	fmt.Fprintf(os.Stderr, "Uso: %v %v [opciones]\n%v\n", os.Args[0], command, description)
	flags.PrintDefaults()
	os.Exit(errorCode)
}

func parseFlags() {
	flags.Parse(os.Args[2:])
	if help {
		usage(0)
	}
}

func proposals() {
	var blockNumber int64
	description = "Detalla el estado de las votaciones en curso"
	setFlags()
	flags.Int64Var(&blockNumber, "block-number", -1, "Número del bloque en el cual se quiere conocer el estado de la propuesta (-1 para el último)")
	parseFlags()
	url = updateURL(url)
	node, err := bfa.Dial(url)
	util.Check(err)
	defer node.Close()
	votes := node.GetVotes(blockNumber)
	if json {
		util.PrintJson(votes)
		return
	}
	fmt.Printf("Bloque: %d\nPropuestas en curso: %d\n", votes.BlockNumber, len(votes.Proposals))
	for _, proposal := range votes.Proposals {
		fmt.Printf("Propuesta: %v\n", proposal)
		for _, signer := range votes.Signers {
			b := votes.Votes[proposal][signer]
			var v string
			if b == nil {
				v = ""
			} else {
				v = strconv.FormatBool(*b)
			}
			fmt.Printf("\t%v: %v\n", signer, v)
		}
		tally := votes.Tally[proposal]
		fmt.Printf("A favor: %v, en contra: %v, no votaron: %v\n", tally.True, tally.False, tally.Null)
	}
}

func sealers() {
	var (
		blockNumber int64
		status      bool
	)
	description = "Presenta la lista de selladores. Opcionalmente indica el último bloque sellado por cada uno."
	setFlags()
	flags.Int64Var(&blockNumber, "block-number", -1, "Número del bloque en el cual se quiere conocer la lista de selladores (-1 para el último)")
	flags.BoolVar(&status, "status", false, "Indica el último bloque sellado por cada sellador, o -1 si un nodo no ha sellado en las últimas 5 rondas.")
	parseFlags()
	if blockNumber == 0{
		panic("El bloque génesis no tiene firmantes")
	}
	url = updateURL(url)
	node, err := bfa.Dial(url)
	defer node.Close()
	if status {
		sealers := node.SealersStatus(blockNumber)
		if json {
			util.PrintJson(sealers)
			return
		}
		var list []string
		for sealer := range sealers {
			list = append(list, sealer)
		}
		sort.Slice(list, func(i, j int) bool { return sealers[list[i]] > sealers[list[j]] })
		length := util.Max(2, int64(len(strconv.FormatInt(sealers[list[0]], 10))))
		for _, sealer := range list {
			fmt.Printf("%v: %*d\n", sealer, length, sealers[sealer])
		}
	} else {
		sealers := node.GetSignersAtBlock(blockNumber)
		sort.Slice(sealers, func(i, j int) bool { return sealers[i] < sealers[j] })
		if json {
			util.PrintJson(sealers)
		} else {
			for _, sealer := range sealers {
				fmt.Println(sealer)
			}
		}
	}
func propose() {
	var (
		all bool
		vote bool
		proposals []string
	)
	description = "Vota por una propuesta."
	setFlags()
	flags.BoolVar(&all, "all", false, "Vota en todas las propuestas activas")
	flags.BoolVar(&vote, "vote", true, "Sentido del voto (true: a favor, false: en contra)")
	parseFlags()
	url = updateURL(url)
	node, err := bfa.Dial(url)
	util.Check(err)
	defer node.Close()
	if all {
		votes := node.GetVotes(latest)
		for _, proposal := range votes.Proposals {
			proposals = append(proposals, proposal)
		}
	} else {
		for i := 0; i < flags.NArg(); i++ {
			proposals = append(proposals, flags.Arg(i))
		}
	for _, proposal := range proposals {
		node.Propose(proposal, vote)
		fmt.Printf("Voto por %v: %v\n", proposal, vote)
		commands = map[string]func(){
			"proposals": proposals,
			"sealers":   sealers,
			"vote": propose,
		validCommands []string
	for command := range commands {
		validCommands = append(validCommands, command)
	}
	defer func() {
		if err := recover(); err != nil {
			log.Printf("Error: %s", err)
			usage(1)
		}
	}()
	if len(os.Args) > 1 {
		command = os.Args[1]
	}
	if commands[command] == nil {
		fmt.Fprintf(os.Stderr, "Uso: %v <%v> [opciones]\n", path.Base(os.Args[0]), strings.Join(validCommands, "|"))
		fmt.Fprintf(os.Stderr, "Para ayuda: %v <command> -h\n", path.Base(os.Args[0]))
		os.Exit(1)
	}
	commands[command]()