Skip to content
Snippets Groups Projects
Commit 260ac500 authored by Miguel Montes's avatar Miguel Montes
Browse files

Refactorización del código de votación

División en dos comandos: vote y autovote
parent b72a3f9d
No related branches found
No related tags found
No related merge requests found
......@@ -15,8 +15,9 @@ import (
)
const (
latest = -1
minSigners = 5
latest = -1
minSigners = 5 // We don't want to have less sealers than this number
voteThreshold int = 3 // Number of manual votes needed to enable autovote
)
type Node = bfa.Node
......@@ -59,13 +60,14 @@ func updateURL(url string) (updated string) {
}
func usage(errorCode int) {
fmt.Fprintf(os.Stderr, "Uso: %v %v [opciones] %v\n%v\n", os.Args[0], command, otherArgs, description)
_, _ = fmt.Fprintf(os.Stderr, "Uso: %v %v [opciones] %v\n%v\n", os.Args[0], command, otherArgs, description)
flags.PrintDefaults()
os.Exit(errorCode)
}
func parseFlags() {
flags.Parse(os.Args[2:])
err := flags.Parse(os.Args[2:])
util.Check(err)
if help {
usage(0)
}
......@@ -205,63 +207,107 @@ func sealers() {
}
}
func autovote() {
var (
removedSealers = 0
threshold = voteThreshold
voted = make(map[string]bool)
)
description = fmt.Sprintf(`Vota automáticamente en todas las propuestas activas, en el sentido que corresponda, con ciertas restricciones.
- No deja votar si el voto puede reducir la cantidad de selladores a menos de %v.
- No permite eliminar a los selladores establecidos en el bloque génesis.
- Requiere que la propuesta tenga al menos %v votos.
- No permite votar para eliminarse a uno mismo de la lista de selladores.`, minSigners, threshold)
flags.IntVar(&threshold, "threshold", voteThreshold, "Cantidad mínima de votos en una propuesta para habilitar el voto automático.")
setFlags()
parseFlags()
util.PanicIf(threshold < voteThreshold, "No se puede especificar una cantidad de votos inferior a %v.", voteThreshold)
url = updateURL(url)
node, err := bfa.Dial(url)
util.Check(err)
defer node.Close()
util.PanicIf(!node.IsSealer(bfa.Self), "Solo los selladores pueden votar")
votes := node.GetVotes(latest)
genesisSigners := node.GetSignersAtBlock(0)
self, err := node.Coinbase()
util.Check(err)
for _, tally := range votes.Tally {
if tally.False >= threshold { // We are trying to remove a sealer
removedSealers += 1
}
}
util.PanicIf(len(votes.Signers)-removedSealers < minSigners, "No se puede emitir un voto automático que reduzca la cantidad de selladores por debajo de %v.", minSigners)
for _, proposal := range votes.Proposals {
isSealer := util.Contains(votes.Signers, proposal)
switch {
case votes.Votes[proposal][self] != nil:
continue // Already voted
case isSealer && votes.Tally[proposal].False < threshold:
continue // There aren't enough votes to enable autovote
case !isSealer && votes.Tally[proposal].True < threshold:
continue // There aren't enough votes to enable autovote
case util.Contains(genesisSigners, proposal) && isSealer:
log.Printf("No se puede quitar en forma automática a un sellador del bloque génesis: %v.\n", proposal)
continue
case proposal == self:
log.Println("No se puede votar para eliminarse uno mismo de la lista de selladores.")
continue
}
node.Propose(proposal, !isSealer)
if json {
voted[proposal] = !isSealer
} else {
fmt.Printf("Voto por %v: %v\n", proposal, !isSealer)
}
}
if json {
util.PrintJson(voted)
}
}
func propose() {
var (
auto bool
authorize bool
proposals []string
voted = make(map[string]bool)
)
description = "Vota por una propuesta."
otherArgs = "[propuesta...]"
setFlags()
flags.BoolVar(&auto, "auto", false, "Vota en todas las propuestas activas, en el sentido que corresponda.")
flags.BoolVar(&authorize, "authorize", 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()
genesisSigners := node.GetSignersAtBlock(0)
util.PanicIf(!node.IsSealer(bfa.Self), "Solo los selladores pueden votar")
votes := node.GetVotes(latest)
if auto {
for _, proposal := range votes.Proposals {
util.PanicIf(util.Contains(genesisSigners, proposal) && node.IsSealer(proposal), "No se puede quitar en forma automática a un sellador del bloque génesis.")
proposals = append(proposals, proposal)
if flags.NArg() == 0 {
panic("No se especificaron candidatos por los cuales votar")
}
for i := 0; i < flags.NArg(); i++ {
address := flags.Arg(i)
if !util.IsAddress(address) {
panic(fmt.Sprintf("'%v' no es una dirección válida", address))
}
if flags.NArg() != 0 {
fmt.Fprintf(os.Stderr, "Se especificó -auto. Ignorando argumentos adicionales.")
if _, ok := votes.Tally[address]; ok {
continue // address is in a proposal, so we allow voting either way
}
} else {
if flags.NArg() == 0 {
panic("No se especificaron candidatos por los cuales votar")
isSealer := util.Contains(votes.Signers, address)
switch { // address is not in a proposal, we allow removing signers or adding non signers
case isSealer && authorize:
panic(fmt.Sprintf("'%v' ya es un sellador", address))
case !isSealer && !authorize:
panic(fmt.Sprintf("'%v' no es un sellador", address))
}
for i := 0; i < flags.NArg(); i++ {
address := flags.Arg(i)
if !util.IsAddress(address) {
panic(fmt.Sprintf("'%v' no es una dirección válida", address))
}
if _, ok := votes.Tally[address]; ok {
continue // address is in a proposal, so we allow voting either way
}
isSealer := node.IsSealer(address)
switch { // address is not in a proposal, we allow removing signers or adding non signers
case isSealer && authorize:
panic(fmt.Sprintf("'%v' ya es un sellador", address))
case !isSealer && !authorize:
panic(fmt.Sprintf("'%v' no es un sellador", address))
}
proposals = append(proposals, flags.Arg(i))
node.Propose(address, authorize)
if json {
voted[address] = authorize
} else {
fmt.Printf("Voto por %v: %v\n", address, authorize)
}
}
self, err := node.Coinbase()
util.Check(err)
for _, proposal := range proposals {
util.PanicIf(proposal == self, "No es válido votarse a sí mismo")
authorize = !node.IsSealer(proposal)
util.PanicIf(len(node.GetSigners()) <= minSigners && !authorize, "Hay sólo %v selladores. No se permite eliminar más selladores.", minSigners)
node.Propose(proposal, authorize)
fmt.Printf("Voto por %v: %v\n", proposal, authorize)
if json {
util.PrintJson(voted)
}
}
......@@ -271,6 +317,7 @@ func main() {
"proposals": proposals,
"sealers": sealers,
"vote": propose,
"autovote": autovote,
}
validCommands []string
)
......@@ -287,8 +334,8 @@ func main() {
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]))
log.Printf("Uso: %v <%v> [opciones]\n", path.Base(os.Args[0]), strings.Join(validCommands, "|"))
log.Printf("Para ayuda: %v <command> -h\n", path.Base(os.Args[0]))
os.Exit(1)
}
commands[command]()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment