diff --git a/bfa_client/src/bfa/node.go b/bfa_client/src/bfa/node.go
index 4eba41587d817c3c1c5186601bb897e22c185795..264594fbbb990ec769b02a55f6d67e116dbb6682 100644
--- a/bfa_client/src/bfa/node.go
+++ b/bfa_client/src/bfa/node.go
@@ -3,6 +3,8 @@ package bfa
 import (
 	. "../clique"
 	. "../util"
+	"bytes"
+	"encoding/hex"
 	"errors"
 	"fmt"
 	"github.com/ethereum/go-ethereum/common"
@@ -20,8 +22,7 @@ type Node rpc.Client
 type BigInt big.Int
 
 func (bigInt *BigInt) MarshalJSON() ([]byte, error) {
-	i := (*big.Int)(bigInt)
-	return []byte(i.String()), nil
+	return (*big.Int)(bigInt).MarshalJSON()
 }
 
 func (bigInt *BigInt) UnmarshalJSON(b []byte) error {
@@ -39,16 +40,32 @@ func (bigInt *BigInt) String() string {
 
 type Uint64 uint64
 
-func (u *Uint64) MarshalJSON() ([]byte, error) {
-	return []byte(strconv.FormatUint(*(*uint64)(u), 10)), nil
-}
-
 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"`
@@ -69,24 +86,49 @@ type RPCTransaction struct {
 
 type Block 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      Uint64           `json:"difficulty"`
-	Number          Uint64           `json:"number"`
+	Difficulty      *BigInt          `json:"difficulty"`
+	Number          *BigInt          `json:"number"`
 	GasLimit        Uint64           `json:"gasLimit"`
 	GasUsed         Uint64           `json:"gasUsed"`
-	Time            Uint64           `json:"timestamp"`
-	Extra           []byte           `json:"extraData"`
+	Time            *BigInt          `json:"timestamp"`
+	Extra           Bytes            `json:"extraData"`
 	MixDigest       common.Hash      `json:"mixHash"`
-	Nonce           Uint64           `json:"nonce"`
+	Nonce           types.BlockNonce `json:"nonce"`
 	Transactions    []RPCTransaction `json:"transactions"`
 	TotalDifficulty Uint64           `json:"totalDifficulty"`
 	Signer          common.Address   `json:"signer"`
 }
 
+func (block *Block) Header() (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() {
+	header := block.Header()
+	block.Signer = GetSigner(&header)
+}
+
 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
@@ -195,31 +237,38 @@ func (node *Node) Coinbase() (coinbase string, err error) {
 	return
 }
 
-func (node *Node) HeaderByNumber(blockNumber int64) types.Header {
-	var (
-		number string
-		resp   types.Header
-	)
-	if blockNumber < 0 || blockNumber > node.BlockNumber() {
-		number = Latest
+func hexBlockNumber(number int64) (blockNumber string) {
+	if number == -1 {
+		blockNumber = Latest
 	} else {
-		number = fmt.Sprintf("0x%x", blockNumber)
+		blockNumber = "0x" + strconv.FormatInt(number, 16)
 	}
-	node.Call(&resp, "eth_getBlockByNumber", number, true)
-	return resp
+	return
 }
 
-func (node *Node) BlockByNumber(blockNumber int64) (block Block) {
-	var (
-		number string
-	)
-	if blockNumber < 0 || blockNumber > node.BlockNumber() {
-		number = Latest
-	} else {
-		number = fmt.Sprintf("0x%x", blockNumber)
+func (node *Node) BlockNumberInRange(number int64) (blockNumber int64) {
+	latest := node.BlockNumber()
+	switch {
+	case number == -1, number > latest:
+		blockNumber = latest
+	case number < 0:
+		blockNumber = Max(0, latest+1+number)
+	default:
+		blockNumber = number
 	}
-	node.Call(&block, "eth_getBlockByNumber", number, true)
-	block.Signer = node.BlockSigner(blockNumber)
+	return
+}
+
+func (node *Node) HeaderByNumber(blockNumber int64) (header types.Header) {
+	Require(blockNumber == -1 || blockNumber == node.BlockNumberInRange(blockNumber), "block number out of range")
+	node.Call(&header, "eth_getBlockByNumber", hexBlockNumber(blockNumber), true)
+	return
+}
+
+func (node *Node) BlockByNumber(blockNumber int64) (block Block) {
+	Require(blockNumber == -1 || blockNumber == node.BlockNumberInRange(blockNumber), "block number out of range")
+	node.Call(&block, "eth_getBlockByNumber", hexBlockNumber(blockNumber), true)
+	block.setSigner()
 	return
 }
 
@@ -243,10 +292,8 @@ func (node *Node) SnapshotAtHash(hash common.Hash) (snapshot Snapshot) {
 }
 
 func (node *Node) SnapshotAtBlock(blockNumber int64) (snapshot Snapshot) {
-	if blockNumber < 0 || blockNumber >= node.BlockNumber() {
-		return node.GetSnapshot()
-	}
-	node.Call(&snapshot, "clique_getSnapshot", Int64ToHex(blockNumber))
+	Require(blockNumber == -1 || blockNumber == node.BlockNumberInRange(blockNumber), "block number out of range")
+	node.Call(&snapshot, "clique_getSnapshot", hexBlockNumber(blockNumber))
 	return
 }
 
diff --git a/bfa_client/src/client/bfa_client.go b/bfa_client/src/client/bfa_client.go
index be426749cb22687f73a065ab5cc29cd04983cecb..926df25fd72bb20525f8e05f11cc4fbdefc9ae60 100644
--- a/bfa_client/src/client/bfa_client.go
+++ b/bfa_client/src/client/bfa_client.go
@@ -88,6 +88,7 @@ func proposals() {
 	node, err := bfa.Dial(url)
 	util.Check(err)
 	defer node.Close()
+	blockNumber = node.BlockNumberInRange(blockNumber)
 	votes := node.Votes(blockNumber)
 	if json {
 		util.PrintJson(votes)
@@ -163,12 +164,13 @@ func sealers() {
 	flags.StringVar(&format, "format", "", "Formato del timestamp. Ignorado en formato json. Opciones: 'unix', 'rfc3339', 'long' ('YYYY-MM-DD hh:mm:ss'), 'short' ('hh:mm:ss') o un formato específico. Ejemplo 'DD/MM/YY hh.mm.ss'. También se admite el formato del paquete 'time' de go.")
 	parseFlags(false)
 	if blockNumber == 0 {
-		panic("El bloque génesis no tiene firmantes")
+		util.Error("El bloque génesis no tiene firmantes")
 	}
 	url = updateURL(url)
 	node, err := bfa.Dial(url)
 	util.Check(err)
 	defer node.Close()
+	blockNumber = node.BlockNumberInRange(blockNumber)
 	extended := lastBlock || timestamp || difficulty || balance
 	if extended {
 		sealers := node.SealersStatus(blockNumber)
@@ -268,12 +270,12 @@ 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.DieIf(threshold < voteThreshold, "No se puede especificar una cantidad de votos inferior a %v.", voteThreshold)
+	util.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)
 	defer node.Close()
-	util.DieIf(!node.IsSealer(bfa.Self), "Solo los selladores pueden votar")
+	util.Ensure(node.IsSealer(bfa.Self), "Solo los selladores pueden votar")
 	votes := node.Votes(latest)
 	genesisSigners := node.SealersAtBlock(0)
 	self, err := node.Coinbase()
@@ -283,7 +285,7 @@ func autovote() {
 			removedSealers += 1
 		}
 	}
-	util.DieIf(len(votes.Signers)-removedSealers < minSigners, "No se puede emitir un voto automático que reduzca la cantidad de selladores por debajo de %v.", minSigners)
+	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)
 	for _, proposal := range votes.Proposals {
 		isSealer := util.Contains(votes.Signers, proposal)
 		switch {
@@ -326,25 +328,21 @@ func propose() {
 	node, err := bfa.Dial(url)
 	util.Check(err)
 	defer node.Close()
-	util.DieIf(!node.IsSealer(bfa.Self), "Solo los selladores pueden votar")
+	util.Ensure(node.IsSealer(bfa.Self), "Solo los selladores pueden votar")
 	votes := node.Votes(latest)
-	if flags.NArg() == 0 {
-		panic("No se especificaron candidatos por los cuales votar")
-	}
+	util.Ensure(flags.NArg() > 0, "No se especificaron candidatos por los cuales votar")
 	for i := 0; i < flags.NArg(); i++ {
 		address := flags.Arg(i)
-		if !util.IsAddress(address) {
-			panic(fmt.Sprintf("'%v' no es una dirección válida", address))
-		}
+		util.Ensure(util.IsAddress(address), "'%v' no es una dirección válida", address)
 		if _, ok := votes.Tally[address]; ok {
 			continue // address is in a proposal, so we allow voting either way
 		}
 		isSealer := util.Contains(votes.Signers, address)
 		switch { // address is not in a proposal, we allow removing signers or adding non signers
 		case isSealer && authorize:
-			panic(fmt.Sprintf("'%v' ya es un sellador", address))
+			util.Error("'%v' ya es un sellador", address)
 		case !isSealer && !authorize:
-			panic(fmt.Sprintf("'%v' no es un sellador", address))
+			util.Error("'%v' no es un sellador", address)
 		}
 		node.Propose(address, authorize)
 		if json {
@@ -411,6 +409,7 @@ func block() {
 	node, err := bfa.Dial(url)
 	util.Check(err)
 	defer node.Close()
+	blockNumber = node.BlockNumberInRange(blockNumber)
 	block := node.BlockByNumber(blockNumber)
 	util.PrintJson(block)
 }
@@ -425,6 +424,7 @@ func snapshot() {
 	node, err := bfa.Dial(url)
 	util.Check(err)
 	defer node.Close()
+	blockNumber = node.BlockNumberInRange(blockNumber)
 	snapshot := node.SnapshotAtBlock(blockNumber)
 	util.PrintJson(snapshot)
 }
diff --git a/bfa_client/src/clique/clique.go b/bfa_client/src/clique/clique.go
index 79cc23a7d8103ff521e74f9fae7537e642797545..2e91d9b6eeb9576019429625b8a2edd21870db59 100644
--- a/bfa_client/src/clique/clique.go
+++ b/bfa_client/src/clique/clique.go
@@ -10,8 +10,7 @@ import (
 
 func sigHash(header *types.Header) (hash common.Hash) {
 	hasher := sha3.NewKeccak256()
-
-	rlp.Encode(hasher, []interface{}{
+	_ = rlp.Encode(hasher, []interface{}{
 		header.ParentHash,
 		header.UncleHash,
 		header.Coinbase,
diff --git a/bfa_client/src/util/util.go b/bfa_client/src/util/util.go
index fab25581370439fab2b9825fc585ecab297b7c91..dfff2b691aca548cf2513f2e1cda7d059787923c 100644
--- a/bfa_client/src/util/util.go
+++ b/bfa_client/src/util/util.go
@@ -80,7 +80,3 @@ func IsAddress(address string) bool {
 	bytes, err := hex.DecodeString(address[2:])
 	return err == nil && len(bytes) == common.AddressLength
 }
-
-func DieIf(cond bool, format string, args ...interface{}) {
-	Ensure(!cond, format, args)
-}