diff --git a/cmd/bfa_client/bfa_client.go b/cmd/bfa_client/bfa_client.go index 56ce965fd8438f72463f9451bcf4f0cd53060d42..9c152e51c1fb4f6ab2580eeef2a5078b2205260d 100644 --- a/cmd/bfa_client/bfa_client.go +++ b/cmd/bfa_client/bfa_client.go @@ -4,7 +4,7 @@ import ( "encoding/json" "flag" "fmt" - "io/ioutil" + "io" "log" "math/big" "os" @@ -14,8 +14,9 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/common" "gitlab.bfa.ar/miguel/bfa/internal/bfa" - "gitlab.bfa.ar/miguel/bfa/internal/util" + "gitlab.bfa.ar/miguel/bfa/internal/cond" ) const ( @@ -58,6 +59,24 @@ var ( } ) +func PrintJson(s interface{}) { + v, err := json.MarshalIndent(s, "", " ") + cond.Check(err) + fmt.Println(string(v)) +} + +func IsValidAddress(address string) bool { + if !common.IsHexAddress(address) { + return false + } + // is mixed case hex address + if strings.ContainsAny(address, "abcdef") && strings.ContainsAny(address, "ABCDEF") { + return common.HexToAddress(address).Hex() == address + } else { + return true + } +} + func setFlags() { flags.BoolVar(&jsonOutput, "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'") @@ -93,7 +112,7 @@ func updateURL(url string) (updated string) { } func usage(errorCode int) { - util.Require(len(os.Args) > 1, "not enough arguments") + cond.Require(len(os.Args) > 1, "not enough arguments") _, _ = fmt.Fprintf(os.Stderr, "Uso: %v %v [opciones] %v\n%v\n", os.Args[0], os.Args[1], otherArgs, description) flags.PrintDefaults() os.Exit(errorCode) @@ -101,7 +120,7 @@ func usage(errorCode int) { func parseFlags(allowAdditionalArgs bool) { err := flags.Parse(os.Args[2:]) - util.Check(err) + cond.Check(err) if help { usage(0) } @@ -119,12 +138,12 @@ func proposals() { parseFlags(false) url = updateURL(url) node, err := bfa.Dial(url) - util.Check(err) + cond.Check(err) defer node.Close() blockNumber = node.BlockNumberInRange(blockNumber) votes := node.Votes(blockNumber) if jsonOutput { - util.PrintJson(votes) + PrintJson(votes) return } fmt.Printf("Bloque: %d\nPropuestas en curso: %d\n", votes.BlockNumber, len(votes.Proposals)) @@ -179,7 +198,7 @@ func parseFormatString(s string) (format string) { func printSealers(sealers []bfa.Address) { bfa.SortAddresses(sealers) if jsonOutput { - util.PrintJson(sealers) + PrintJson(sealers) } else { for _, sealer := range sealers { fmt.Println(sealer.Hex()) @@ -226,15 +245,15 @@ func sealers() { flags.StringVar(&unit, "unit", "wei", "Unidades en la que se expresa el balance. Posibles valores: wei, Kwei, kilowei, Mwei, megawei, Gwei, gigawei, microether, milliether, ether, babbage, lovelace, shannon, szabo, finney.") parseFlags(false) if blockNumber == 0 { - util.Error("El bloque génesis no tiene firmantes\n") + log.Fatal("El bloque génesis no tiene firmantes\n") } unit = strings.ToLower(unit) if _, ok := units[unit]; !ok { - util.Error("Unidad '%v' desconocida\n", unit) + log.Fatalf("Unidad '%v' desconocida\n", unit) } url = updateURL(url) node, err := bfa.Dial(url) - util.Check(err) + cond.Check(err) defer node.Close() blockNumber = node.BlockNumberInRange(blockNumber) extended := lastBlock || timestamp || difficulty || balance || len(formatStr) > 0 @@ -246,7 +265,7 @@ func sealers() { sealers := node.SealersStatus(blockNumber) if jsonOutput { - util.PrintJson(sealers) + PrintJson(sealers) return } @@ -282,7 +301,7 @@ func sealers() { formatStr = "%42v" if lastBlock { formatStr += " %[2]*[3]v" - lastBlockLen = util.Max(2, int64(len(strconv.FormatInt(sealers[list[0]].LastBlock, 10)))) + lastBlockLen = max(2, int64(len(strconv.FormatInt(sealers[list[0]].LastBlock, 10)))) } if timestamp { formatStr += " %[4]*[5]v" @@ -303,7 +322,7 @@ func sealers() { lastBlockLen, fmt.Sprintf("%*v", -lastBlockLen/2-2, "Last"), timestampLen, fmt.Sprintf("%*v", -timestampLen/2-2, "Time"), "Dif", - balanceLen, fmt.Sprintf("%*v", -(int(balanceLen)+len(unit))/2-1, strings.Title(unit))) + balanceLen, fmt.Sprintf("%*v", -(int(balanceLen)+len(unit))/2-1, unit)) } } formatStr += "\n" @@ -335,22 +354,22 @@ func autovote() { flags.IntVar(&threshold, "threshold", voteThreshold, "Cantidad mÃnima de votos en una propuesta para habilitar el voto automático.") setFlags() parseFlags(false) - util.Ensure(threshold >= voteThreshold, "No se puede especificar una cantidad de votos inferior a %v.", voteThreshold) + cond.Ensure(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) + cond.Check(err) defer node.Close() - util.Ensure(node.IsSealer(bfa.Self), "Solo los selladores pueden votar") + cond.Ensure(node.IsSealer(bfa.Self), "Solo los selladores pueden votar") votes := node.Votes(latest) genesisSigners := node.SealersAtBlock(0) self, err := node.Coinbase() - util.Check(err) + cond.Check(err) for _, tally := range votes.Tally { if tally.False >= threshold { // We are trying to remove a sealer removedSealers++ } } - util.Ensure(len(votes.Signers)-removedSealers >= minSigners, "No se puede emitir un voto automático que reduzca la cantidad de selladores por debajo de %v.", minSigners) + cond.Ensure(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 := proposal.In(votes.Signers) switch { @@ -375,7 +394,7 @@ func autovote() { } } if jsonOutput { - util.PrintJson(voted) + PrintJson(voted) } } @@ -391,22 +410,22 @@ func propose() { parseFlags(true) url = updateURL(url) node, err := bfa.Dial(url) - util.Check(err) + cond.Check(err) defer node.Close() - util.Ensure(node.IsSealer(bfa.Self), "Solo los selladores pueden votar") + cond.Ensure(node.IsSealer(bfa.Self), "Solo los selladores pueden votar") votes := node.Votes(latest) - util.Ensure(flags.NArg() > 0, "No se especificaron candidatos por los cuales votar\n") + cond.Ensure(flags.NArg() > 0, "No se especificaron candidatos por los cuales votar\n") for i := 0; i < flags.NArg(); i++ { addr := flags.Arg(i) - util.Ensure(util.IsValidAddress(addr), "'%v' no es una dirección válida\n", addr) + cond.Ensure(IsValidAddress(addr), "'%v' no es una dirección válida\n", addr) address := bfa.HexToAddress(addr) if _, ok := votes.Tally[address]; !ok { isSealer := address.In(votes.Signers) switch { // address is not in a proposal, we only allow removing signers or adding non signers case isSealer && authorize: - util.Error("'%v' ya es un sellador\n", address) + log.Fatalf("'%v' ya es un sellador\n", address) case !isSealer && !authorize: - util.Error("'%v' no es un sellador\n", address) + log.Fatalf("'%v' no es un sellador\n", address) } } node.Propose(address, authorize) @@ -417,7 +436,7 @@ func propose() { } } if jsonOutput { - util.PrintJson(voted) + PrintJson(voted) } } @@ -447,7 +466,7 @@ func status() { parseFlags(false) url = updateURL(url) node, err := bfa.Dial(url) - util.Check(err) + cond.Check(err) defer node.Close() for _, account := range node.Accounts() { nodeStatus.Accounts[account] = node.Balance(account) @@ -475,7 +494,7 @@ func status() { nodeStatus.BFAGenesis = bfa.Genesis(nodeStatus.Genesis).String() nodeStatus.BFANetwork = bfa.Network(nodeStatus.Network).String() nodeStatus.PeerCount = node.PeerCount() - util.PrintJson(nodeStatus) + PrintJson(nodeStatus) } func block() { @@ -488,11 +507,11 @@ func block() { parseFlags(false) url = updateURL(url) node, err := bfa.Dial(url) - util.Check(err) + cond.Check(err) defer node.Close() blockNumber = node.BlockNumberInRange(blockNumber) block := node.BlockByNumber(blockNumber) - util.PrintJson(block) + PrintJson(block) } func snapshot() { @@ -503,11 +522,11 @@ func snapshot() { parseFlags(false) url = updateURL(url) node, err := bfa.Dial(url) - util.Check(err) + cond.Check(err) defer node.Close() blockNumber = node.BlockNumberInRange(blockNumber) snapshot := node.SnapshotAtBlock(blockNumber) - util.PrintJson(snapshot) + PrintJson(snapshot) } func transfers() { @@ -528,13 +547,13 @@ func transfers() { parseFlags(true) url = updateURL(url) node, err := bfa.Dial(url) - util.Check(err) + cond.Check(err) defer node.Close() set := make(map[bfa.Address]bool) txs := make([]Transfer, 0) for i := 0; i < flags.NArg(); i++ { address := flags.Arg(i) - util.Ensure(util.IsValidAddress(address), "'%v' no es una dirección válida\n", address) + cond.Ensure(IsValidAddress(address), "'%v' no es una dirección válida\n", address) set[bfa.HexToAddress(address)] = true } latest := node.BlockNumber() @@ -576,7 +595,7 @@ func transfers() { } } if jsonOutput { - util.PrintJson(txs) + PrintJson(txs) } } @@ -621,7 +640,7 @@ func calculateSealerStats(url string, first int64, last int64, factor int64) (se lastBlock, end int64 ) node, err := bfa.Dial(url) - util.Check(err) + cond.Check(err) defer node.Close() sealerStats = make(map[bfa.Address]*Stats) latest := node.BlockNumber() @@ -746,12 +765,12 @@ func calculateSealerStats(url string, first int64, last int64, factor int64) (se func readStatsFromFile(filename string) (sealerStats map[bfa.Address]*Stats) { file, err := os.Open(filename) - util.Check(err) + cond.Check(err) defer file.Close() - byteBuffer, err := ioutil.ReadAll(file) - util.Check(err) + byteBuffer, err := io.ReadAll(file) + cond.Check(err) err = json.Unmarshal(byteBuffer, &sealerStats) - util.Check(err) + cond.Check(err) return } @@ -775,7 +794,7 @@ func sealerstats() { } else { sealerStats = calculateSealerStats(url, first, last, factor) } - util.PrintJson(sealerStats) + PrintJson(sealerStats) } func main() { @@ -794,6 +813,7 @@ func main() { validCommands []string command func() ) + log.SetFlags(0) for cmd := range commands { validCommands = append(validCommands, cmd) } @@ -801,6 +821,6 @@ func main() { if len(os.Args) > 1 { command = commands[os.Args[1]] } - util.Ensure(command != nil, "Uso: %v <%v> [opciones]\nPara ayuda: %v <command> -h\n", path.Base(os.Args[0]), strings.Join(validCommands, "|"), path.Base(os.Args[0])) + cond.Ensure(command != nil, "Uso: %v <%v> [opciones]\nPara ayuda: %v <command> -h\n", path.Base(os.Args[0]), strings.Join(validCommands, "|"), path.Base(os.Args[0])) command() } diff --git a/internal/util/util_test.go b/cmd/bfa_client/main_test.go similarity index 98% rename from internal/util/util_test.go rename to cmd/bfa_client/main_test.go index e94eb02f9d37664e8f1f9588bd5e316f96a1c379..28f12da3a39f2eb6eadfcf9d748da631164ba349 100644 --- a/internal/util/util_test.go +++ b/cmd/bfa_client/main_test.go @@ -1,4 +1,4 @@ -package util +package main import ( "strings" diff --git a/internal/bfa/block.go b/internal/bfa/block.go index 1af548b007f3440c97c0b87283484ad441c98105..17cd44ed1976ef2680663a32fe36ff1ca8724903 100644 --- a/internal/bfa/block.go +++ b/internal/bfa/block.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" - "gitlab.bfa.ar/miguel/bfa/internal/util" + "gitlab.bfa.ar/miguel/bfa/internal/cond" ) type BigInt struct { @@ -50,7 +50,7 @@ func (b Bytes) MarshalJSON() ([]byte, error) { } func (b *Bytes) UnmarshalJSON(src []byte) (err error) { - util.Require(len(src) >= 4 && bytes.Equal(src[1:3], []byte("0x")), "invalid json string") + cond.Require(len(src) >= 4 && bytes.Equal(src[1:3], []byte("0x")), "invalid json string") dest := make([]byte, hex.DecodedLen(len(src)-4)) _, err = hex.Decode(dest, src[3:len(src)-1]) if err == nil { diff --git a/internal/bfa/node.go b/internal/bfa/node.go index 225a0609840a6b1847d7c498e8bc73da78dfb6fe..c499c6fa26f609ae4a3391efed0311cb21bc0eb1 100644 --- a/internal/bfa/node.go +++ b/internal/bfa/node.go @@ -1,6 +1,7 @@ package bfa import ( + "fmt" "strconv" "github.com/ethereum/go-ethereum/common" @@ -8,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" - "gitlab.bfa.ar/miguel/bfa/internal/util" + "gitlab.bfa.ar/miguel/bfa/internal/cond" ) type Node rpc.Client @@ -87,7 +88,7 @@ func (genesis Genesis) String() string { var Self = Address{} // Empty address to represent the address of the caller func (node *Node) Call(result interface{}, method string, args ...interface{}) { - util.Check((*rpc.Client)(node).Call(result, method, args...)) + cond.Check((*rpc.Client)(node).Call(result, method, args...)) } func (node *Node) CallWithError(result interface{}, method string, args ...interface{}) error { @@ -142,7 +143,7 @@ func (node *Node) BlockNumberInRange(number int64) (blockNumber int64) { case number == -1, number > latest: blockNumber = latest case number < 0: - blockNumber = util.Max(0, latest+1+number) + blockNumber = max(0, latest+1+number) default: blockNumber = number } @@ -210,7 +211,7 @@ func (node *Node) SealersAtBlock(blockNumber int64) (signers []Address) { if blockNumber == -1 { return node.Sealers() } - node.Call(&signers, "clique_getSigners", util.Int64ToHex(blockNumber)) + node.Call(&signers, "clique_getSigners", fmt.Sprintf("0x%x", blockNumber)) return } @@ -315,7 +316,7 @@ func (node *Node) SealersStatus(blockNumber int64) (status map[Address]*SealerSt notSeen := int64(len(status)) block := node.HeaderByNumber(blockNumber) blockNumber = block.Number.Int64() - until := util.Max(1, blockNumber-SealerRounds*notSeen) + until := max(1, blockNumber-SealerRounds*notSeen) for notSeen > 0 { signer := node.BlockSigner(blockNumber) if _, ok := status[signer]; !ok { diff --git a/internal/cond/cond.go b/internal/cond/cond.go new file mode 100644 index 0000000000000000000000000000000000000000..5baa68bf3539eb9cf74778118fb05c67b0919c6d --- /dev/null +++ b/internal/cond/cond.go @@ -0,0 +1,23 @@ +package cond + +import ( + "log" + "runtime" +) + +func Ensure(condition bool, format string, args ...interface{}) { + if !condition { + log.Fatalf(format, args...) + } +} + +func Check(err error) { + Ensure(err == nil, "%v\n", err) +} + +func Require(condition bool, msg string) { + if !condition { + ptr, _, _, _ := runtime.Caller(1) + log.Panicf("%v in %v", msg, runtime.FuncForPC(ptr).Name()) + } +} diff --git a/internal/util/util.go b/internal/util/util.go deleted file mode 100644 index 15564b152992602fb58f5b5785e9631d5b647813..0000000000000000000000000000000000000000 --- a/internal/util/util.go +++ /dev/null @@ -1,83 +0,0 @@ -package util - -import ( - "encoding/json" - "fmt" - "log" - "os" - "runtime" - "strconv" - "strings" - - "github.com/ethereum/go-ethereum/common" -) - -func Contains(slice []string, s string) bool { - for _, x := range slice { - if x == s { - return true - } - } - return false -} - -func Error(format string, args ...interface{}) { - _, _ = fmt.Fprintf(os.Stderr, format, args...) - os.Exit(1) -} - -func Ensure(condition bool, format string, args ...interface{}) { - if !condition { - Error(format, args...) - } -} - -func Check(err error) { - Ensure(err == nil, "%v\n", err) -} - -func Int64ToHex(n int64) string { - return "0x" + strconv.FormatInt(n, 16) -} - -func Require(condition bool, msg string) { - if !condition { - ptr, _, _, _ := runtime.Caller(1) - log.Panicf("%v in %v", msg, runtime.FuncForPC(ptr).Name()) - } -} - -func Min(a, b int64) int64 { - if a < b { - return a - } - 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)) -} - -func isMixedCase(address string) bool { - return strings.ContainsAny(address, "abcdef") && strings.ContainsAny(address, "ABCDEF") -} - -func IsValidAddress(address string) bool { - if !common.IsHexAddress(address) { - return false - } - if isMixedCase(address) { - return common.HexToAddress(address).Hex() == address - } else { - return true - } -}