From fd6f11a042bc431109a55be537369f3971748f50 Mon Sep 17 00:00:00 2001
From: Miguel Montes <miguel.montes@gmail.com>
Date: Mon, 12 Nov 2018 17:51:50 -0300
Subject: [PATCH] =?UTF-8?q?Cambio=20de=20organizaci=C3=B3n=20del=20c=C3=B3?=
 =?UTF-8?q?digo=20de=20bfa=5Fclient?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 bfa_client/src/bfa/node.go          | 447 +++++++++++++++++++++++++
 bfa_client/src/client/bfa_client.go | 502 +---------------------------
 bfa_client/src/util/util.go         |  42 +++
 3 files changed, 502 insertions(+), 489 deletions(-)
 create mode 100644 bfa_client/src/bfa/node.go
 create mode 100644 bfa_client/src/util/util.go

diff --git a/bfa_client/src/bfa/node.go b/bfa_client/src/bfa/node.go
new file mode 100644
index 0000000..73f9b86
--- /dev/null
+++ b/bfa_client/src/bfa/node.go
@@ -0,0 +1,447 @@
+package bfa
+
+import (
+	. "../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
+
+type Snapshot struct {
+	Number  uint64                          `json:"number"`  // Block number where the snapshot was created
+	Hash    common.Hash                     `json:"hash"`    // Block hash where the snapshot was created
+	Signers map[common.Address]struct{}     `json:"signers"` // Set of authorized signers at this moment
+	Recents map[uint64]common.Address       `json:"recents"` // Set of recent signers for spam protections
+	Votes   []*clique.Vote                  `json:"votes"`   // List of votes cast in chronological order
+	Tally   map[common.Address]clique.Tally `json:"tally"`   // Current vote tally to avoid recalculating
+}
+
+type Tally struct {
+	True  int `json:"true"`
+	False int `json:"false"`
+	Null  int `json:"null"`
+}
+
+type Proposals struct {
+	BlockNumber int64                       `json:"number"`    // Block number where the snapshot was created
+	Proposals   []string                    `json:"proposals"` // List of proposals being voted
+	Signers     []string                    `json:"signers"`   // List of authorized signers at this moment
+	Tally       map[string]*Tally           `json:"tally"`     // Count of positive, negative and empty votes for a proposal
+	Votes       map[string]map[string]*bool `json:"votes"`     // List of votes for each proposal
+}
+
+type SealerInfo struct {
+	Address      string
+	CurrentBlock int64
+	Since        int64
+	FirstBlock   int64
+	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...))
+}
+
+func (node *Node) blockNumber() int64 {
+	var bn rpc.BlockNumber
+	node.Call(&bn, "eth_blockNumber")
+	return bn.Int64()
+}
+
+
+
+func (node *Node) GetBlockByNumber(blockNumber int64) types.Header {
+	var (
+		number string
+		resp   types.Header
+	)
+	if blockNumber < 0 {
+		number = "latest"
+	} else {
+		number = fmt.Sprintf("0x%x", blockNumber)
+	}
+	node.Call(&resp, "eth_getBlockByNumber", number, false)
+	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)
+	Check(err)
+	return
+}
+
+
+
+func (node *Node) GetSnapshot() (snapshot Snapshot) {
+	node.Call(&snapshot, "clique_getSnapshot", nil)
+	return
+}
+
+func (node *Node) GetSnapshotAtHash(hash common.Hash) (snapshot Snapshot) {
+	node.Call(&snapshot, "clique_getSnapshotAtHash", hash)
+	return
+}
+
+func (node *Node) GetSnapshotAtBlock(blockNumber int64) (snapshot Snapshot) {
+	node.Call(&snapshot, "clique_getSnapshot", fmt.Sprintf("0x%x", blockNumber))
+	return
+}
+
+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()))
+	}
+	return
+}
+
+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()))
+	}
+	return
+}
+
+func (node *Node) GetSignersAtBlock(blockNumber int64) (signers []string) {
+	var s []common.Address
+	node.Call(&s, "clique_getSigners", "0x"+strconv.FormatInt(blockNumber, 16))
+	for _, signer := range s {
+		signers = append(signers, ToHex(signer.Bytes()))
+	}
+	return
+}
+
+func (node *Node) GetVotes(blockNumber int64) (votes Proposals) {
+	var (
+		snapshot Snapshot
+	)
+	if blockNumber < 0 {
+		snapshot = node.GetSnapshot()
+	} else {
+		snapshot = node.GetSnapshotAtBlock(blockNumber)
+	}
+	votes.BlockNumber = int64(snapshot.Number)
+	for signer := range snapshot.Signers {
+		votes.Signers = append(votes.Signers, ToHex(signer[:]))
+		sort.Strings(votes.Signers)
+	}
+	for proposal := range snapshot.Tally {
+		votes.Proposals = append(votes.Proposals, ToHex(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[:])
+		if votes.Votes[proposal] == nil {
+			votes.Votes[proposal] = make(map[string]*bool)
+			for _, signer := range votes.Signers {
+				votes.Votes[proposal][signer] = nil
+			}
+			votes.Tally[proposal] = &Tally{0, 0, len(votes.Signers)}
+		}
+		votes.Votes[proposal][signer] = &v.Authorize
+		if v.Authorize {
+			votes.Tally[proposal].True += 1
+		} else {
+			votes.Tally[proposal].False += 1
+		}
+		votes.Tally[proposal].Null -= 1
+	}
+	return
+}
+
+func (node *Node) SealersStatus() map[string]int64 {
+	status := make(map[string]int64)
+	for _, address := range node.GetSigners() {
+		status[address] = -1
+	}
+	notSeen := int64(len(status))
+	block := node.GetBlockByNumber(-1)
+	blockNumber := block.Number.Int64()
+	until := blockNumber - 5*notSeen
+	for notSeen > 0 {
+		signer, _ := getSigner(&block)
+		if status[signer] == -1 {
+			status[signer] = block.Number.Int64()
+			notSeen--
+		}
+		if blockNumber == until {
+			break
+		}
+		blockNumber--
+		block = node.GetBlockByNumber(blockNumber)
+	}
+	return status
+}
+
+
+func (node *Node) GetSealerInception(address string) (since int64) {
+	if signers := node.GetSigners(); !Contains(signers, address) {
+		return -1
+	}
+
+	lo := int64(0)
+	hi := node.blockNumber()
+	for lo < hi {
+		mid := lo + (hi-lo)/2
+		signers := node.GetSignersAtBlock(mid)
+		if Contains(signers, address) {
+			hi = mid
+		} else {
+			lo = mid + 1
+		}
+	}
+	return hi
+}
+
+func (node *Node) getSignerFirstBlock(signer string, since int64, until int64) (blockNumber int64) {
+	if since < 0 {
+		return -1
+	}
+	//snapshot := node.GetSnapshotAtBlock(since)
+	var (count int64 = 20
+		found int64 = -1
+	)
+	// first, we look close to the inception
+	if blockNumber, _ = node.searchSnapshotForward(since, signer, count); blockNumber > 0 {
+		return
+	}
+	// next, we do a coarse search
+	since += count
+	for i := since + 10000; i < until && found == -1; i += 10000 {
+		if found, _ = node.searchSnapshotBackward(i, signer, 0); found == -1 { // still not found
+			since = i
+		}
+	}
+	if found > 0 {
+		until = found
+	}
+	n := Min(10, (until-since)/count+1) // number of goroutines
+	ch := make(chan int64)
+	for i := int64(0); i < n; i++ {
+		go func() {
+			for blockNumber := <-ch; blockNumber > 0; blockNumber = <-ch {
+				cnt := Min(count, until-blockNumber+1)
+				if found, _ := node.searchSnapshotForward(blockNumber, signer, cnt); found > 0 {
+					ch <- found
+				}
+			}
+			ch <- (-1)
+		}()
+	}
+	for {
+		select {
+		case ch <- since:
+			switch {
+			case since < 0:
+				continue
+			case since+count < until:
+				since += count
+			default:
+				since = -1 //we have exhausted the search space
+			}
+		case found := <-ch:
+			switch {
+			case found < 0:
+				n-- // a goroutine has ended
+				if n == 0 { // all goroutines have ended
+					return
+				}
+			case blockNumber < 0:
+				blockNumber = found // first time we see this signer
+				since = -1          // Notify everyone
+			case found < blockNumber:
+				blockNumber = found // found an earlier block
+			}
+		}
+	}
+}
+
+func (node *Node) getSignerLastBlock(signer string, since int64, until int64) (blockNumber int64) {
+	if since < 0 {
+		return -1
+	}
+	var (
+		count   int64 = 20
+		visited int64 = 0
+		found   int64 = -1
+	)
+	// first, we look close to the last block
+	if blockNumber, visited = node.searchSnapshotBackward(until, signer, 0); blockNumber > 0 {
+		return
+	}
+	// next, we do a coarse search
+	until -= visited
+	for i := until - 10000; i > since && found == -1; i -= 10000 {
+		if found, _ = node.searchSnapshotBackward(i, signer, 0); found == -1 { // still not found
+			until = i
+		}
+	}
+	if found > 0 {
+		since = found
+	}
+	n := Min(10, (until-since)/count+1) // number of goroutines
+	ch := make(chan int64)
+	for i := int64(0); i < n; i++ {
+		go func() {
+			for blockNumber := <-ch; blockNumber > 0; blockNumber = <-ch {
+				cnt := Min(count, blockNumber-since+1)
+				if found, _ := node.searchSnapshotBackward(blockNumber, signer, cnt); found > 0 {
+					ch <- found
+				}
+			}
+			ch <- (-1)
+		}()
+	}
+	for {
+		select {
+		case ch <- until:
+			switch {
+			case until < 0:
+				continue
+			case until-count > since:
+				until -= count
+			default:
+				until = -1 //we have exhausted the search space
+			}
+		case found := <-ch:
+			switch {
+			case found < 0:
+				n-- // a goroutine has ended
+				if n == 0 { // all goroutines have ended
+					return
+				}
+			case blockNumber < 0:
+				blockNumber = found // first time we see this signer
+				until = -1          // Notify everyone
+			case found > blockNumber:
+				blockNumber = found // found a later block
+			}
+		}
+	}
+}
+
+
+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
+	}
+	for count > 0 {
+		snapshot := node.GetSnapshotAtBlock(blockNumber + count - 1)
+		recents := int64(len(snapshot.Recents))
+		visited += recents
+		count -= recents
+		for b, s := range snapshot.Recents {
+			if ToHex(s[:]) == signer {
+				found = int64(b)
+			}
+		}
+	}
+	return
+}
+
+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
+	}
+	count = Min(count, blockNumber) // Never search below block 1
+	for {
+		snapshot := node.GetSnapshotAtBlock(blockNumber - visited)
+		visited += int64(len(snapshot.Recents))
+		if count == 0 {
+			count = Min(blockNumber, int64(2*len(snapshot.Signers)))
+		}
+		for b, s := range snapshot.Recents {
+			if ToHex(s[:]) == signer {
+				found = int64(b)
+				return
+			}
+		}
+		if visited >= count {
+			return
+		}
+	}
+}
+
+
+
+func (node *Node) SealerInfo(sealer string) (info SealerInfo, err error) {
+	info.Address = sealer
+	info.CurrentBlock = node.blockNumber()
+	info.Since = node.GetSealerInception(sealer)
+	if info.Since == -1 {
+		return info, fmt.Errorf("%q is not a sealer", sealer)
+	}
+	info.FirstBlock = node.getSignerFirstBlock(sealer, info.Since+1, info.CurrentBlock)
+	info.LastBlock = node.getSignerLastBlock(sealer, info.FirstBlock, info.CurrentBlock)
+	return
+}
+
+
+
+func Dial(url string) *Node {
+	client, err := rpc.Dial(url)
+	Check(err)
+	return (*Node)(client)
+}
+
+func (node *Node) Close() {
+	(*rpc.Client)(node).Close()
+}
+
+
diff --git a/bfa_client/src/client/bfa_client.go b/bfa_client/src/client/bfa_client.go
index 86e5d7c..a3ee59e 100644
--- a/bfa_client/src/client/bfa_client.go
+++ b/bfa_client/src/client/bfa_client.go
@@ -4,461 +4,27 @@ import (
 	"encoding/json"
 	"flag"
 	"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"
 	"log"
 	"os"
 	"path"
-	"runtime"
 	"sort"
 	"strconv"
 	"strings"
+	"../util"
+	"../bfa"
 )
 
 const (
 	DefaultURL = "http://localhost:8545"
 )
 
