prysm-pulse/tools/eth1exporter/main.go
Preston Van Loon 7cc32c4dda
Various code inspection resolutions (#7438)
* remove unused code

* remove defer use in loop

* Remove unused methods and constants

* gofmt and gaz

* nilness check

* remove unused args

* Add TODO for refactoring subscribeWithBase to remove unused arg. It seems too involved to include in this sweeping PR. https://github.com/prysmaticlabs/prysm/issues/7437

* replace empty slice declaration

* Remove unnecessary type conversions

* remove redundant type declaration

* rename receivers to be consistent

* Remove bootnode query tool. It is now obsolete by discv5

* Remove relay node. It is no longer used or supported

* Revert "Remove relay node. It is no longer used or supported"

This reverts commit 4bd7717334dad85ef4766ed9bc4da711fb5fa810.

* Delete unused test directory

* Delete unsupported gcp startup script

* Delete old k8s script

* build fixes

* fix build

* go mod tidy

* revert slasher/db/kv/block_header.go

* fix build

* remove redundant nil check

* combine func args

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
Co-authored-by: Victor Farazdagi <simple.square@gmail.com>
2020-10-12 08:11:05 +00:00

184 lines
4.5 KiB
Go

// Prometheus exporter for Ethereum address balances.
// Forked from https://github.com/hunterlong/ethexporter
package main
import (
"bufio"
"context"
"flag"
"fmt"
"log"
"math/big"
"net/http"
"os"
"strings"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/params"
_ "github.com/prysmaticlabs/prysm/shared/maxprocs"
"github.com/sirupsen/logrus"
)
var (
allWatching []*Watching
loadSeconds float64
totalLoaded int64
eth *ethclient.Client
)
var (
port = flag.Int("port", 9090, "Port to serve /metrics")
web3URL = flag.String("web3-provider", "https://goerli.prylabs.net", "Web3 URL to access information about ETH1")
prefix = flag.String("prefix", "", "Metrics prefix.")
addressFilePath = flag.String("addresses", "", "File path to addresses text file.")
)
func main() {
flag.Parse()
if *addressFilePath == "" {
log.Println("--addresses is required")
return
}
err := OpenAddresses(*addressFilePath)
if err != nil {
panic(err)
}
err = ConnectionToGeth(*web3URL)
if err != nil {
panic(err)
}
// check address balances
go func() {
for {
totalLoaded = 0
t1 := time.Now()
fmt.Printf("Checking %v wallets...\n", len(allWatching))
for _, v := range allWatching {
v.Balance = GetEthBalance(v.Address).String()
totalLoaded++
}
t2 := time.Now()
loadSeconds = t2.Sub(t1).Seconds()
fmt.Printf("Finished checking %v wallets in %0.0f seconds, sleeping for %v seconds.\n", len(allWatching), loadSeconds, 15)
time.Sleep(15 * time.Second)
}
}()
block := CurrentBlock()
fmt.Printf("ETHexporter has started on port %v using web3 server: %v at block #%v\n", *port, *web3URL, block)
http.HandleFunc("/metrics", MetricsHTTP)
http.HandleFunc("/reload", ReloadHTTP)
log.Fatal(http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", *port), nil))
}
// Watching address wrapper
type Watching struct {
Name string
Address string
Balance string
}
// ConnectionToGeth - Connect to remote server.
func ConnectionToGeth(url string) error {
var err error
eth, err = ethclient.Dial(url)
return err
}
// GetEthBalance from remote server.
func GetEthBalance(address string) *big.Float {
balance, err := eth.BalanceAt(context.TODO(), common.HexToAddress(address), nil)
if err != nil {
fmt.Printf("Error fetching ETH Balance for address: %v\n", address)
}
return ToEther(balance)
}
// CurrentBlock in ETH1.
func CurrentBlock() uint64 {
block, err := eth.BlockByNumber(context.TODO(), nil)
if err != nil {
fmt.Printf("Error fetching current block height: %v\n", err)
return 0
}
return block.NumberU64()
}
// ToEther from Wei.
func ToEther(o *big.Int) *big.Float {
wei := big.NewFloat(0)
wei.SetInt(o)
return new(big.Float).Quo(wei, big.NewFloat(params.Ether))
}
// MetricsHTTP - HTTP response handler for /metrics.
func MetricsHTTP(w http.ResponseWriter, _ *http.Request) {
var allOut []string
total := big.NewFloat(0)
for _, v := range allWatching {
if v.Balance == "" {
v.Balance = "0"
}
bal := big.NewFloat(0)
bal.SetString(v.Balance)
total.Add(total, bal)
allOut = append(allOut, fmt.Sprintf("%veth_balance{name=\"%v\",address=\"%v\"} %v", *prefix, v.Name, v.Address, v.Balance))
}
allOut = append(allOut,
fmt.Sprintf("%veth_balance_total %0.18f", *prefix, total),
fmt.Sprintf("%veth_load_seconds %0.2f", *prefix, loadSeconds),
fmt.Sprintf("%veth_loaded_addresses %v", *prefix, totalLoaded),
fmt.Sprintf("%veth_total_addresses %v", *prefix, len(allWatching)))
if _, err := fmt.Fprintln(w, strings.Join(allOut, "\n")); err != nil {
logrus.WithError(err).Error("Failed to write metrics")
}
}
// ReloadHTTP reloads the addresses from disk.
func ReloadHTTP(w http.ResponseWriter, _ *http.Request) {
if err := OpenAddresses(*addressFilePath); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
log.Println("Reloaded addresses")
}
// OpenAddresses from text file (name:address)
func OpenAddresses(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer func() {
if err := file.Close(); err != nil {
panic(err)
}
}()
scanner := bufio.NewScanner(file)
allWatching = []*Watching{}
for scanner.Scan() {
object := strings.Split(scanner.Text(), ":")
if common.IsHexAddress(object[1]) {
w := &Watching{
Name: object[0],
Address: object[1],
}
allWatching = append(allWatching, w)
}
}
if err := scanner.Err(); err != nil {
return err
}
return err
}