diff --git a/bfa_client/Makefile b/bfa_client/Makefile
index 77f6e402f22cf55142936801e2a3c10114eb9838..ba58e52f67380c78fba0fd17c5430803bba81b42 100644
--- a/bfa_client/Makefile
+++ b/bfa_client/Makefile
@@ -1,4 +1,4 @@
-SRC:=src/client/bfa_client.go src/bfa/node.go src/util/util.go src/clique/clique.go
+SRC:=src/client/bfa_client.go src/bfa/node.go src/util/util.go src/bfa/clique.go src/bfa/block.go
 
 all: bin/bfa_client
 
diff --git a/bfa_client/src/bfa/block.go b/bfa_client/src/bfa/block.go
new file mode 100644
index 0000000000000000000000000000000000000000..248ebf939c9c821104614d5b38242861ce073546
--- /dev/null
+++ b/bfa_client/src/bfa/block.go
@@ -0,0 +1,148 @@
+package bfa
+
+import (
+	"../util"
+	"bytes"
+	"encoding/hex"
+	"errors"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/crypto/sha3"
+	"github.com/ethereum/go-ethereum/rlp"
+	"math/big"
+	"strconv"
+)
+
+type BigInt big.Int
+
+func (bigInt *BigInt) MarshalJSON() ([]byte, error) {
+	return (*big.Int)(bigInt).MarshalJSON()
+}
+
+func (bigInt *BigInt) UnmarshalJSON(b []byte) error {
+	if i, ok := new(big.Int).SetString(string(b[1:len(b)-1]), 0); ok {
+		*bigInt = BigInt(*i)
+		return nil
+	}
+	return errors.New("can't unmarshal BigInt")
+
+}
+
+func (bigInt *BigInt) Int64() int64 {
+	return (*big.Int)(bigInt).Int64()
+}
+
+func (bigInt *BigInt) Uint64() uint64 {
+	return (*big.Int)(bigInt).Uint64()
+}
+
+type Uint64 uint64
+
+func (u *Uint64) UnmarshalJSON(b []byte) (err error) {
+	i, err := strconv.ParseUint(string(b[1:len(b)-1]), 0, 64)
+	*u = Uint64(i)
+	return
+}
+
+type Bytes []byte
+
+func (b Bytes) MarshalJSON() ([]byte, error) {
+	dest := make([]byte, 2+hex.EncodedLen(len(b)))
+	copy(dest, []byte("\"0x"))
+	hex.Encode(dest[2:], b)
+	dest[len(dest)-1] = '"'
+	return dest, nil
+}
+
+func (b *Bytes) UnmarshalJSON(src []byte) (err error) {
+	util.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 {
+		*b = dest
+	}
+	return
+}
+
+// RPCTransaction represents a transaction
+type RPCTransaction struct {
+	BlockHash        common.Hash    `json:"blockHash"`
+	BlockNumber      Uint64         `json:"blockNumber"`
+	From             common.Address `json:"from"`
+	Gas              Uint64         `json:"gas"`
+	GasPrice         *BigInt        `json:"gasPrice"`
+	Hash             common.Hash    `json:"hash"`
+	Input            string         `json:"input"`
+	Nonce            Uint64         `json:"nonce"`
+	To               common.Address `json:"to"`
+	TransactionIndex Uint64         `json:"transactionIndex"`
+	Value            *BigInt        `json:"value"`
+	V                *BigInt        `json:"v"`
+	R                *BigInt        `json:"r"`
+	S                *BigInt        `json:"s"`
+}
+
+type Header struct {
+	ParentHash  common.Hash      `json:"parentHash"`
+	UncleHash   common.Hash      `json:"sha3Uncles"`
+	Coinbase    common.Address   `json:"miner"`
+	Root        common.Hash      `json:"stateRoot"`
+	TxHash      common.Hash      `json:"transactionsRoot"`
+	ReceiptHash common.Hash      `json:"receiptsRoot"`
+	Bloom       types.Bloom      `json:"logsBloom"`
+	Difficulty  *BigInt          `json:"difficulty"`
+	Number      *BigInt          `json:"number"`
+	GasLimit    Uint64           `json:"gasLimit"`
+	GasUsed     Uint64           `json:"gasUsed"`
+	Time        *BigInt          `json:"timestamp"`
+	Extra       Bytes            `json:"extraData"`
+	MixDigest   common.Hash      `json:"mixHash"`
+	Nonce       types.BlockNonce `json:"nonce"`
+}
+
+func (header *Header) ExtraWithoutSignature() []byte {
+	return header.Extra[:len(header.Extra)-65]
+}
+
+func (header *Header) Signature() []byte {
+	return header.Extra[len(header.Extra)-65:]
+}
+
+func (header *Header) ethHeader() *types.Header {
+	var h types.Header
+	h.ParentHash = header.ParentHash
+	h.UncleHash = header.UncleHash
+	h.Coinbase = header.Coinbase
+	h.Root = header.Root
+	h.TxHash = header.TxHash
+	h.ReceiptHash = header.ReceiptHash
+	h.Bloom = header.Bloom
+	h.Difficulty = (*big.Int)(header.Difficulty)
+	h.Number = (*big.Int)(header.Number)
+	h.GasLimit = uint64(header.GasLimit)
+	h.GasUsed = uint64(header.GasUsed)
+	h.Time = (*big.Int)(header.Time)
+	h.Extra = header.Extra
+	h.MixDigest = header.MixDigest
+	h.Nonce = header.Nonce
+	return &h
+}
+
+func (header *Header) GetSigner() common.Address {
+	return getSigner(header.ethHeader())
+}
+
+func (header *Header) GetHash() (h common.Hash) {
+	hw := sha3.NewKeccak256()
+	_ = rlp.Encode(hw, header.ethHeader())
+	hw.Sum(h[:0])
+	return h
+}
+
+type Block struct {
+	Header
+	Transactions    []RPCTransaction `json:"transactions"`
+	TotalDifficulty Uint64           `json:"totalDifficulty"`
+	Signer          common.Address   `json:"signer"`
+	Hash            common.Hash      `json:"hash"`
+}
diff --git a/bfa_client/src/bfa/clique.go b/bfa_client/src/bfa/clique.go
new file mode 100644
index 0000000000000000000000000000000000000000..af6dc84a154039b615245a5e4feca40e14ca9655
--- /dev/null
+++ b/bfa_client/src/bfa/clique.go
@@ -0,0 +1,46 @@
+package bfa
+
+import (
+	"github.com/ethereum/go-ethereum/common"
+	"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"
+)
+
+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 getSigner(header *types.Header) (address common.Address) {
+	if header.Number.Int64() == 0 { // Genesis block has no signers, we return an empty address
+		return
+	}
+	hash := sigHash(header).Bytes()
+	pubkey, err := crypto.Ecrecover(hash, header.Extra[len(header.Extra)-65:])
+	if err != nil {
+		panic(err)
+	}
+	copy(address[:], crypto.Keccak256(pubkey[1:])[12:])
+	return
+}
diff --git a/bfa_client/src/bfa/node.go b/bfa_client/src/bfa/node.go
index c0b66fe304321761d796392aeaf22f71e0125bce..23f6c084640154cd58c3c390b3d02c488e63519a 100644
--- a/bfa_client/src/bfa/node.go
+++ b/bfa_client/src/bfa/node.go
@@ -1,15 +1,10 @@
 package bfa
 
 import (
-	. "../clique"
 	. "../util"
-	"bytes"
-	"encoding/hex"
-	"errors"
 	"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/p2p"
 	"github.com/ethereum/go-ethereum/rpc"
 	"math/big"
@@ -19,183 +14,6 @@ import (
 
 type Node rpc.Client
 
-type BigInt big.Int
-
-func (bigInt *BigInt) MarshalJSON() ([]byte, error) {
-	return (*big.Int)(bigInt).MarshalJSON()
-}
-
-func (bigInt *BigInt) UnmarshalJSON(b []byte) error {
-	if i, ok := new(big.Int).SetString(string(b[1:len(b)-1]), 0); ok {
-		*bigInt = BigInt(*i)
-		return nil
-	}
-	return errors.New("can't unmarshal BigInt")
-
-}
-
-func (bigInt *BigInt) String() string {
-	return (*big.Int)(bigInt).String()
-}
-
-type Uint64 uint64
-
-func (u *Uint64) UnmarshalJSON(b []byte) (err error) {
-	i, err := strconv.ParseUint(string(b[1:len(b)-1]), 0, 64)
-	*u = Uint64(i)
-	return
-}
-
-type Bytes []byte
-
-func (b Bytes) MarshalJSON() ([]byte, error) {
-	dest := make([]byte, 2+hex.EncodedLen(len(b)))
-	copy(dest, []byte("\"0x"))
-	hex.Encode(dest[2:], b)
-	dest[len(dest)-1] = '"'
-	return dest, nil
-}
-
-func (b *Bytes) UnmarshalJSON(src []byte) (err error) {
-	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 {
-		*b = dest
-	}
-	return
-}
-
-// RPCTransaction represents a transaction
-type RPCTransaction struct {
-	BlockHash        common.Hash    `json:"blockHash"`
-	BlockNumber      Uint64         `json:"blockNumber"`
-	From             common.Address `json:"from"`
-	Gas              Uint64         `json:"gas"`
-	GasPrice         *BigInt        `json:"gasPrice"`
-	Hash             common.Hash    `json:"hash"`
-	Input            string         `json:"input"`
-	Nonce            Uint64         `json:"nonce"`
-	To               common.Address `json:"to"`
-	TransactionIndex Uint64         `json:"transactionIndex"`
-	Value            *BigInt        `json:"value"`
-	V                *BigInt        `json:"v"`
-	R                *BigInt        `json:"r"`
-	S                *BigInt        `json:"s"`
-}
-
-type Header struct {
-	ParentHash  common.Hash      `json:"parentHash"`
-	UncleHash   common.Hash      `json:"sha3Uncles"`
-	Coinbase    common.Address   `json:"miner"`
-	Root        common.Hash      `json:"stateRoot"`
-	TxHash      common.Hash      `json:"transactionsRoot"`
-	ReceiptHash common.Hash      `json:"receiptsRoot"`
-	Bloom       types.Bloom      `json:"logsBloom"`
-	Difficulty  *BigInt          `json:"difficulty"`
-	Number      *BigInt          `json:"number"`
-	GasLimit    Uint64           `json:"gasLimit"`
-	GasUsed     Uint64           `json:"gasUsed"`
-	Time        *BigInt          `json:"timestamp"`
-	Extra       Bytes            `json:"extraData"`
-	MixDigest   common.Hash      `json:"mixHash"`
-	Nonce       types.BlockNonce `json:"nonce"`
-}
-
-func (header *Header) ParentHsh() common.Hash {
-	return header.ParentHash
-}
-
-func (header *Header) UncleHsh() common.Hash {
-	return header.UncleHash
-}
-
-func (header *Header) RootHsh() common.Hash {
-	return header.Root
-}
-
-func (header *Header) TxHsh() common.Hash {
-	return header.TxHash
-}
-
-func (header *Header) ReceiptHsh() common.Hash {
-	return header.ReceiptHash
-}
-
-func (header *Header) MixDigestHsh() common.Hash {
-	return header.MixDigest
-}
-
-func (header *Header) LogsBloom() types.Bloom {
-	return header.Bloom
-}
-
-func (header *Header) BlockNonce() types.BlockNonce {
-	return header.Nonce
-}
-
-func (header *Header) BlockDifficulty() *big.Int {
-	return (*big.Int)(header.Difficulty)
-}
-
-func (header *Header) BlockNumber() *big.Int {
-	return (*big.Int)(header.Number)
-}
-
-func (header *Header) Timestamp() *big.Int {
-	return (*big.Int)(header.Time)
-}
-
-func (header *Header) MaxGas() uint64 {
-	return uint64(header.GasLimit)
-}
-
-func (header *Header) Gas() uint64 {
-	return uint64(header.GasUsed)
-}
-
-func (header *Header) ExtraWithoutSignature() []byte {
-	return header.Extra[:len(header.Extra)-65]
-}
-
-func (header *Header) Signature() []byte {
-	return header.Extra[len(header.Extra)-65:]
-}
-
-func (header *Header) Miner() common.Address {
-	return header.Coinbase
-}
-
-type Block struct {
-	Header
-	Transactions    []RPCTransaction `json:"transactions"`
-	TotalDifficulty Uint64           `json:"totalDifficulty"`
-	Signer          common.Address   `json:"signer"`
-}
-
-func (block *Block) GetHeader() (header types.Header) {
-	header.ParentHash = block.ParentHash
-	header.UncleHash = block.UncleHash
-	header.Coinbase = block.Coinbase
-	header.Root = block.Root
-	header.TxHash = block.TxHash
-	header.ReceiptHash = block.TxHash
-	header.Bloom = block.Bloom
-	header.Difficulty = (*big.Int)(block.Difficulty)
-	header.Number = (*big.Int)(block.Number)
-	header.GasLimit = uint64(block.GasLimit)
-	header.GasUsed = uint64(block.GasUsed)
-	header.Time = (*big.Int)(block.Time)
-	header.Extra = block.Extra
-	header.MixDigest = block.MixDigest
-	header.Nonce = block.Nonce
-	return
-}
-
-func (block *Block) setSigner() {
-	block.Signer = GetSigner(block)
-}
-
 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
@@ -311,13 +129,26 @@ func (node *Node) BlockNumberInRange(number int64) (blockNumber int64) {
 }
 
 func (node *Node) HeaderByNumber(blockNumber int64) (header Header) {
-	node.Call(&header, "eth_getBlockByNumber", hexBlockNumber(blockNumber), true)
+	node.Call(&header, "eth_getBlockByNumber", hexBlockNumber(blockNumber), false)
+	return
+}
+
+func (node *Node) HeaderByHash(hash common.Hash) (header Header) {
+	node.Call(&header, "eth_getBlockByHash", hash, false)
 	return
 }
 
 func (node *Node) BlockByNumber(blockNumber int64) (block Block) {
 	node.Call(&block, "eth_getBlockByNumber", hexBlockNumber(blockNumber), true)
-	block.setSigner()
+	block.Signer = block.GetSigner()
+	block.Hash = block.GetHash()
+	return
+}
+
+func (node *Node) BlockByHash(hash common.Hash) (block Block) {
+	node.Call(&block, "eth_getBlockByHash", hash, true)
+	block.Signer = block.GetSigner()
+	block.Hash = block.GetHash()
 	return
 }
 
@@ -326,8 +157,7 @@ func (node *Node) BlockSigner(blockNumber int64) (signer common.Address) {
 		return
 	}
 	header := node.HeaderByNumber(blockNumber)
-	signer = GetSigner(&header)
-	return
+	return header.GetSigner()
 }
 
 func (node *Node) GetSnapshot() (snapshot Snapshot) {
@@ -435,14 +265,14 @@ func (node *Node) SealersStatus(blockNumber int64) (status map[string]*SealerSta
 	}
 	notSeen := int64(len(status))
 	block := node.HeaderByNumber(blockNumber)
-	blockNumber = block.BlockNumber().Int64()
+	blockNumber = block.Number.Int64()
 	until := Max(1, blockNumber-5*notSeen)
 	for notSeen > 0 {
-		signer := BytesToHex(GetSigner(&block).Bytes())
+		signer := BytesToHex(block.GetSigner().Bytes())
 		if status[signer].LastBlock == 0 {
-			status[signer].LastBlock = block.BlockNumber().Int64()
-			status[signer].Time = block.Timestamp().Uint64()
-			status[signer].Difficulty = block.BlockDifficulty().Uint64()
+			status[signer].LastBlock = block.Number.Int64()
+			status[signer].Time = block.Time.Uint64()
+			status[signer].Difficulty = block.Difficulty.Uint64()
 			notSeen--
 		}
 		if blockNumber == until {
diff --git a/bfa_client/src/bfa/node_test.go b/bfa_client/src/bfa/node_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..0133db642fee59af20c38ceb50e2eb4a7f04e32b
--- /dev/null
+++ b/bfa_client/src/bfa/node_test.go
@@ -0,0 +1,181 @@
+package bfa
+
+import (
+	"flag"
+	"github.com/ethereum/go-ethereum/common"
+	"log"
+	"os"
+	"testing"
+)
+
+const (
+	NumBlocks int64 = 1000
+)
+
+var (
+	node    *Node
+	numbers map[string]int64
+	hashes  map[string][]common.Hash
+)
+
+func BenchmarkBlockByNumber(b *testing.B) {
+	for r, base := range numbers {
+		b.Run(r, func(b *testing.B) {
+			for i := int64(0); i < int64(b.N); i++ {
+				_ = node.BlockByNumber(base + i%NumBlocks)
+			}
+		})
+	}
+}
+
+func BenchmarkHeaderByNumber(b *testing.B) {
+	for r, base := range numbers {
+		b.Run(r, func(b *testing.B) {
+			for i := int64(0); i < int64(b.N); i++ {
+				_ = node.HeaderByNumber(base + i%NumBlocks)
+			}
+		})
+	}
+}
+
+func BenchmarkBlockByHash(b *testing.B) {
+	for r := range numbers {
+		b.Run(r, func(b *testing.B) {
+			for i := int64(0); i < int64(b.N); i++ {
+				_ = node.BlockByHash(hashes[r][i%NumBlocks])
+			}
+		})
+	}
+}
+
+func BenchmarkHeaderByHash(b *testing.B) {
+	for r := range numbers {
+		b.Run(r, func(b *testing.B) {
+			for i := int64(0); i < int64(b.N); i++ {
+				_ = node.HeaderByHash(hashes[r][i%NumBlocks])
+			}
+		})
+	}
+}
+
+func (node *Node) getBlocksByNumber(last int64, n int64) int64 {
+	block := node.BlockByNumber(last)
+	for i := int64(0); i < n; i++ {
+		block = node.BlockByNumber(block.Number.Int64() - 1)
+	}
+	return block.Number.Int64()
+}
+
+func (node *Node) getBlocksByHash(last int64, n int64) int64 {
+	block := node.BlockByNumber(last)
+	for i := int64(0); i < n; i++ {
+		block = node.BlockByHash(block.ParentHash)
+	}
+	return block.Number.Int64()
+}
+
+func (node *Node) getHeadersByNumber(last int64, n int64) int64 {
+	header := node.HeaderByNumber(last)
+	for i := int64(0); i < n; i++ {
+		header = node.HeaderByNumber(header.Number.Int64() - 1)
+	}
+	return header.Number.Int64()
+}
+
+func (node *Node) getHeadersByHash(last int64, n int64) int64 {
+	header := node.HeaderByNumber(last)
+	for i := int64(0); i < n; i++ {
+		header = node.HeaderByHash(header.ParentHash)
+	}
+	return header.Number.Int64()
+}
+
+func TestBlockGetters(t *testing.T) {
+	latest := node.BlockNumber()
+	if latest < NumBlocks {
+		t.Skip("No hay suficientes bloques")
+	}
+	t.Run("BlockByNumber", func(t *testing.T) {
+		if node.getBlocksByNumber(latest, NumBlocks) != latest-NumBlocks {
+			t.Fail()
+		}
+	})
+	t.Run("BlockByHash", func(t *testing.T) {
+		if node.getBlocksByHash(latest, NumBlocks) != latest-NumBlocks {
+			t.Fail()
+		}
+	})
+}
+
+func TestHeaderGetters(t *testing.T) {
+	latest := node.BlockNumber()
+	if latest < NumBlocks {
+		t.Skip("No hay suficientes bloques")
+	}
+	t.Run("HeaderByNumber", func(t *testing.T) {
+		if node.getHeadersByNumber(latest, NumBlocks) != latest-NumBlocks {
+			t.Fail()
+		}
+	})
+	t.Run("HeaderByHash", func(t *testing.T) {
+		if node.getHeadersByHash(latest, NumBlocks) != latest-NumBlocks {
+			t.Fail()
+		}
+	})
+}
+
+func BenchmarkBlockGetters(b *testing.B) {
+	latest := node.BlockNumber()
+	if latest < NumBlocks {
+		b.Skip("No hay suficientes bloques")
+	}
+	b.Run("BlockByNumber", func(b *testing.B) {
+		for i := int64(0); i < int64(b.N); i++ {
+			_ = node.getBlocksByNumber(latest, NumBlocks)
+		}
+	})
+	b.Run("BlockByHash", func(b *testing.B) {
+		for i := int64(0); i < int64(b.N); i++ {
+			_ = node.getBlocksByHash(latest, NumBlocks)
+		}
+	})
+}
+
+func BenchmarkHeaderGetters(b *testing.B) {
+	latest := node.BlockNumber()
+	if latest < NumBlocks {
+		b.Skip("No hay suficientes bloques")
+	}
+	b.Run("HeaderByNumber", func(b *testing.B) {
+		for i := int64(0); i < int64(b.N); i++ {
+			_ = node.getHeadersByNumber(latest, NumBlocks)
+		}
+	})
+	b.Run("HeaderByHash", func(b *testing.B) {
+		for i := int64(0); i < int64(b.N); i++ {
+			_ = node.getHeadersByHash(latest, NumBlocks)
+		}
+	})
+}
+
+func TestMain(m *testing.M) {
+	flag.Parse()
+	var err error
+	if node, err = Dial("http://localhost:8545"); err != nil {
+		log.Fatal(err)
+	}
+	latest := node.BlockNumber()
+	if latest < 3*NumBlocks {
+		log.Fatal("No hay suficientes bloques como para correr benchmarks")
+	}
+	numbers = map[string]int64{"lo": 1, "mid": latest / 2, "hi": latest - NumBlocks}
+	hashes = make(map[string][]common.Hash)
+	for r, base := range numbers {
+		for i := int64(0); i < NumBlocks; i++ {
+			header := node.HeaderByNumber(base + 1)
+			hashes[r] = append(hashes[r], header.GetHash())
+		}
+	}
+	os.Exit(m.Run())
+
+}
diff --git a/bfa_client/src/client/bfa_client.go b/bfa_client/src/client/bfa_client.go
index 7be848fbce2bda9d1e0f13052f07c381cae87f74..eac8434165334385cd9b04c6ebdc34e54bcea9de 100644
--- a/bfa_client/src/client/bfa_client.go
+++ b/bfa_client/src/client/bfa_client.go
@@ -339,9 +339,9 @@ func propose() {
 			isSealer := util.Contains(votes.Signers, address)
 			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", address)
+				util.Error("'%v' ya es un sellador\n", address)
 			case !isSealer && !authorize:
-				util.Error("'%v' no es un sellador", address)
+				util.Error("'%v' no es un sellador\n", address)
 			}
 		}
 		node.Propose(address, authorize)
diff --git a/bfa_client/src/clique/clique.go b/bfa_client/src/clique/clique.go
deleted file mode 100644
index fbc159e531ec564ee614f910500b482de35c2754..0000000000000000000000000000000000000000
--- a/bfa_client/src/clique/clique.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package clique
-
-import (
-	"github.com/ethereum/go-ethereum/common"
-	"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"
-	"math/big"
-)
-
-type BlockHeader interface {
-	ParentHsh() common.Hash
-	UncleHsh() common.Hash
-	Miner() common.Address
-	RootHsh() common.Hash
-	TxHsh() common.Hash
-	ReceiptHsh() common.Hash
-	LogsBloom() types.Bloom
-	BlockDifficulty() *big.Int
-	BlockNumber() *big.Int
-	MaxGas() uint64
-	Gas() uint64
-	Timestamp() *big.Int
-	ExtraWithoutSignature() []byte
-	MixDigestHsh() common.Hash
-	BlockNonce() types.BlockNonce
-	Signature() []byte
-}
-
-func sigHash(header BlockHeader) (hash common.Hash) {
-	hasher := sha3.NewKeccak256()
-	_ = rlp.Encode(hasher, []interface{}{
-		header.ParentHsh(),
-		header.UncleHsh(),
-		header.Miner(),
-		header.RootHsh(),
-		header.TxHsh(),
-		header.ReceiptHsh(),
-		header.LogsBloom(),
-		header.BlockDifficulty(),
-		header.BlockNumber(),
-		header.MaxGas(),
-		header.Gas(),
-		header.Timestamp(),
-		header.ExtraWithoutSignature(),
-		header.MixDigestHsh(),
-		header.BlockNonce(),
-	})
-	hasher.Sum(hash[:0])
-	return hash
-}
-
-func GetSigner(header BlockHeader) (address common.Address) {
-	if header.BlockNumber().Int64() == 0 { // Genesis block has no signers, we return an empty address
-		return
-	}
-	hash := sigHash(header).Bytes()
-	pubkey, err := crypto.Ecrecover(hash, header.Signature())
-	if err != nil {
-		panic(err)
-	}
-	copy(address[:], crypto.Keccak256(pubkey[1:])[12:])
-	return
-}
diff --git a/bfa_client/src/util/util_test.go b/bfa_client/src/util/util_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5de70e7831f7dc5f2d635b0be60ed57d0b666f53
--- /dev/null
+++ b/bfa_client/src/util/util_test.go
@@ -0,0 +1,41 @@
+package util
+
+import (
+	"strings"
+	"testing"
+)
+
+var (
+	addresses = map[string]string{
+		"ValidReal":               "0x46991ada2a2544468eb3673524641bf293f23ccc",
+		"ValidSeq":                "0x000102030405060708090a0b0c0d0e0f10111213",
+		"ValidZero":               "0x0000000000000000000000000000000000000000",
+		"InvalidNoPrefix":         "0046991ada2a2544468eb3673524641bf293f23ccc",
+		"InvalidEmpty":            "",
+		"InvalidLengthVeryShort":  "0x",
+		"InvalidLengthShort":      "0x46991ada2a2544468eb3673524641bf293f23cc",
+		"InvalidLengthLong":       "0x46991ada2a2544468eb3673524641bf293f23ccc00",
+		"InvalidNoHexAtBeginning": "0xx6991ada2a2544468eb3673524641bf293f23ccc",
+		"InvalidNoHexAtEnd":       "0x46991ada2a2544468eb3673524641bf293f23ccx",
+	}
+)
+
+func TestValidAddress(t *testing.T) {
+	for name, address := range addresses {
+		t.Run(name, func(t *testing.T) {
+			if IsAddress(address) != strings.HasPrefix(name, "Valid") {
+				t.Fail()
+			}
+		})
+	}
+}
+
+func BenchmarkIsAddressTrue(b *testing.B) {
+	for name, address := range addresses {
+		b.Run(name, func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				_ = IsAddress(address)
+			}
+		})
+	}
+}