-type Node rpc.Client
+type Node = bfa.Node
 
-func toHex(b []byte) string {
-	return fmt.Sprintf("0x%02x", b)
-}
-
-func (node *Node) blockNumber() int64 {
-	var bn rpc.BlockNumber
-	node.Call(&bn, "eth_blockNumber")
-	return bn.Int64()
-}
-
-func check(err error) {
-	if err != nil {
-		panic(err.Error())
-	}
-}
-
-func (node *Node) Call(result interface{}, method string, args ...interface{}) {
-	check((*rpc.Client)(node).Call(result, method, args...))
-}
-
-func (node *Node) getBlockByNumber(blockNumber int64) types.Header {
-	var (
-		number string
-		resp   types.Header
-	)
-	if blockNumber < 0 {
-		number = "latest"
-	} else {
-		number = fmt.Sprintf("0x%x", blockNumber)
-	}
-	node.Call(&resp, "eth_getBlockByNumber", number, false)
-	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)
-	check(err)
-	return
-}
-
-type Snapshot struct {
-	Number  uint64                          `json:"number"`  // Block number where the snapshot was created
-	Hash    common.Hash                     `json:"hash"`    // Block hash where the snapshot was created
-	Signers map[common.Address]struct{}     `json:"signers"` // Set of authorized signers at this moment
-	Recents map[uint64]common.Address       `json:"recents"` // Set of recent signers for spam protections
-	Votes   []*clique.Vote                  `json:"votes"`   // List of votes cast in chronological order
-	Tally   map[common.Address]clique.Tally `json:"tally"`   // Current vote tally to avoid recalculating
-}
-
-type Tally struct {
-	True  int `json:"true"`
-	False int `json:"false"`
-	Null  int `json:"null"`
-}
-
-type Proposals struct {
-	BlockNumber int64                       `json:"number"`    // Block number where the snapshot was created
-	Proposals   []string                    `json:"proposals"` // List of proposals being voted
-	Signers     []string                    `json:"signers"`   // List of authorized signers at this moment
-	Tally       map[string]*Tally           `json:"tally"`     // Count of positive, negative and empty votes for a proposal
-	Votes       map[string]map[string]*bool `json:"votes"`     // List of votes for each proposal
-}
-
-func (node *Node) getSnapshot() (snapshot Snapshot) {
-	node.Call(&snapshot, "clique_getSnapshot", nil)
-	return
-}
-
-func (node *Node) getSnapshotAtHash(hash common.Hash) (snapshot Snapshot) {
-	node.Call(&snapshot, "clique_getSnapshotAtHash", hash)
-	return
-}
-
-func (node *Node) getSnapshotAtBlock(blockNumber int64) Snapshot {
-	block := node.getBlockByNumber(blockNumber)
-	return node.getSnapshotAtHash(block.Hash())
-}
-
-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()))
-	}
-	return
-}
-
-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()))
-	}
-	return
-}
-
-func (node *Node) getSignersAtBlock(blockNumber int64) []string {
-	block := node.getBlockByNumber(blockNumber)
-	return node.getSignersAtHash(block.Hash())
-}
-
-func (node *Node) getVotes(blockNumber int64) (votes Proposals) {
-	var (
-		snapshot Snapshot
-	)
-	if blockNumber < 0 {
-		snapshot = node.getSnapshot()
-	} else {
-		snapshot = node.getSnapshotAtBlock(blockNumber)
-	}
-	votes.BlockNumber = int64(snapshot.Number)
-	for signer := range snapshot.Signers {
-		votes.Signers = append(votes.Signers, toHex(signer[:]))
-		sort.Strings(votes.Signers)
-	}
-	for proposal := range snapshot.Tally {
-		votes.Proposals = append(votes.Proposals, toHex(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[:])
-		if votes.Votes[proposal] == nil {
-			votes.Votes[proposal] = make(map[string]*bool)
-			for _, signer := range votes.Signers {
-				votes.Votes[proposal][signer] = nil
-			}
-			votes.Tally[proposal] = &Tally{0, 0, len(votes.Signers)}
-		}
-		votes.Votes[proposal][signer] = &v.Authorize
-		if v.Authorize {
-			votes.Tally[proposal].True += 1
-		} else {
-			votes.Tally[proposal].False += 1
-		}
-		votes.Tally[proposal].Null -= 1
-	}
-	return
-}
-
-func (node *Node) sealersStatus() map[string]int64 {
-	status := make(map[string]int64)
-	for _, address := range node.getSigners() {
-		status[address] = -1
-	}
-	notSeen := int64(len(status))
-	block := node.getBlockByNumber(-1)
-	blockNumber := block.Number.Int64()
-	until := blockNumber - 5*notSeen
-	for notSeen > 0 {
-		signer, _ := getSigner(&block)
-		if status[signer] == -1 {
-			status[signer] = block.Number.Int64()
-			notSeen--
-		}
-		if blockNumber == until {
-			break
-		}
-		blockNumber--
-		block = node.getBlockByNumber(blockNumber)
-	}
-	return status
-}
-
-func printDebug(msg string) {
-	ptr, _, _, _ := runtime.Caller(1)
-	fmt.Printf("%v: %v\n", msg, runtime.FuncForPC(ptr).Name())
-}
-
-func (node *Node) getSealerInception(address string) (since int64) {
-	if signers := node.getSigners(); !contains(signers, address) {
-		return -1
-	}
-
-	lo := int64(0)
-	hi := node.blockNumber()
-	for lo < hi {
-		mid := lo + (hi-lo)/2
-		signers := node.getSignersAtBlock(mid)
-		if contains(signers, address) {
-			hi = mid
-		} else {
-			lo = mid + 1
-		}
-	}
-	return hi
-}
-
-func min(a, b int64) int64 {
-	if a < b {
-		return a
-	}
-	return b
-}
-
-func (node *Node) getSignerFirstBlock(signer string, since int64, until int64) (blockNumber int64) {
-	if since < 0 {
-		return -1
-	}
-	//snapshot := node.getSnapshotAtBlock(since)
-	var count int64 = 20
-	// first, we look close to the inception
-	if blockNumber = node.searchSnapshotForward(since, signer, count); blockNumber > 0 {
-		return
-	}
-	since += count
-	n := min(10, (until-since)/count+1) // number of goroutines
-	ch := make(chan int64)
-	for i := int64(0); i < n; i++ {
-		go func() {
-			for blockNumber := <-ch; blockNumber > 0; blockNumber = <-ch {
-				cnt := min(count, until-blockNumber+1)
-				if found := node.searchSnapshotForward(blockNumber, signer, cnt); found > 0 {
-					ch <- found
-				}
-			}
-			ch <- (-1)
-		}()
-	}
-	for {
-		select {
-		case ch <- since:
-			switch {
-			case since < 0:
-				continue
-			case since + count < until:
-				since += count
-			default:
-				since = -1 //we have exhausted the search space
-			}
-		case found := <-ch:
-			switch {
-			case found < 0:
-				n-- // a goroutine has ended
-				if n == 0 { // all goroutines have ended
-					return
-				}
-			case blockNumber < 0:
-				blockNumber = found // first time we see this signer
-				since = -1          // Notify everyone
-			case found < blockNumber:
-				blockNumber = found // found an earlier block
-			}
-		}
-	}
-}
-
-func (node *Node) getSignerFirstBlock_(signer string, since int64, until int64) (blockNumber int64) {
-	if since < 0 {
-		return -1
-	}
-	last := since
-	for i := since; ; {
-		snapshot := node.getSnapshotAtBlock(i)
-		n := int64(len(snapshot.Recents))
-		if int64(snapshot.Number)-n > last {
-			i--
-			continue
-		}
-		for b, s := range snapshot.Recents {
-			if toHex(s[:]) == signer {
-				return int64(b)
-			}
-		}
-		if i >= until {
-			return -1
-		}
-		last = i
-		i += n
-	}
-}
-
-func (node *Node) searchSnapshot(blockNumber int64, signer string, count int64, forward bool) (found int64) {
-	found = -1
-	for count > 0 {
-		snapshot := node.getSnapshotAtBlock(blockNumber + count - 1)
-		for b, s := range snapshot.Recents {
-			if toHex(s[:]) == signer {
-				found = int64(b)
-				if !forward {
-					return
-				}
-			}
-		}
-		count -= int64(len(snapshot.Recents))
-	}
-	return
-}
-
-func (node *Node) searchSnapshotForward(blockNumber int64, signer string, count int64) (found int64) {
-	found = -1
-	for count > 0 {
-		snapshot := node.getSnapshotAtBlock(blockNumber + count - 1)
-		for b, s := range snapshot.Recents {
-			if toHex(s[:]) == signer {
-				found = int64(b)
-			}
-		}
-		count -= int64(len(snapshot.Recents))
-	}
-	return
-}
-
-func (node *Node) searchSnapshotBackward(blockNumber int64, signer string, count int64) (found int64) {
-	found = -1
-	for i := int64(0); i < count;  {
-		snapshot := node.getSnapshotAtBlock(blockNumber - i)
-		for b, s := range snapshot.Recents {
-			if toHex(s[:]) == signer {
-				return int64(b)
-			}
-		}
-		i += int64(len(snapshot.Recents))
-	}
-	return
-}
-
-func (node *Node) getSignerLastBlock(signer string, since int64, until int64) (blockNumber int64) {
-	if since < 0 {
-		return -1
-	}
-	var count int64 = 20
-	// first, we look close to the last block
-	if blockNumber = node.searchSnapshotBackward(until, signer, count); blockNumber > 0 {
-		return
-	}
-	until -= count
-	n := min(10, (until-since)/count+1) // number of goroutines
-	ch := make(chan int64)
-	for i := int64(0); i < n; i++ {
-		go func() {
-			for blockNumber := <-ch; blockNumber > 0; blockNumber = <-ch {
-				cnt := min(count, blockNumber - since + 1)
-				if found := node.searchSnapshotBackward(blockNumber, signer, cnt); found > 0 {
-					ch <- found
-				}
-			}
-			ch <- (-1)
-		}()
-	}
-	for {
-		select {
-		case ch <- since:
-			switch {
-			case until < 0:
-				continue
-			case until - count > since:
-				until -= count
-			default:
-				until = -1 //we have exhausted the search space
-			}
-		case found := <-ch:
-			switch {
-			case found < 0:
-				n-- // a goroutine has ended
-				if n == 0 { // all goroutines have ended
-					return
-				}
-			case blockNumber < 0:
-				blockNumber = found // first time we see this signer
-				until = -1          // Notify everyone
-			case found > blockNumber:
-				blockNumber = found // found a later block
-			}
-		}
-	}
-}
-
-func (node *Node) getSignerLastBlock__(signer string, since int64, until int64) (blockNumber int64) {
-	if since < 0 {
-		return -1
-	}
-	for i := until; i >= since; {
-		snapshot := node.getSnapshotAtBlock(i)
-		for b, s := range snapshot.Recents {
-			if toHex(s[:]) == signer {
-				return int64(b)
-			}
-		}
-		i -= int64(len(snapshot.Recents))
-	}
-	return -1
-}
-
-func (node *Node) getSignerLastBlock_(signer string, since int64, until int64) (blockNumber int64) {
-	if since < 0 {
-		return -1
-	}
-	for i := until; i >= since; i-- {
-		if signer == node.getBlockSigner(i) {
-			return i
-		}
-	}
-	return -1
-}
-
-type SealerInfo struct {
-	Address      string
-	CurrentBlock int64
-	Since        int64
-	FirstBlock   int64
-	LastBlock    int64
-}
-
-func (node *Node) sealerInfo(sealer string) (info SealerInfo, err error) {
-	info.Address = sealer
-	info.CurrentBlock = node.blockNumber()
-	info.Since = node.getSealerInception(sealer)
-	if info.Since == -1 {
-		return info, fmt.Errorf("%q is not a sealer", sealer)
-	}
-	info.FirstBlock = node.getSignerFirstBlock(sealer, info.Since + 1, info.CurrentBlock)
-	info.LastBlock = node.getSignerLastBlock(sealer, info.FirstBlock, info.CurrentBlock)
-	return
-}
-
-func printVotes(node *Node, useJson bool) {
-	votes := node.getVotes(-1)
+func printVotes(node *bfa.Node, useJson bool) {
+	votes := node.GetVotes(-1)
 	if useJson {
 		v, err := json.MarshalIndent(votes, "", "  ")
-		check(err)
+		util.Check(err)
 		fmt.Println(string(v))
 		return
 	}
@@ -481,18 +47,18 @@ func printVotes(node *Node, useJson bool) {
 }
 
 func printSealerInfo(node *Node, sealer string) {
-	info, err := node.sealerInfo(sealer)
-	check(err)
+	info, err := node.SealerInfo(sealer)
+	util.Check(err)
 	v, err := json.MarshalIndent(info, "", "  ")
-	check(err)
+	util.Check(err)
 	fmt.Println(string(v))
 }
 
 func printSealers(node *Node, useJson bool) {
-	sealers := node.sealersStatus()
+	sealers := node.SealersStatus()
 	if useJson {
 		v, err := json.MarshalIndent(sealers, "", "  ")
-		check(err)
+		util.Check(err)
 		fmt.Println(string(v))
 		return
 	}
@@ -507,48 +73,6 @@ func printSealers(node *Node, useJson bool) {
 	}
 }
 
-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 Dial(url string) *Node {
-	client, err := rpc.Dial(url)
-	check(err)
-	return (*Node)(client)
-}
-
-func (node *Node) Close() {
-	(*rpc.Client)(node).Close()
-}
-
-func contains(slice []string, s string) bool {
-	for _, x := range slice {
-		if x == s {
-			return true
-		}
-	}
-	return false
-}
 
 func main() {
 	var (
@@ -572,7 +96,7 @@ func main() {
 	if len(os.Args) > 1 {
 		command = os.Args[1]
 	}
-	if !contains(commands, command) {
+	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]))
 		os.Exit(1)
@@ -587,7 +111,7 @@ func main() {
 		flags.PrintDefaults()
 		return
 	}
-	node := Dial(url)
+	node := bfa.Dial(url)
 	defer node.Close()
 	switch command {
 	case "sealers":
diff --git a/bfa_client/src/util/util.go b/bfa_client/src/util/util.go
new file mode 100644
index 0000000..83c4197
--- /dev/null
+++ b/bfa_client/src/util/util.go
@@ -0,0 +1,42 @@
+package util
+
+import (
+	"fmt"
+	"runtime"
+)
+
+func Contains(slice []string, s string) bool {
+	for _, x := range slice {
+		if x == s {
+			return true
+		}
+	}
+	return false
+}
+
+func Check(err error) {
+	if err != nil {
+		panic(err.Error())
+	}
+}
+
+func ToHex(b []byte) string {
+	return fmt.Sprintf("0x%02x", b)
+}
+
+func PrintDebug(prefix, suffix string) {
+	ptr, _, _, _ := runtime.Caller(1)
+	fmt.Printf("%v: %v%v\n", prefix, runtime.FuncForPC(ptr).Name(), suffix)
+}
+
+func Min(a, b int64) int64 {
+	if a < b {
+		return a
+	}
+	return b
+}
+
+
+
+
+
-- 
GitLab