Skip to content
Snippets Groups Projects
Commit efb19800 authored by Miguel Montes's avatar Miguel Montes
Browse files

Refactorización del código

Cambio en la forma de obtener Hash y Signer del encabezado
parent 7ac17cce
No related branches found
No related tags found
No related merge requests found
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
......
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"`
}
package clique
package bfa
import (
"github.com/ethereum/go-ethereum/common"
......@@ -6,57 +6,38 @@ import (
"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) {
func sigHash(header *types.Header) (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(),
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 BlockHeader) (address common.Address) {
if header.BlockNumber().Int64() == 0 { // Genesis block has no signers, we return an empty address
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.Signature())
pubkey, err := crypto.Ecrecover(hash, header.Extra[len(header.Extra)-65:])
if err != nil {
panic(err)
}
......
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 {
......
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())
}
......@@ -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)
......
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)
}
})
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment