forked from cerc-io/ipld-eth-server
Get transactions (#45)
* Make transactions requests in parallel * Update transaction error handling
This commit is contained in:
@@ -4,7 +4,7 @@ import "math/big"
|
||||
|
||||
type Blockchain interface {
|
||||
ContractDataFetcher
|
||||
GetBlockByNumber(blockNumber int64) Block
|
||||
GetBlockByNumber(blockNumber int64) (Block, error)
|
||||
GetLogs(contract Contract, startingBlockNumber *big.Int, endingBlockNumber *big.Int) ([]Log, error)
|
||||
LastBlock() *big.Int
|
||||
Node() Node
|
||||
|
||||
@@ -3,10 +3,17 @@ package postgres_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
func TestPostgres(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Postgres Suite")
|
||||
|
||||
@@ -4,9 +4,6 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"math/big"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
@@ -20,10 +17,6 @@ import (
|
||||
"github.com/vulcanize/vulcanizedb/test_config"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
var _ = Describe("Postgres DB", func() {
|
||||
var sqlxdb *sqlx.DB
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ type Blockchain struct {
|
||||
WasToldToStop bool
|
||||
node core.Node
|
||||
ContractReturnValue []byte
|
||||
err error
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) FetchContractData(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) error {
|
||||
@@ -42,12 +43,13 @@ func (blockchain *Blockchain) Node() core.Node {
|
||||
return blockchain.node
|
||||
}
|
||||
|
||||
func NewBlockchain() *Blockchain {
|
||||
func NewBlockchain(err error) *Blockchain {
|
||||
return &Blockchain{
|
||||
blocks: make(map[int64]core.Block),
|
||||
logs: make(map[string][]core.Log),
|
||||
contractAttributes: make(map[string]map[string]string),
|
||||
node: core.Node{GenesisBlock: "GENESIS", NetworkID: 1, ID: "x123", ClientName: "Geth"},
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +63,11 @@ func NewBlockchainWithBlocks(blocks []core.Block) *Blockchain {
|
||||
}
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) GetBlockByNumber(blockNumber int64) core.Block {
|
||||
return blockchain.blocks[blockNumber]
|
||||
func (blockchain *Blockchain) GetBlockByNumber(blockNumber int64) (core.Block, error) {
|
||||
if blockchain.err != nil {
|
||||
return core.Block{}, blockchain.err
|
||||
}
|
||||
return blockchain.blocks[blockNumber], nil
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) AddBlock(block core.Block) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
@@ -17,8 +18,11 @@ type Client interface {
|
||||
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
|
||||
}
|
||||
|
||||
func ToCoreBlock(gethBlock *types.Block, client Client) core.Block {
|
||||
transactions := convertTransactionsToCore(gethBlock, client)
|
||||
func ToCoreBlock(gethBlock *types.Block, client Client) (core.Block, error) {
|
||||
transactions, err := convertTransactionsToCore(gethBlock, client)
|
||||
if err != nil {
|
||||
return core.Block{}, err
|
||||
}
|
||||
coreBlock := core.Block{
|
||||
Difficulty: gethBlock.Difficulty().Int64(),
|
||||
ExtraData: hexutil.Encode(gethBlock.Extra()),
|
||||
@@ -36,35 +40,48 @@ func ToCoreBlock(gethBlock *types.Block, client Client) core.Block {
|
||||
}
|
||||
coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles())
|
||||
coreBlock.UnclesReward = CalcUnclesReward(coreBlock, gethBlock.Uncles())
|
||||
return coreBlock
|
||||
return coreBlock, nil
|
||||
}
|
||||
|
||||
func convertTransactionsToCore(gethBlock *types.Block, client Client) []core.Transaction {
|
||||
transactions := make([]core.Transaction, 0)
|
||||
for i, gethTransaction := range gethBlock.Transactions() {
|
||||
from, err := client.TransactionSender(context.Background(), gethTransaction, gethBlock.Hash(), uint(i))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
transaction := transToCoreTrans(gethTransaction, &from)
|
||||
transaction, err = appendReceiptToTransaction(client, transaction)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
transactions = append(transactions, transaction)
|
||||
func convertTransactionsToCore(gethBlock *types.Block, client Client) ([]core.Transaction, error) {
|
||||
var g errgroup.Group
|
||||
coreTransactions := make([]core.Transaction, len(gethBlock.Transactions()))
|
||||
|
||||
for gethTransactionIndex, gethTransaction := range gethBlock.Transactions() {
|
||||
//https://golang.org/doc/faq#closures_and_goroutines
|
||||
transaction := gethTransaction
|
||||
transactionIndex := uint(gethTransactionIndex)
|
||||
g.Go(func() error {
|
||||
from, err := client.TransactionSender(context.Background(), transaction, gethBlock.Hash(), transactionIndex)
|
||||
if err != nil {
|
||||
log.Println("transaction sender: ", err)
|
||||
return err
|
||||
}
|
||||
coreTransaction := transToCoreTrans(transaction, &from)
|
||||
coreTransaction, err = appendReceiptToTransaction(client, coreTransaction)
|
||||
if err != nil {
|
||||
log.Println("receipt: ", err)
|
||||
return err
|
||||
}
|
||||
coreTransactions[transactionIndex] = coreTransaction
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return transactions
|
||||
if err := g.Wait(); err != nil {
|
||||
log.Println("transactions: ", err)
|
||||
return coreTransactions, err
|
||||
}
|
||||
return coreTransactions, nil
|
||||
}
|
||||
|
||||
func appendReceiptToTransaction(client Client, transaction core.Transaction) (core.Transaction, error) {
|
||||
gethReceipt, err := client.TransactionReceipt(context.Background(), common.HexToHash(transaction.Hash))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return transaction, err
|
||||
}
|
||||
receipt := ReceiptToCoreReceipt(gethReceipt)
|
||||
transaction.Receipt = receipt
|
||||
return transaction, err
|
||||
return transaction, nil
|
||||
}
|
||||
|
||||
func transToCoreTrans(transaction *types.Transaction, from *common.Address) core.Transaction {
|
||||
|
||||
@@ -5,6 +5,13 @@ import (
|
||||
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
@@ -15,11 +22,25 @@ import (
|
||||
|
||||
type FakeGethClient struct {
|
||||
receipts map[string]*types.Receipt
|
||||
err error
|
||||
}
|
||||
|
||||
func NewFakeClient() *FakeGethClient {
|
||||
type TransActionReceiptError struct{}
|
||||
|
||||
func (tarErr TransActionReceiptError) Error() string {
|
||||
return fmt.Sprintf("transaction receipt error")
|
||||
}
|
||||
|
||||
type TransactionSenderError struct{}
|
||||
|
||||
func (tasErr TransactionSenderError) Error() string {
|
||||
return fmt.Sprintf("transaction sender error")
|
||||
}
|
||||
|
||||
func NewFakeClient(err error) *FakeGethClient {
|
||||
return &FakeGethClient{
|
||||
receipts: make(map[string]*types.Receipt),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +51,9 @@ func (client *FakeGethClient) AddReceipts(receipts []*types.Receipt) {
|
||||
}
|
||||
|
||||
func (client *FakeGethClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
||||
if err, ok := client.err.(TransActionReceiptError); ok {
|
||||
return &types.Receipt{}, err
|
||||
}
|
||||
if gasUsed, ok := client.receipts[txHash.Hex()]; ok {
|
||||
return gasUsed, nil
|
||||
}
|
||||
@@ -37,6 +61,9 @@ func (client *FakeGethClient) TransactionReceipt(ctx context.Context, txHash com
|
||||
}
|
||||
|
||||
func (client *FakeGethClient) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) {
|
||||
if err, ok := client.err.(TransactionSenderError); ok {
|
||||
return common.Address{}, err
|
||||
}
|
||||
return common.HexToAddress("0x123"), nil
|
||||
}
|
||||
|
||||
@@ -66,8 +93,9 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
}
|
||||
block := types.NewBlock(&header, []*types.Transaction{}, []*types.Header{}, []*types.Receipt{})
|
||||
client := &FakeGethClient{}
|
||||
gethBlock := geth.ToCoreBlock(block, client)
|
||||
gethBlock, err := geth.ToCoreBlock(block, client)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(gethBlock.Difficulty).To(Equal(difficulty.Int64()))
|
||||
Expect(gethBlock.GasLimit).To(Equal(gasLimit))
|
||||
Expect(gethBlock.Miner).To(Equal(miner.Hex()))
|
||||
@@ -104,7 +132,7 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
}
|
||||
receipts := []*types.Receipt{&receipt}
|
||||
|
||||
client := NewFakeClient()
|
||||
client := NewFakeClient(nil)
|
||||
client.AddReceipts(receipts)
|
||||
|
||||
number := int64(1071819)
|
||||
@@ -113,8 +141,9 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
}
|
||||
uncles := []*types.Header{{Number: big.NewInt(1071817)}, {Number: big.NewInt(1071818)}}
|
||||
block := types.NewBlock(&header, transactions, uncles, []*types.Receipt{&receipt})
|
||||
coreBlock := geth.ToCoreBlock(block, client)
|
||||
coreBlock, err := geth.ToCoreBlock(block, client)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(geth.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(5.31355))
|
||||
})
|
||||
|
||||
@@ -144,11 +173,12 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
}
|
||||
block := types.NewBlock(&header, transactions, uncles, receipts)
|
||||
|
||||
client := NewFakeClient()
|
||||
client := NewFakeClient(nil)
|
||||
client.AddReceipts(receipts)
|
||||
|
||||
coreBlock := geth.ToCoreBlock(block, client)
|
||||
coreBlock, err := geth.ToCoreBlock(block, client)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(geth.CalcUnclesReward(coreBlock, block.Uncles())).To(Equal(6.875))
|
||||
})
|
||||
|
||||
@@ -190,10 +220,11 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
var uncles []*types.Header
|
||||
block := types.NewBlock(&header, transactions, uncles, receipts)
|
||||
|
||||
client := NewFakeClient()
|
||||
client := NewFakeClient(nil)
|
||||
client.AddReceipts(receipts)
|
||||
coreBlock := geth.ToCoreBlock(block, client)
|
||||
coreBlock, err := geth.ToCoreBlock(block, client)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(geth.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(3.024990672))
|
||||
})
|
||||
})
|
||||
@@ -203,8 +234,9 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
header := types.Header{}
|
||||
block := types.NewBlock(&header, []*types.Transaction{}, []*types.Header{}, []*types.Receipt{})
|
||||
client := &FakeGethClient{}
|
||||
coreBlock := geth.ToCoreBlock(block, client)
|
||||
coreBlock, err := geth.ToCoreBlock(block, client)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(coreBlock.Transactions)).To(Equal(0))
|
||||
})
|
||||
|
||||
@@ -227,7 +259,7 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
TxHash: gethTransaction.Hash(),
|
||||
}
|
||||
|
||||
client := NewFakeClient()
|
||||
client := NewFakeClient(nil)
|
||||
client.AddReceipts([]*types.Receipt{gethReceipt})
|
||||
|
||||
header := types.Header{}
|
||||
@@ -237,8 +269,9 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
[]*types.Header{},
|
||||
[]*types.Receipt{gethReceipt},
|
||||
)
|
||||
coreBlock := geth.ToCoreBlock(gethBlock, client)
|
||||
coreBlock, err := geth.ToCoreBlock(gethBlock, client)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(coreBlock.Transactions)).To(Equal(1))
|
||||
coreTransaction := coreBlock.Transactions[0]
|
||||
Expect(coreTransaction.Data).To(Equal("0xf7d8c8830000000000000000000000000000000000000000000000000000000000037788000000000000000000000000000000000000000000000000000000000003bd14"))
|
||||
@@ -271,7 +304,7 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
ContractAddress: common.HexToAddress("0x1023342345"),
|
||||
}
|
||||
|
||||
client := NewFakeClient()
|
||||
client := NewFakeClient(nil)
|
||||
client.AddReceipts([]*types.Receipt{gethReceipt})
|
||||
|
||||
gethBlock := types.NewBlock(
|
||||
@@ -281,8 +314,9 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
[]*types.Receipt{gethReceipt},
|
||||
)
|
||||
|
||||
coreBlock := geth.ToCoreBlock(gethBlock, client)
|
||||
coreBlock, err := geth.ToCoreBlock(gethBlock, client)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
coreTransaction := coreBlock.Transactions[0]
|
||||
Expect(coreTransaction.To).To(Equal(""))
|
||||
|
||||
@@ -292,4 +326,50 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Describe("transaction error handling", func() {
|
||||
var gethTransaction *types.Transaction
|
||||
var gethReceipt *types.Receipt
|
||||
var header *types.Header
|
||||
var gethBlock *types.Block
|
||||
|
||||
BeforeEach(func() {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
gethTransaction = types.NewTransaction(
|
||||
uint64(0),
|
||||
common.Address{},
|
||||
big.NewInt(0),
|
||||
uint64(0),
|
||||
big.NewInt(0),
|
||||
[]byte{},
|
||||
)
|
||||
gethReceipt = &types.Receipt{}
|
||||
header = &types.Header{}
|
||||
gethBlock = types.NewBlock(
|
||||
header,
|
||||
[]*types.Transaction{gethTransaction},
|
||||
[]*types.Header{},
|
||||
[]*types.Receipt{gethReceipt},
|
||||
)
|
||||
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
defer log.SetOutput(os.Stdout)
|
||||
})
|
||||
|
||||
It("returns an error when transaction sender call fails", func() {
|
||||
client := NewFakeClient(TransactionSenderError{})
|
||||
client.AddReceipts([]*types.Receipt{})
|
||||
_, err := geth.ToCoreBlock(gethBlock, client)
|
||||
Expect(err).To(Equal(TransactionSenderError{}))
|
||||
})
|
||||
|
||||
It("returns an error when transaction receipt call fails", func() {
|
||||
client := NewFakeClient(TransActionReceiptError{})
|
||||
client.AddReceipts([]*types.Receipt{})
|
||||
_, err := geth.ToCoreBlock(gethBlock, client)
|
||||
Expect(err).To(Equal(TransActionReceiptError{}))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
+10
-3
@@ -58,9 +58,16 @@ func (blockchain *Blockchain) Node() core.Node {
|
||||
return blockchain.node
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) GetBlockByNumber(blockNumber int64) core.Block {
|
||||
gethBlock, _ := blockchain.client.BlockByNumber(context.Background(), big.NewInt(blockNumber))
|
||||
return ToCoreBlock(gethBlock, blockchain.client)
|
||||
func (blockchain *Blockchain) GetBlockByNumber(blockNumber int64) (core.Block, error) {
|
||||
gethBlock, err := blockchain.client.BlockByNumber(context.Background(), big.NewInt(blockNumber))
|
||||
if err != nil {
|
||||
return core.Block{}, err
|
||||
}
|
||||
block, err := ToCoreBlock(gethBlock, blockchain.client)
|
||||
if err != nil {
|
||||
return core.Block{}, err
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func (blockchain *Blockchain) LastBlock() *big.Int {
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
|
||||
"strings"
|
||||
|
||||
"log"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
@@ -79,7 +81,10 @@ func MakeNode(wrapper ClientWrapper) core.Node {
|
||||
|
||||
func (client ClientWrapper) NetworkId() float64 {
|
||||
var version string
|
||||
client.CallContext(context.Background(), &version, "net_version")
|
||||
err := client.CallContext(context.Background(), &version, "net_version")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
networkId, _ := strconv.ParseFloat(version, 64)
|
||||
return networkId
|
||||
}
|
||||
|
||||
@@ -4,9 +4,15 @@ import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
func TestHistory(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "History Suite")
|
||||
|
||||
@@ -18,7 +18,11 @@ func PopulateMissingBlocks(blockchain core.Blockchain, blockRepository datastore
|
||||
|
||||
func RetrieveAndUpdateBlocks(blockchain core.Blockchain, blockRepository datastore.BlockRepository, blockNumbers []int64) int {
|
||||
for _, blockNumber := range blockNumbers {
|
||||
block := blockchain.GetBlockByNumber(blockNumber)
|
||||
block, err := blockchain.GetBlockByNumber(blockNumber)
|
||||
if err != nil {
|
||||
log.Printf("failed to retrieve block number: %d\n", blockNumber)
|
||||
return 0
|
||||
}
|
||||
blockRepository.CreateOrUpdateBlock(block)
|
||||
}
|
||||
return len(blockNumbers)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package history_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
@@ -100,4 +102,12 @@ var _ = Describe("Populating blocks", func() {
|
||||
Expect(blockRepository.CreateOrUpdateBlockCallCount).To(Equal(3))
|
||||
})
|
||||
|
||||
It("does not call repository create block when there is an error", func() {
|
||||
blockchain := fakes.NewBlockchain(errors.New("error getting block"))
|
||||
blocks := history.MakeRange(1, 10)
|
||||
history.RetrieveAndUpdateBlocks(blockchain, blockRepository, blocks)
|
||||
Expect(blockRepository.BlockCount()).To(Equal(0))
|
||||
Expect(blockRepository.CreateOrUpdateBlockCallCount).To(Equal(0))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@@ -3,9 +3,6 @@ package history_test
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
@@ -14,10 +11,6 @@ import (
|
||||
"github.com/vulcanize/vulcanizedb/pkg/history"
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
var _ = Describe("Blocks validator", func() {
|
||||
|
||||
It("creates a ValidationWindow equal to (HEAD-windowSize, HEAD)", func() {
|
||||
|
||||
Reference in New Issue
Block a user