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

Agregado código de votación

parent 13aeb83f
No related branches found
No related tags found
No related merge requests found
SRC:=src/client/bfa_client.go src/bfa/node.go src/util/util.go src/clique/clique.go
all: bin/bfa_client
bin/bfa_client: src/client/bfa_client.go | bin
bin/bfa_client: $(SRC) | bin
go build -o $@ $<
bin:
......
package bfa
import (
. "../clique"
. "../util"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/clique"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"sort"
"strconv"
)
type Node rpc.Client
......@@ -47,30 +44,6 @@ type SealerInfo struct {
LastBlock int64
}
func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256()
rlp.Encode(hasher, []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
header.MixDigest,
header.Nonce,
})
hasher.Sum(hash[:0])
return hash
}
func (node *Node) Call(result interface{}, method string, args ...interface{}) {
Check((*rpc.Client)(node).Call(result, method, args...))
......@@ -98,19 +71,10 @@ func (node *Node) GetBlockByNumber(blockNumber int64) types.Header {
return resp
}
func getSigner(header *types.Header) (signer string, err error) {
signature := header.Extra[len(header.Extra)-65:]
hash := sigHash(header).Bytes()
pubkey, err := crypto.Ecrecover(hash, signature)
address := make([]byte, 20)
copy(address, crypto.Keccak256(pubkey[1:])[12:])
signer = ToHex(address)
return
}
func (node *Node) GetBlockSigner(blockNumber int64) (signer string) {
header := node.GetBlockByNumber(blockNumber)
signer, err := getSigner(&header)
signer, err := GetSigner(&header)
Check(err)
return
}
......@@ -128,7 +92,10 @@ func (node *Node) GetSnapshotAtHash(hash common.Hash) (snapshot Snapshot) {
}
func (node *Node) GetSnapshotAtBlock(blockNumber int64) (snapshot Snapshot) {
node.Call(&snapshot, "clique_getSnapshot", fmt.Sprintf("0x%x", blockNumber))
if blockNumber < 0 {
return node.GetSnapshot()
}
node.Call(&snapshot, "clique_getSnapshot", Int64ToHex(blockNumber))
return
}
......@@ -136,7 +103,7 @@ func (node *Node) GetSigners() (signers []string) {
var s []common.Address
node.Call(&s, "clique_getSigners", nil)
for _, signer := range s {
signers = append(signers, ToHex(signer.Bytes()))
signers = append(signers, BytesToHex(signer.Bytes()))
}
return
}
......@@ -145,20 +112,28 @@ func (node *Node) GetSignersAtHash(hash common.Hash) (signers []string) {
var s []common.Address
node.Call(&signers, "clique_getSignersAtHash", hash)
for _, signer := range s {
signers = append(signers, ToHex(signer.Bytes()))
signers = append(signers, BytesToHex(signer.Bytes()))
}
return
}
func (node *Node) GetSignersAtBlock(blockNumber int64) (signers []string) {
var s []common.Address
node.Call(&s, "clique_getSigners", "0x"+strconv.FormatInt(blockNumber, 16))
if blockNumber < 0 {
return node.GetSigners()
}
node.Call(&s, "clique_getSigners", Int64ToHex(blockNumber))
for _, signer := range s {
signers = append(signers, ToHex(signer.Bytes()))
signers = append(signers, BytesToHex(signer.Bytes()))
}
return
}
func (node *Node) Propose(address string, vote bool){
node.Call(nil, "clique_propose", address, vote)
return
}
func (node *Node) GetVotes(blockNumber int64) (votes Proposals) {
var (
snapshot Snapshot
......@@ -170,17 +145,17 @@ func (node *Node) GetVotes(blockNumber int64) (votes Proposals) {
}
votes.BlockNumber = int64(snapshot.Number)
for signer := range snapshot.Signers {
votes.Signers = append(votes.Signers, ToHex(signer[:]))
votes.Signers = append(votes.Signers, BytesToHex(signer[:]))
sort.Strings(votes.Signers)
}
for proposal := range snapshot.Tally {
votes.Proposals = append(votes.Proposals, ToHex(proposal[:]))
votes.Proposals = append(votes.Proposals, BytesToHex(proposal[:]))
}
votes.Votes = make(map[string]map[string]*bool)
votes.Tally = make(map[string]*Tally)
for _, v := range snapshot.Votes {
proposal := ToHex(v.Address[:])
signer := ToHex(v.Signer[:])
proposal := BytesToHex(v.Address[:])
signer := BytesToHex(v.Signer[:])
if votes.Votes[proposal] == nil {
votes.Votes[proposal] = make(map[string]*bool)
for _, signer := range votes.Signers {
......@@ -199,17 +174,20 @@ func (node *Node) GetVotes(blockNumber int64) (votes Proposals) {
return
}
func (node *Node) SealersStatus() map[string]int64 {
status := make(map[string]int64)
for _, address := range node.GetSigners() {
func (node *Node) SealersStatus(blockNumber int64) (status map[string]int64) {
if blockNumber == 0 { // Genesis block doesn't have signer
return
}
status = make(map[string]int64)
for _, address := range node.GetSignersAtBlock(blockNumber) {
status[address] = -1
}
notSeen := int64(len(status))
block := node.GetBlockByNumber(-1)
blockNumber := block.Number.Int64()
until := blockNumber - 5*notSeen
block := node.GetBlockByNumber(blockNumber)
blockNumber = block.Number.Int64()
until := Max(1, blockNumber - 5*notSeen)
for notSeen > 0 {
signer, _ := getSigner(&block)
signer, _ := GetSigner(&block)
if status[signer] == -1 {
status[signer] = block.Number.Int64()
notSeen--
......@@ -275,7 +253,7 @@ func (node *Node) getSignerFirstBlock(signer string, since int64, until int64) (
ch <- found
}
}
ch <- (-1)
ch <- -1
}()
}
for {
......@@ -339,7 +317,7 @@ func (node *Node) getSignerLastBlock(signer string, since int64, until int64) (b
ch <- found
}
}
ch <- (-1)
ch <- -1
}()
}
for {
......@@ -372,8 +350,6 @@ func (node *Node) getSignerLastBlock(signer string, since int64, until int64) (b
func (node *Node) searchSnapshotForward(blockNumber int64, signer string, count int64) (found int64, visited int64) {
//printDebug("In",fmt.Sprintf("(%v, %v, %v)", blockNumber, signer, count))
//defer printDebug("Out", "")
found = -1
if blockNumber+count < 1 {
return
......@@ -384,7 +360,7 @@ func (node *Node) searchSnapshotForward(blockNumber int64, signer string, count
visited += recents
count -= recents
for b, s := range snapshot.Recents {
if ToHex(s[:]) == signer {
if BytesToHex(s[:]) == signer {
found = int64(b)
}
}
......@@ -393,8 +369,6 @@ func (node *Node) searchSnapshotForward(blockNumber int64, signer string, count
}
func (node *Node) searchSnapshotBackward(blockNumber int64, signer string, count int64) (found int64, visited int64) {
//printDebug("In",fmt.Sprintf("(%v, %v, %v)", blockNumber, signer, count))
//defer printDebug("Out", "")
found = -1
if blockNumber < 1 { // Genesis block has no signers
return
......@@ -407,7 +381,7 @@ func (node *Node) searchSnapshotBackward(blockNumber int64, signer string, count
count = Min(blockNumber, int64(2*len(snapshot.Signers)))
}
for b, s := range snapshot.Recents {
if ToHex(s[:]) == signer {
if BytesToHex(s[:]) == signer {
found = int64(b)
return
}
......@@ -434,10 +408,9 @@ func (node *Node) SealerInfo(sealer string) (info SealerInfo, err error) {
func Dial(url string) *Node {
func Dial(url string) (*Node, error) {
client, err := rpc.Dial(url)
Check(err)
return (*Node)(client)
return (*Node)(client), err
}
func (node *Node) Close() {
......
package main
import (
"encoding/json"
"../bfa"
"../util"
"flag"
"fmt"
"log"
......@@ -10,22 +11,78 @@ import (
"sort"
"strconv"
"strings"
"../util"
"../bfa"
)
const (
DefaultURL = "http://localhost:8545"
latest = -1
)
type Node = bfa.Node
func printVotes(node *bfa.Node, useJson bool) {
votes := node.GetVotes(-1)
if useJson {
v, err := json.MarshalIndent(votes, "", " ")
util.Check(err)
fmt.Println(string(v))
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))
......@@ -46,81 +103,107 @@ func printVotes(node *bfa.Node, useJson bool) {
}
}
func printSealerInfo(node *Node, sealer string) {
info, err := node.SealerInfo(sealer)
util.Check(err)
v, err := json.MarshalIndent(info, "", " ")
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)
util.Check(err)
fmt.Println(string(v))
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 printSealers(node *Node, useJson bool) {
sealers := node.SealersStatus()
if useJson {
v, err := json.MarshalIndent(sealers, "", " ")
util.Check(err)
fmt.Println(string(v))
return
}
var list []string
for sealer := range sealers {
list = append(list, 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))
}
}
sort.Slice(list, func(i, j int) bool { return sealers[list[i]] > sealers[list[j]] })
length := len(strconv.FormatInt(sealers[list[0]], 10))
for _, sealer := range list {
fmt.Printf("%v: %*d\n", sealer, length, sealers[sealer])
for _, proposal := range proposals {
node.Propose(proposal, vote)
fmt.Printf("Voto por %v: %v\n", proposal, vote)
}
}
func main() {
var (
url string
useJson bool
help bool
flags flag.FlagSet
command = ""
commands = []string{"sealers", "proposals", "sealerInfo"}
desc = map[string]string{
"proposals": "Detalla el estado de una votación",
"sealerInfo": "Brinda datos sobre un sealer",
"sealers": "Brinda información sobre la última actividad de los selladores",
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.Fatalf("Error: %s", err)
log.Printf("Error: %s", err)
usage(1)
}
}()
if len(os.Args) > 1 {
command = os.Args[1]
}
if !util.Contains(commands, command) {
fmt.Fprintf(os.Stderr, "Uso: %v <%v> [opciones]\n", path.Base(os.Args[0]), strings.Join(commands, "|"))
fmt.Fprintf(os.Stderr, "For help: %v <command> -h\n", path.Base(os.Args[0]))
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)
}
flags.BoolVar(&useJson, "json", false, "Produce salida en formato json")
flags.StringVar(&url, "url", DefaultURL, "URL para conexión con geth. Ejemplo: /home/bfa/bfa/network/node/geth.ipc")
//flags.BoolVar(&help, "h", false, "")
//flags.BoolVar(&help, "help", false, "Muestra esta ayuda")
flags.Parse(os.Args[2:])
if help {
fmt.Fprintf(os.Stderr, "Uso: %v %v [opciones]\n%v\nOpciones: \n", path.Base(os.Args[0]), command, desc[command])
flags.PrintDefaults()
return
}
node := bfa.Dial(url)
defer node.Close()
switch command {
case "sealers":
printSealers(node, useJson)
case "proposals":
printVotes(node, useJson)
case "sealerInfo":
for i := 0; i < flags.NArg(); i++ {
printSealerInfo(node, flags.Arg(i))
}
}
commands[command]()
}
......@@ -39,6 +39,6 @@ func GetSigner(header *types.Header) (signer string, err error) {
pubkey, err := crypto.Ecrecover(hash, signature)
address := make([]byte, 20)
copy(address, crypto.Keccak256(pubkey[1:])[12:])
signer = util.ToHex(address)
signer = util.BytesToHex(address)
return
}
package util
import (
"encoding/json"
"fmt"
"runtime"
"strconv"
)
func Contains(slice []string, s string) bool {
......@@ -20,10 +22,14 @@ func Check(err error) {
}
}
func ToHex(b []byte) string {
func BytesToHex(b []byte) string {
return fmt.Sprintf("0x%02x", b)
}
func Int64ToHex(n int64) string {
return "0x"+strconv.FormatInt(n,16)
}
func PrintDebug(prefix, suffix string) {
ptr, _, _, _ := runtime.Caller(1)
fmt.Printf("%v: %v%v\n", prefix, runtime.FuncForPC(ptr).Name(), suffix)
......@@ -36,6 +42,19 @@ func Min(a, b int64) int64 {
return b
}
func Max(a, b int64) int64 {
if a > b {
return a
}
return b
}
func PrintJson(s interface{}){
v, err := json.MarshalIndent(s, "", " ")
Check(err)
fmt.Println(string(v))
return
}
......
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