forked from cerc-io/ipld-eth-server
Add cold import script
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package ethereum
|
||||
|
||||
type DatabaseType int
|
||||
|
||||
const (
|
||||
Level DatabaseType = iota
|
||||
)
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Type DatabaseType
|
||||
Path string
|
||||
}
|
||||
|
||||
func CreateDatabaseConfig(dbType DatabaseType, path string) DatabaseConfig {
|
||||
return DatabaseConfig{
|
||||
Type: dbType,
|
||||
Path: path,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package ethereum
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/ethereum/level"
|
||||
)
|
||||
|
||||
type Database interface {
|
||||
GetBlock(hash []byte, blockNumber int64) *types.Block
|
||||
GetBlockHash(blockNumber int64) []byte
|
||||
GetBlockReceipts(blockHash []byte, blockNumber int64) types.Receipts
|
||||
}
|
||||
|
||||
func CreateDatabase(config DatabaseConfig) (Database, error) {
|
||||
switch config.Type {
|
||||
case Level:
|
||||
levelDBConnection, err := ethdb.NewLDBDatabase(config.Path, 128, 1024)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
levelDBReader := level.NewLevelDatabaseReader(levelDBConnection)
|
||||
levelDB := level.NewLevelDatabase(levelDBReader)
|
||||
return levelDB, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown ethereum database: %s", config.Path)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package level
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
type LevelDatabase struct {
|
||||
reader Reader
|
||||
}
|
||||
|
||||
func NewLevelDatabase(ldbReader Reader) *LevelDatabase {
|
||||
return &LevelDatabase{
|
||||
reader: ldbReader,
|
||||
}
|
||||
}
|
||||
|
||||
func (l LevelDatabase) GetBlock(blockHash []byte, blockNumber int64) *types.Block {
|
||||
n := uint64(blockNumber)
|
||||
h := common.BytesToHash(blockHash)
|
||||
return l.reader.GetBlock(h, n)
|
||||
}
|
||||
|
||||
func (l LevelDatabase) GetBlockHash(blockNumber int64) []byte {
|
||||
n := uint64(blockNumber)
|
||||
h := l.reader.GetCanonicalHash(n)
|
||||
return h.Bytes()
|
||||
}
|
||||
|
||||
func (l LevelDatabase) GetBlockReceipts(blockHash []byte, blockNumber int64) types.Receipts {
|
||||
n := uint64(blockNumber)
|
||||
h := common.BytesToHash(blockHash)
|
||||
return l.reader.GetBlockReceipts(h, n)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package level
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
type Reader interface {
|
||||
GetBlock(hash common.Hash, number uint64) *types.Block
|
||||
GetBlockReceipts(hash common.Hash, number uint64) types.Receipts
|
||||
GetCanonicalHash(number uint64) common.Hash
|
||||
}
|
||||
|
||||
type LevelDatabaseReader struct {
|
||||
core.DatabaseReader
|
||||
}
|
||||
|
||||
func NewLevelDatabaseReader(reader core.DatabaseReader) *LevelDatabaseReader {
|
||||
return &LevelDatabaseReader{DatabaseReader: reader}
|
||||
}
|
||||
|
||||
func (ldbr *LevelDatabaseReader) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return core.GetBlock(ldbr.DatabaseReader, hash, number)
|
||||
}
|
||||
|
||||
func (ldbr *LevelDatabaseReader) GetBlockReceipts(hash common.Hash, number uint64) types.Receipts {
|
||||
return core.GetBlockReceipts(ldbr.DatabaseReader, hash, number)
|
||||
}
|
||||
|
||||
func (ldbr *LevelDatabaseReader) GetCanonicalHash(number uint64) common.Hash {
|
||||
return core.GetCanonicalHash(ldbr.DatabaseReader, number)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package level_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
. "github.com/onsi/ginkgo"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/ethereum/level"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||
)
|
||||
|
||||
var _ = Describe("Level database", func() {
|
||||
Describe("Getting a block hash", func() {
|
||||
It("converts block number to uint64 to fetch hash from reader", func() {
|
||||
mockReader := fakes.NewMockLevelDatabaseReader()
|
||||
ldb := level.NewLevelDatabase(mockReader)
|
||||
blockNumber := int64(12345)
|
||||
|
||||
ldb.GetBlockHash(blockNumber)
|
||||
|
||||
expectedBlockNumber := uint64(blockNumber)
|
||||
mockReader.AssertGetCanonicalHashCalledWith(expectedBlockNumber)
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Getting a block", func() {
|
||||
It("converts block number to uint64 and hash to common.Hash to fetch block from reader", func() {
|
||||
mockReader := fakes.NewMockLevelDatabaseReader()
|
||||
ldb := level.NewLevelDatabase(mockReader)
|
||||
blockHash := []byte{5, 4, 3, 2, 1}
|
||||
blockNumber := int64(12345)
|
||||
|
||||
ldb.GetBlock(blockHash, blockNumber)
|
||||
|
||||
expectedBlockHash := common.BytesToHash(blockHash)
|
||||
expectedBlockNumber := uint64(blockNumber)
|
||||
mockReader.AssertGetBlockCalledWith(expectedBlockHash, expectedBlockNumber)
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Getting a block's receipts", func() {
|
||||
It("converts block number to uint64 and hash to common.Hash to fetch receipts from reader", func() {
|
||||
mockReader := fakes.NewMockLevelDatabaseReader()
|
||||
ldb := level.NewLevelDatabase(mockReader)
|
||||
blockHash := []byte{5, 4, 3, 2, 1}
|
||||
blockNumber := int64(12345)
|
||||
|
||||
ldb.GetBlockReceipts(blockHash, blockNumber)
|
||||
|
||||
expectedBlockHash := common.BytesToHash(blockHash)
|
||||
expectedBlockNumber := uint64(blockNumber)
|
||||
mockReader.AssertGetBlockReceiptsCalledWith(expectedBlockHash, expectedBlockNumber)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
package level_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestLevel(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Level Suite")
|
||||
}
|
||||
@@ -9,14 +9,14 @@ type BlockRepository struct {
|
||||
*InMemory
|
||||
}
|
||||
|
||||
func (blockRepository *BlockRepository) CreateOrUpdateBlock(block core.Block) error {
|
||||
func (blockRepository *BlockRepository) CreateOrUpdateBlock(block core.Block) (int64, error) {
|
||||
blockRepository.CreateOrUpdateBlockCallCount++
|
||||
blockRepository.blocks[block.Number] = block
|
||||
for _, transaction := range block.Transactions {
|
||||
blockRepository.receipts[transaction.Hash] = transaction.Receipt
|
||||
blockRepository.logs[transaction.TxHash] = transaction.Logs
|
||||
}
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (blockRepository *BlockRepository) GetBlock(blockNumber int64) (core.Block, error) {
|
||||
|
||||
@@ -23,7 +23,9 @@ var _ = Describe("Postgres DB", func() {
|
||||
It("connects to the database", func() {
|
||||
var err error
|
||||
pgConfig := config.DbConnectionString(test_config.DBConfig)
|
||||
|
||||
sqlxdb, err = sqlx.Connect("postgres", pgConfig)
|
||||
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(sqlxdb).ShouldNot(BeNil())
|
||||
})
|
||||
@@ -76,10 +78,10 @@ var _ = Describe("Postgres DB", func() {
|
||||
db := test_config.NewTestDB(node)
|
||||
blocksRepository := repositories.BlockRepository{DB: db}
|
||||
|
||||
err1 := blocksRepository.CreateOrUpdateBlock(badBlock)
|
||||
savedBlock, err2 := blocksRepository.GetBlock(123)
|
||||
_, err1 := blocksRepository.CreateOrUpdateBlock(badBlock)
|
||||
|
||||
Expect(err1).To(HaveOccurred())
|
||||
savedBlock, err2 := blocksRepository.GetBlock(123)
|
||||
Expect(err2).To(HaveOccurred())
|
||||
Expect(savedBlock).To(BeZero())
|
||||
})
|
||||
@@ -87,7 +89,9 @@ var _ = Describe("Postgres DB", func() {
|
||||
It("throws error when can't connect to the database", func() {
|
||||
invalidDatabase := config.Database{}
|
||||
node := core.Node{GenesisBlock: "GENESIS", NetworkID: 1, ID: "x123", ClientName: "geth"}
|
||||
|
||||
_, err := postgres.NewDB(invalidDatabase, node)
|
||||
|
||||
Expect(err).To(Equal(postgres.ErrDBConnectionFailed))
|
||||
})
|
||||
|
||||
@@ -110,10 +114,10 @@ var _ = Describe("Postgres DB", func() {
|
||||
db, _ := postgres.NewDB(test_config.DBConfig, node)
|
||||
logRepository := repositories.LogRepository{DB: db}
|
||||
|
||||
err := logRepository.CreateLogs([]core.Log{badLog})
|
||||
savedBlock := logRepository.GetLogs("x123", 1)
|
||||
err := logRepository.CreateLogs([]core.Log{badLog}, 123)
|
||||
|
||||
Expect(err).ToNot(BeNil())
|
||||
savedBlock := logRepository.GetLogs("x123", 1)
|
||||
Expect(savedBlock).To(BeNil())
|
||||
})
|
||||
|
||||
@@ -129,12 +133,11 @@ var _ = Describe("Postgres DB", func() {
|
||||
db, _ := postgres.NewDB(test_config.DBConfig, node)
|
||||
blockRepository := repositories.BlockRepository{DB: db}
|
||||
|
||||
err1 := blockRepository.CreateOrUpdateBlock(block)
|
||||
savedBlock, err2 := blockRepository.GetBlock(123)
|
||||
_, err1 := blockRepository.CreateOrUpdateBlock(block)
|
||||
|
||||
Expect(err1).To(HaveOccurred())
|
||||
savedBlock, err2 := blockRepository.GetBlock(123)
|
||||
Expect(err2).To(HaveOccurred())
|
||||
Expect(savedBlock).To(BeZero())
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@@ -3,10 +3,11 @@ package repositories
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
@@ -16,6 +17,8 @@ const (
|
||||
blocksFromHeadBeforeFinal = 20
|
||||
)
|
||||
|
||||
var ErrBlockExists = errors.New("Won't add block that already exists.")
|
||||
|
||||
type BlockRepository struct {
|
||||
*postgres.DB
|
||||
}
|
||||
@@ -28,22 +31,21 @@ func (blockRepository BlockRepository) SetBlocksStatus(chainHead int64) {
|
||||
cutoff)
|
||||
}
|
||||
|
||||
func (blockRepository BlockRepository) CreateOrUpdateBlock(block core.Block) error {
|
||||
func (blockRepository BlockRepository) CreateOrUpdateBlock(block core.Block) (int64, error) {
|
||||
var err error
|
||||
var blockId int64
|
||||
retrievedBlockHash, ok := blockRepository.getBlockHash(block)
|
||||
if !ok {
|
||||
err = blockRepository.insertBlock(block)
|
||||
return err
|
||||
return blockRepository.insertBlock(block)
|
||||
}
|
||||
if ok && retrievedBlockHash != block.Hash {
|
||||
err = blockRepository.removeBlock(block.Number)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
err = blockRepository.insertBlock(block)
|
||||
return err
|
||||
return blockRepository.insertBlock(block)
|
||||
}
|
||||
return nil
|
||||
return blockId, ErrBlockExists
|
||||
}
|
||||
|
||||
func (blockRepository BlockRepository) MissingBlockNumbers(startingBlockNumber int64, highestBlockNumber int64) []int64 {
|
||||
@@ -92,7 +94,7 @@ func (blockRepository BlockRepository) GetBlock(blockNumber int64) (core.Block,
|
||||
return savedBlock, nil
|
||||
}
|
||||
|
||||
func (blockRepository BlockRepository) insertBlock(block core.Block) error {
|
||||
func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, error) {
|
||||
var blockId int64
|
||||
tx, _ := blockRepository.DB.BeginTx(context.Background(), nil)
|
||||
err := tx.QueryRow(
|
||||
@@ -104,15 +106,17 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) error {
|
||||
Scan(&blockId)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return postgres.ErrDBInsertFailed
|
||||
return 0, postgres.ErrDBInsertFailed
|
||||
}
|
||||
err = blockRepository.createTransactions(tx, blockId, block.Transactions)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return postgres.ErrDBInsertFailed
|
||||
if len(block.Transactions) > 0 {
|
||||
err = blockRepository.createTransactions(tx, blockId, block.Transactions)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return 0, postgres.ErrDBInsertFailed
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
return blockId, nil
|
||||
}
|
||||
|
||||
func (blockRepository BlockRepository) createTransactions(tx *sql.Tx, blockId int64, transactions []core.Transaction) error {
|
||||
|
||||
@@ -177,6 +177,22 @@ var _ = Describe("Saving blocks", func() {
|
||||
Expect(retrievedBlockTwo.Transactions[0].Hash).To(Equal("x678"))
|
||||
})
|
||||
|
||||
It("returns 'block exists' error if attempting to add duplicate block", func() {
|
||||
block := core.Block{
|
||||
Number: 12345,
|
||||
Hash: "0x12345",
|
||||
}
|
||||
|
||||
_, err := blockRepository.CreateOrUpdateBlock(block)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
_, err = blockRepository.CreateOrUpdateBlock(block)
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(repositories.ErrBlockExists))
|
||||
})
|
||||
|
||||
It("saves the attributes associated to a transaction", func() {
|
||||
gasLimit := uint64(5000)
|
||||
gasPrice := int64(3)
|
||||
|
||||
@@ -13,14 +13,14 @@ type LogRepository struct {
|
||||
*postgres.DB
|
||||
}
|
||||
|
||||
func (logRepository LogRepository) CreateLogs(lgs []core.Log) error {
|
||||
func (logRepository LogRepository) CreateLogs(lgs []core.Log, receiptId int64) error {
|
||||
tx, _ := logRepository.DB.BeginTx(context.Background(), nil)
|
||||
for _, tlog := range lgs {
|
||||
_, err := tx.Exec(
|
||||
`INSERT INTO logs (block_number, address, tx_hash, index, topic0, topic1, topic2, topic3, data)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
`INSERT INTO logs (block_number, address, tx_hash, index, topic0, topic1, topic2, topic3, data, receipt_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
`,
|
||||
tlog.BlockNumber, tlog.Address, tlog.TxHash, tlog.Index, tlog.Topics[0], tlog.Topics[1], tlog.Topics[2], tlog.Topics[3], tlog.Data,
|
||||
tlog.BlockNumber, tlog.Address, tlog.TxHash, tlog.Index, tlog.Topics[0], tlog.Topics[1], tlog.Topics[2], tlog.Topics[3], tlog.Data, receiptId,
|
||||
)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
|
||||
@@ -13,36 +13,45 @@ import (
|
||||
)
|
||||
|
||||
var _ = Describe("Logs Repository", func() {
|
||||
var db *postgres.DB
|
||||
var logsRepository datastore.LogRepository
|
||||
var node core.Node
|
||||
BeforeEach(func() {
|
||||
node = core.Node{
|
||||
GenesisBlock: "GENESIS",
|
||||
NetworkID: 1,
|
||||
ID: "b6f90c0fdd8ec9607aed8ee45c69322e47b7063f0bfb7a29c8ecafab24d0a22d24dd2329b5ee6ed4125a03cb14e57fd584e67f9e53e6c631055cbbd82f080845",
|
||||
ClientName: "Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9",
|
||||
}
|
||||
db = test_config.NewTestDB(node)
|
||||
logsRepository = repositories.LogRepository{DB: db}
|
||||
})
|
||||
|
||||
Describe("Saving logs", func() {
|
||||
var db *postgres.DB
|
||||
var blockRepository datastore.BlockRepository
|
||||
var logsRepository datastore.LogRepository
|
||||
var receiptRepository datastore.ReceiptRepository
|
||||
var node core.Node
|
||||
|
||||
BeforeEach(func() {
|
||||
node = core.Node{
|
||||
GenesisBlock: "GENESIS",
|
||||
NetworkID: 1,
|
||||
ID: "b6f90c0fdd8ec9607aed8ee45c69322e47b7063f0bfb7a29c8ecafab24d0a22d24dd2329b5ee6ed4125a03cb14e57fd584e67f9e53e6c631055cbbd82f080845",
|
||||
ClientName: "Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9",
|
||||
}
|
||||
db = test_config.NewTestDB(node)
|
||||
blockRepository = repositories.BlockRepository{DB: db}
|
||||
logsRepository = repositories.LogRepository{DB: db}
|
||||
receiptRepository = repositories.ReceiptRepository{DB: db}
|
||||
})
|
||||
|
||||
It("returns the log when it exists", func() {
|
||||
blockNumber := int64(12345)
|
||||
blockId, err := blockRepository.CreateOrUpdateBlock(core.Block{Number: blockNumber})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
receiptId, err := receiptRepository.CreateReceipt(blockId, core.Receipt{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
logsRepository.CreateLogs([]core.Log{{
|
||||
BlockNumber: 1,
|
||||
BlockNumber: blockNumber,
|
||||
Index: 0,
|
||||
Address: "x123",
|
||||
TxHash: "x456",
|
||||
Topics: core.Topics{0: "x777", 1: "x888", 2: "x999"},
|
||||
Data: "xabc",
|
||||
}},
|
||||
)
|
||||
}}, receiptId)
|
||||
|
||||
log := logsRepository.GetLogs("x123", 1)
|
||||
log := logsRepository.GetLogs("x123", blockNumber)
|
||||
|
||||
Expect(log).NotTo(BeNil())
|
||||
Expect(log[0].BlockNumber).To(Equal(int64(1)))
|
||||
Expect(log[0].BlockNumber).To(Equal(blockNumber))
|
||||
Expect(log[0].Address).To(Equal("x123"))
|
||||
Expect(log[0].Index).To(Equal(int64(0)))
|
||||
Expect(log[0].TxHash).To(Equal("x456"))
|
||||
@@ -58,24 +67,27 @@ var _ = Describe("Logs Repository", func() {
|
||||
})
|
||||
|
||||
It("filters to the correct block number and address", func() {
|
||||
blockNumber := int64(12345)
|
||||
blockId, err := blockRepository.CreateOrUpdateBlock(core.Block{Number: blockNumber})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
receiptId, err := receiptRepository.CreateReceipt(blockId, core.Receipt{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
logsRepository.CreateLogs([]core.Log{{
|
||||
BlockNumber: 1,
|
||||
BlockNumber: blockNumber,
|
||||
Index: 0,
|
||||
Address: "x123",
|
||||
TxHash: "x456",
|
||||
Topics: core.Topics{0: "x777", 1: "x888", 2: "x999"},
|
||||
Data: "xabc",
|
||||
}},
|
||||
)
|
||||
}}, receiptId)
|
||||
logsRepository.CreateLogs([]core.Log{{
|
||||
BlockNumber: 1,
|
||||
BlockNumber: blockNumber,
|
||||
Index: 1,
|
||||
Address: "x123",
|
||||
TxHash: "x789",
|
||||
Topics: core.Topics{0: "x111", 1: "x222", 2: "x333"},
|
||||
Data: "xdef",
|
||||
}},
|
||||
)
|
||||
}}, receiptId)
|
||||
logsRepository.CreateLogs([]core.Log{{
|
||||
BlockNumber: 2,
|
||||
Index: 0,
|
||||
@@ -83,10 +95,9 @@ var _ = Describe("Logs Repository", func() {
|
||||
TxHash: "x456",
|
||||
Topics: core.Topics{0: "x777", 1: "x888", 2: "x999"},
|
||||
Data: "xabc",
|
||||
}},
|
||||
)
|
||||
}}, receiptId)
|
||||
|
||||
log := logsRepository.GetLogs("x123", 1)
|
||||
log := logsRepository.GetLogs("x123", blockNumber)
|
||||
|
||||
type logIndex struct {
|
||||
blockNumber int64
|
||||
@@ -111,14 +122,12 @@ var _ = Describe("Logs Repository", func() {
|
||||
Expect(len(log)).To(Equal(2))
|
||||
Expect(uniqueBlockNumbers).To(Equal(
|
||||
[]logIndex{
|
||||
{blockNumber: 1, Index: 0},
|
||||
{blockNumber: 1, Index: 1}},
|
||||
{blockNumber: blockNumber, Index: 0},
|
||||
{blockNumber: blockNumber, Index: 1}},
|
||||
))
|
||||
})
|
||||
|
||||
It("saves the logs attached to a receipt", func() {
|
||||
var blockRepository datastore.BlockRepository
|
||||
blockRepository = repositories.BlockRepository{DB: db}
|
||||
|
||||
logs := []core.Log{{
|
||||
Address: "0x8a4774fe82c63484afef97ca8d89a6ea5e21f973",
|
||||
@@ -171,7 +180,7 @@ var _ = Describe("Logs Repository", func() {
|
||||
}
|
||||
|
||||
block := core.Block{Transactions: []core.Transaction{transaction}}
|
||||
err := blockRepository.CreateOrUpdateBlock(block)
|
||||
_, err := blockRepository.CreateOrUpdateBlock(block)
|
||||
Expect(err).To(Not(HaveOccurred()))
|
||||
retrievedLogs := logsRepository.GetLogs("0x99041f808d598b782d5a3e498681c2452a31da08", 4745407)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
@@ -12,6 +13,73 @@ type ReceiptRepository struct {
|
||||
*postgres.DB
|
||||
}
|
||||
|
||||
func (receiptRepository ReceiptRepository) CreateReceiptsAndLogs(blockId int64, receipts []core.Receipt) error {
|
||||
tx, err := receiptRepository.DB.BeginTx(context.Background(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, receipt := range receipts {
|
||||
receiptId, err := createReceipt(receipt, blockId, tx)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if len(receipt.Logs) > 0 {
|
||||
err = createLogs(receipt.Logs, receiptId, tx)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func createReceipt(receipt core.Receipt, blockId int64, tx *sql.Tx) (int64, error) {
|
||||
var receiptId int64
|
||||
err := tx.QueryRow(
|
||||
`INSERT INTO receipts
|
||||
(contract_address, tx_hash, cumulative_gas_used, gas_used, state_root, status, block_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id`,
|
||||
receipt.ContractAddress, receipt.TxHash, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, blockId,
|
||||
).Scan(&receiptId)
|
||||
return receiptId, err
|
||||
}
|
||||
|
||||
func createLogs(logs []core.Log, receiptId int64, tx *sql.Tx) error {
|
||||
for _, log := range logs {
|
||||
_, err := tx.Exec(
|
||||
`INSERT INTO logs (block_number, address, tx_hash, index, topic0, topic1, topic2, topic3, data, receipt_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
`,
|
||||
log.BlockNumber, log.Address, log.TxHash, log.Index, log.Topics[0], log.Topics[1], log.Topics[2], log.Topics[3], log.Data, receiptId,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (receiptRepository ReceiptRepository) CreateReceipt(blockId int64, receipt core.Receipt) (int64, error) {
|
||||
tx, _ := receiptRepository.DB.BeginTx(context.Background(), nil)
|
||||
var receiptId int64
|
||||
err := tx.QueryRow(
|
||||
`INSERT INTO receipts
|
||||
(contract_address, tx_hash, cumulative_gas_used, gas_used, state_root, status, block_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id`,
|
||||
receipt.ContractAddress, receipt.TxHash, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.StateRoot, receipt.Status, blockId).Scan(&receiptId)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return receiptId, err
|
||||
}
|
||||
tx.Commit()
|
||||
return receiptId, nil
|
||||
}
|
||||
|
||||
func (receiptRepository ReceiptRepository) GetReceipt(txHash string) (core.Receipt, error) {
|
||||
row := receiptRepository.DB.QueryRow(
|
||||
`SELECT contract_address,
|
||||
|
||||
@@ -10,7 +10,9 @@ import (
|
||||
"github.com/vulcanize/vulcanizedb/test_config"
|
||||
)
|
||||
|
||||
var _ bool = Describe("Logs Repository", func() {
|
||||
var _ = Describe("Logs Repository", func() {
|
||||
var blockRepository datastore.BlockRepository
|
||||
var logRepository datastore.LogRepository
|
||||
var receiptRepository datastore.ReceiptRepository
|
||||
var db *postgres.DB
|
||||
var node core.Node
|
||||
@@ -22,14 +24,67 @@ var _ bool = Describe("Logs Repository", func() {
|
||||
ClientName: "Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9",
|
||||
}
|
||||
db = test_config.NewTestDB(node)
|
||||
blockRepository = repositories.BlockRepository{DB: db}
|
||||
logRepository = repositories.LogRepository{DB: db}
|
||||
receiptRepository = repositories.ReceiptRepository{DB: db}
|
||||
})
|
||||
|
||||
Describe("Saving receipts", func() {
|
||||
Describe("Saving multiple receipts", func() {
|
||||
It("persists each receipt and its logs", func() {
|
||||
blockNumber := int64(1234567)
|
||||
blockId, err := blockRepository.CreateOrUpdateBlock(core.Block{Number: blockNumber})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
txHashOne := "0xTxHashOne"
|
||||
txHashTwo := "0xTxHashTwo"
|
||||
addressOne := "0xAddressOne"
|
||||
addressTwo := "0xAddressTwo"
|
||||
logsOne := []core.Log{{
|
||||
Address: addressOne,
|
||||
BlockNumber: blockNumber,
|
||||
TxHash: txHashOne,
|
||||
}, {
|
||||
Address: addressOne,
|
||||
BlockNumber: blockNumber,
|
||||
TxHash: txHashOne,
|
||||
}}
|
||||
logsTwo := []core.Log{{
|
||||
BlockNumber: blockNumber,
|
||||
TxHash: txHashTwo,
|
||||
Address: addressTwo,
|
||||
}}
|
||||
receiptOne := core.Receipt{
|
||||
Logs: logsOne,
|
||||
TxHash: txHashOne,
|
||||
}
|
||||
receiptTwo := core.Receipt{
|
||||
Logs: logsTwo,
|
||||
TxHash: txHashTwo,
|
||||
}
|
||||
receipts := []core.Receipt{receiptOne, receiptTwo}
|
||||
|
||||
err = receiptRepository.CreateReceiptsAndLogs(blockId, receipts)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
persistedReceiptOne, err := receiptRepository.GetReceipt(txHashOne)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(persistedReceiptOne).NotTo(BeNil())
|
||||
Expect(persistedReceiptOne.TxHash).To(Equal(txHashOne))
|
||||
persistedReceiptTwo, err := receiptRepository.GetReceipt(txHashTwo)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(persistedReceiptTwo).NotTo(BeNil())
|
||||
Expect(persistedReceiptTwo.TxHash).To(Equal(txHashTwo))
|
||||
persistedAddressOneLogs := logRepository.GetLogs(addressOne, blockNumber)
|
||||
Expect(persistedAddressOneLogs).NotTo(BeNil())
|
||||
Expect(len(persistedAddressOneLogs)).To(Equal(2))
|
||||
persistedAddressTwoLogs := logRepository.GetLogs(addressTwo, blockNumber)
|
||||
Expect(persistedAddressTwoLogs).NotTo(BeNil())
|
||||
Expect(len(persistedAddressTwoLogs)).To(Equal(1))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Saving receipts on a block's transactions", func() {
|
||||
It("returns the receipt when it exists", func() {
|
||||
var blockRepository datastore.BlockRepository
|
||||
db := test_config.NewTestDB(node)
|
||||
blockRepository = repositories.BlockRepository{DB: db}
|
||||
expected := core.Receipt{
|
||||
ContractAddress: "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
|
||||
CumulativeGasUsed: 7996119,
|
||||
@@ -66,9 +121,6 @@ var _ bool = Describe("Logs Repository", func() {
|
||||
})
|
||||
|
||||
It("still saves receipts without logs", func() {
|
||||
var blockRepository datastore.BlockRepository
|
||||
db := test_config.NewTestDB(node)
|
||||
blockRepository = repositories.BlockRepository{DB: db}
|
||||
receipt := core.Receipt{
|
||||
TxHash: "0x002c4799161d809b23f67884eb6598c9df5894929fe1a9ead97ca175d360f547",
|
||||
}
|
||||
|
||||
@@ -13,14 +13,18 @@ import (
|
||||
|
||||
var _ = Describe("Watched Events Repository", func() {
|
||||
var db *postgres.DB
|
||||
var logRepository datastore.LogRepository
|
||||
var blocksRepository datastore.BlockRepository
|
||||
var filterRepository datastore.FilterRepository
|
||||
var logRepository datastore.LogRepository
|
||||
var receiptRepository datastore.ReceiptRepository
|
||||
var watchedEventRepository datastore.WatchedEventRepository
|
||||
|
||||
BeforeEach(func() {
|
||||
db = test_config.NewTestDB(core.Node{})
|
||||
logRepository = repositories.LogRepository{DB: db}
|
||||
blocksRepository = repositories.BlockRepository{DB: db}
|
||||
filterRepository = repositories.FilterRepository{DB: db}
|
||||
logRepository = repositories.LogRepository{DB: db}
|
||||
receiptRepository = repositories.ReceiptRepository{DB: db}
|
||||
watchedEventRepository = repositories.WatchedEventRepository{DB: db}
|
||||
})
|
||||
|
||||
@@ -56,7 +60,11 @@ var _ = Describe("Watched Events Repository", func() {
|
||||
}
|
||||
err := filterRepository.CreateFilter(filter)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = logRepository.CreateLogs(logs)
|
||||
blockId, err := blocksRepository.CreateOrUpdateBlock(core.Block{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
receiptId, err := receiptRepository.CreateReceipt(blockId, core.Receipt{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = logRepository.CreateLogs(logs, receiptId)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
matchingLogs, err := watchedEventRepository.GetWatchedEvents("Filter1")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -69,7 +77,6 @@ var _ = Describe("Watched Events Repository", func() {
|
||||
Expect(matchingLogs[0].Topic1).To(Equal(expectedWatchedEventLog[0].Topic1))
|
||||
Expect(matchingLogs[0].Topic2).To(Equal(expectedWatchedEventLog[0].Topic2))
|
||||
Expect(matchingLogs[0].Data).To(Equal(expectedWatchedEventLog[0].Data))
|
||||
|
||||
})
|
||||
|
||||
It("retrieves a watched event log by name", func() {
|
||||
@@ -110,7 +117,11 @@ var _ = Describe("Watched Events Repository", func() {
|
||||
}}
|
||||
err := filterRepository.CreateFilter(filter)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = logRepository.CreateLogs(logs)
|
||||
blockId, err := blocksRepository.CreateOrUpdateBlock(core.Block{Hash: "Ox123"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
receiptId, err := receiptRepository.CreateReceipt(blockId, core.Receipt{TxHash: "0x123"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = logRepository.CreateLogs(logs, receiptId)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
matchingLogs, err := watchedEventRepository.GetWatchedEvents("Filter1")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
@@ -12,7 +12,7 @@ var ErrBlockDoesNotExist = func(blockNumber int64) error {
|
||||
}
|
||||
|
||||
type BlockRepository interface {
|
||||
CreateOrUpdateBlock(block core.Block) error
|
||||
CreateOrUpdateBlock(block core.Block) (int64, error)
|
||||
GetBlock(blockNumber int64) (core.Block, error)
|
||||
MissingBlockNumbers(startingBlockNumber int64, endingBlockNumber int64) []int64
|
||||
SetBlocksStatus(chainHead int64)
|
||||
@@ -38,7 +38,7 @@ type FilterRepository interface {
|
||||
}
|
||||
|
||||
type LogRepository interface {
|
||||
CreateLogs(logs []core.Log) error
|
||||
CreateLogs(logs []core.Log, receiptId int64) error
|
||||
GetLogs(address string, blockNumber int64) []core.Log
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ var ErrReceiptDoesNotExist = func(txHash string) error {
|
||||
}
|
||||
|
||||
type ReceiptRepository interface {
|
||||
CreateReceiptsAndLogs(blockId int64, receipts []core.Receipt) error
|
||||
CreateReceipt(blockId int64, receipt core.Receipt) (int64, error)
|
||||
GetReceipt(txHash string) (core.Receipt, error)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package fakes
|
||||
|
||||
import (
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
)
|
||||
|
||||
type MockBlockRepository struct {
|
||||
createOrUpdateBlockCalled bool
|
||||
createOrUpdateBlockPassedBlock core.Block
|
||||
createOrUpdateBlockReturnInt int64
|
||||
createOrUpdateBlockReturnErr error
|
||||
}
|
||||
|
||||
func NewMockBlockRepository() *MockBlockRepository {
|
||||
return &MockBlockRepository{
|
||||
createOrUpdateBlockCalled: false,
|
||||
createOrUpdateBlockPassedBlock: core.Block{},
|
||||
createOrUpdateBlockReturnInt: 0,
|
||||
createOrUpdateBlockReturnErr: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (mbr *MockBlockRepository) SetCreateOrUpdateBlockReturnVals(i int64, err error) {
|
||||
mbr.createOrUpdateBlockReturnInt = i
|
||||
mbr.createOrUpdateBlockReturnErr = err
|
||||
}
|
||||
|
||||
func (mbr *MockBlockRepository) CreateOrUpdateBlock(block core.Block) (int64, error) {
|
||||
mbr.createOrUpdateBlockCalled = true
|
||||
mbr.createOrUpdateBlockPassedBlock = block
|
||||
return mbr.createOrUpdateBlockReturnInt, mbr.createOrUpdateBlockReturnErr
|
||||
}
|
||||
|
||||
func (mbr *MockBlockRepository) GetBlock(blockNumber int64) (core.Block, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (mbr *MockBlockRepository) MissingBlockNumbers(startingBlockNumber int64, endingBlockNumber int64) []int64 {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (mbr *MockBlockRepository) SetBlocksStatus(chainHead int64) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (mbr *MockBlockRepository) AssertCreateOrUpdateBlockCalledWith(block core.Block) {
|
||||
Expect(mbr.createOrUpdateBlockCalled).To(BeTrue())
|
||||
Expect(mbr.createOrUpdateBlockPassedBlock).To(Equal(block))
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package fakes
|
||||
|
||||
import (
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
type MockEthereumDatabase struct {
|
||||
getBlockCalled bool
|
||||
getBlockPassedHash []byte
|
||||
getBlockPassedNumber int64
|
||||
getBlockReturnBlock *types.Block
|
||||
getBlockHashCalled bool
|
||||
getBlockHashPassedNumber int64
|
||||
getBlockHashReturnHash []byte
|
||||
getBlockReceiptsCalled bool
|
||||
getBlockReceiptsPassedHash []byte
|
||||
getBlockReceiptsPassedNumber int64
|
||||
getBlockReceiptsReturnReceipts types.Receipts
|
||||
}
|
||||
|
||||
func NewMockEthereumDatabase() *MockEthereumDatabase {
|
||||
return &MockEthereumDatabase{
|
||||
getBlockCalled: false,
|
||||
getBlockPassedHash: nil,
|
||||
getBlockPassedNumber: 0,
|
||||
getBlockReturnBlock: nil,
|
||||
getBlockHashCalled: false,
|
||||
getBlockHashPassedNumber: 0,
|
||||
getBlockHashReturnHash: nil,
|
||||
getBlockReceiptsCalled: false,
|
||||
getBlockReceiptsPassedHash: nil,
|
||||
getBlockReceiptsPassedNumber: 0,
|
||||
getBlockReceiptsReturnReceipts: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) SetReturnBlock(block *types.Block) {
|
||||
med.getBlockReturnBlock = block
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) SetReturnHash(hash []byte) {
|
||||
med.getBlockHashReturnHash = hash
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) SetReturnReceipts(receipts types.Receipts) {
|
||||
med.getBlockReceiptsReturnReceipts = receipts
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) GetBlock(hash []byte, blockNumber int64) *types.Block {
|
||||
med.getBlockCalled = true
|
||||
med.getBlockPassedHash = hash
|
||||
med.getBlockPassedNumber = blockNumber
|
||||
return med.getBlockReturnBlock
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) GetBlockHash(blockNumber int64) []byte {
|
||||
med.getBlockHashCalled = true
|
||||
med.getBlockHashPassedNumber = blockNumber
|
||||
return med.getBlockHashReturnHash
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) GetBlockReceipts(blockHash []byte, blockNumber int64) types.Receipts {
|
||||
med.getBlockReceiptsCalled = true
|
||||
med.getBlockReceiptsPassedHash = blockHash
|
||||
med.getBlockReceiptsPassedNumber = blockNumber
|
||||
return med.getBlockReceiptsReturnReceipts
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) AssertGetBlockCalledWith(hash []byte, blockNumber int64) {
|
||||
Expect(med.getBlockCalled).To(BeTrue())
|
||||
Expect(med.getBlockPassedHash).To(Equal(hash))
|
||||
Expect(med.getBlockPassedNumber).To(Equal(blockNumber))
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) AssertGetBlockHashCalledWith(blockNumber int64) {
|
||||
Expect(med.getBlockHashCalled).To(BeTrue())
|
||||
Expect(med.getBlockHashPassedNumber).To(Equal(blockNumber))
|
||||
}
|
||||
|
||||
func (med *MockEthereumDatabase) AssertGetBlockReceiptsCalledWith(blockHash []byte, blockNumber int64) {
|
||||
Expect(med.getBlockReceiptsCalled).To(BeTrue())
|
||||
Expect(med.getBlockReceiptsPassedHash).To(Equal(blockHash))
|
||||
Expect(med.getBlockReceiptsPassedNumber).To(Equal(blockNumber))
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package fakes
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
type MockLevelDatabaseReader struct {
|
||||
getBlockCalled bool
|
||||
getBlockReceiptsCalled bool
|
||||
getCanonicalHashCalled bool
|
||||
passedHash common.Hash
|
||||
getCanonicalHashPassedNumber uint64
|
||||
getBlockPassedHash common.Hash
|
||||
getBlockPassedNumber uint64
|
||||
getBlockReceiptsPassedHash common.Hash
|
||||
getBlockReceiptsPassedNumber uint64
|
||||
returnBlock *types.Block
|
||||
returnHash common.Hash
|
||||
returnReceipts types.Receipts
|
||||
}
|
||||
|
||||
func NewMockLevelDatabaseReader() *MockLevelDatabaseReader {
|
||||
return &MockLevelDatabaseReader{
|
||||
getBlockCalled: false,
|
||||
getBlockReceiptsCalled: false,
|
||||
getCanonicalHashCalled: false,
|
||||
passedHash: common.Hash{},
|
||||
getCanonicalHashPassedNumber: 0,
|
||||
getBlockPassedHash: common.Hash{},
|
||||
getBlockPassedNumber: 0,
|
||||
getBlockReceiptsPassedHash: common.Hash{},
|
||||
getBlockReceiptsPassedNumber: 0,
|
||||
returnBlock: nil,
|
||||
returnHash: common.Hash{},
|
||||
returnReceipts: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) SetReturnBlock(block *types.Block) {
|
||||
mldr.returnBlock = block
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) SetReturnHash(hash common.Hash) {
|
||||
mldr.returnHash = hash
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) SetReturnReceipts(receipts types.Receipts) {
|
||||
mldr.returnReceipts = receipts
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) GetCanonicalHash(number uint64) common.Hash {
|
||||
mldr.getCanonicalHashCalled = true
|
||||
mldr.getCanonicalHashPassedNumber = number
|
||||
return mldr.returnHash
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
mldr.getBlockCalled = true
|
||||
mldr.getBlockPassedHash = hash
|
||||
mldr.getBlockPassedNumber = number
|
||||
return mldr.returnBlock
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) GetBlockReceipts(hash common.Hash, number uint64) types.Receipts {
|
||||
mldr.getBlockReceiptsCalled = true
|
||||
mldr.getBlockReceiptsPassedHash = hash
|
||||
mldr.getBlockReceiptsPassedNumber = number
|
||||
return mldr.returnReceipts
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) AssertGetCanonicalHashCalledWith(number uint64) {
|
||||
Expect(mldr.getCanonicalHashCalled).To(BeTrue())
|
||||
Expect(mldr.getCanonicalHashPassedNumber).To(Equal(number))
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) AssertGetBlockCalledWith(hash common.Hash, number uint64) {
|
||||
Expect(mldr.getBlockCalled).To(BeTrue())
|
||||
Expect(mldr.getBlockPassedHash).To(Equal(hash))
|
||||
Expect(mldr.getBlockPassedNumber).To(Equal(number))
|
||||
}
|
||||
|
||||
func (mldr *MockLevelDatabaseReader) AssertGetBlockReceiptsCalledWith(hash common.Hash, number uint64) {
|
||||
Expect(mldr.getBlockReceiptsCalled).To(BeTrue())
|
||||
Expect(mldr.getBlockReceiptsPassedHash).To(Equal(hash))
|
||||
Expect(mldr.getBlockReceiptsPassedNumber).To(Equal(number))
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package fakes
|
||||
|
||||
import (
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
)
|
||||
|
||||
type MockReceiptRepository struct {
|
||||
createReceiptsAndLogsCalled bool
|
||||
createReceiptsAndLogsPassedBlockId int64
|
||||
createReceiptsAndLogsPassedReceipts []core.Receipt
|
||||
createReceiptsAndLogsReturnErr error
|
||||
}
|
||||
|
||||
func NewMockReceiptRepository() *MockReceiptRepository {
|
||||
return &MockReceiptRepository{
|
||||
createReceiptsAndLogsCalled: false,
|
||||
createReceiptsAndLogsPassedBlockId: 0,
|
||||
createReceiptsAndLogsPassedReceipts: nil,
|
||||
createReceiptsAndLogsReturnErr: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (mrr *MockReceiptRepository) SetCreateReceiptsAndLogsReturnErr(err error) {
|
||||
mrr.createReceiptsAndLogsReturnErr = err
|
||||
}
|
||||
|
||||
func (mrr *MockReceiptRepository) CreateReceiptsAndLogs(blockId int64, receipts []core.Receipt) error {
|
||||
mrr.createReceiptsAndLogsCalled = true
|
||||
mrr.createReceiptsAndLogsPassedBlockId = blockId
|
||||
mrr.createReceiptsAndLogsPassedReceipts = receipts
|
||||
return mrr.createReceiptsAndLogsReturnErr
|
||||
}
|
||||
|
||||
func (mrr *MockReceiptRepository) CreateReceipt(blockId int64, receipt core.Receipt) (int64, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (mrr *MockReceiptRepository) GetReceipt(txHash string) (core.Receipt, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (mrr *MockReceiptRepository) AssertCreateReceiptsAndLogsCalledWith(blockId int64, receipts []core.Receipt) {
|
||||
Expect(mrr.createReceiptsAndLogsCalled).To(BeTrue())
|
||||
Expect(mrr.createReceiptsAndLogsPassedBlockId).To(Equal(blockId))
|
||||
Expect(mrr.createReceiptsAndLogsPassedReceipts).To(Equal(receipts))
|
||||
}
|
||||
|
||||
func (mrr *MockReceiptRepository) AssertCreateReceiptsAndLogsNotCalled() {
|
||||
Expect(mrr.createReceiptsAndLogsCalled).To(BeFalse())
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package fakes
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
)
|
||||
|
||||
type MockTransactionConverter struct {
|
||||
convertTransactionsToCoreCalled bool
|
||||
convertTransactionsToCorePassedBlock *types.Block
|
||||
convertTransactionsToCoreReturnTransactions []core.Transaction
|
||||
convertTransactionsToCoreReturnError error
|
||||
}
|
||||
|
||||
func NewMockTransactionConverter() *MockTransactionConverter {
|
||||
return &MockTransactionConverter{
|
||||
convertTransactionsToCoreCalled: false,
|
||||
convertTransactionsToCorePassedBlock: nil,
|
||||
convertTransactionsToCoreReturnTransactions: nil,
|
||||
convertTransactionsToCoreReturnError: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (mtc *MockTransactionConverter) SetConvertTransactionsToCoreReturnVals(transactions []core.Transaction, err error) {
|
||||
mtc.convertTransactionsToCoreReturnTransactions = transactions
|
||||
mtc.convertTransactionsToCoreReturnError = err
|
||||
}
|
||||
|
||||
func (mtc *MockTransactionConverter) ConvertTransactionsToCore(gethBlock *types.Block) ([]core.Transaction, error) {
|
||||
mtc.convertTransactionsToCoreCalled = true
|
||||
mtc.convertTransactionsToCorePassedBlock = gethBlock
|
||||
return mtc.convertTransactionsToCoreReturnTransactions, mtc.convertTransactionsToCoreReturnError
|
||||
}
|
||||
|
||||
func (mtc *MockTransactionConverter) AssertConvertTransactionsToCoreCalledWith(gethBlock *types.Block) {
|
||||
Expect(mtc.convertTransactionsToCoreCalled).To(BeTrue())
|
||||
Expect(mtc.convertTransactionsToCorePassedBlock).To(Equal(gethBlock))
|
||||
}
|
||||
+10
-4
@@ -10,13 +10,17 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
|
||||
vulcRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
|
||||
)
|
||||
|
||||
type Blockchain struct {
|
||||
client *ethclient.Client
|
||||
blockConverter vulcCommon.BlockConverter
|
||||
readGethHeaders chan *types.Header
|
||||
outputBlocks chan core.Block
|
||||
newHeadSubscription ethereum.Subscription
|
||||
@@ -33,6 +37,8 @@ func NewBlockchain(ipcPath string) *Blockchain {
|
||||
clientWrapper := node.ClientWrapper{ContextCaller: rpcClient, IPCPath: ipcPath}
|
||||
blockchain.node = node.MakeNode(clientWrapper)
|
||||
blockchain.client = client
|
||||
transactionConverter := vulcRpc.NewRpcTransactionConverter(client)
|
||||
blockchain.blockConverter = vulcCommon.NewBlockConverter(transactionConverter)
|
||||
return &blockchain
|
||||
}
|
||||
|
||||
@@ -50,7 +56,7 @@ func (blockchain *Blockchain) GetLogs(contract core.Contract, startingBlockNumbe
|
||||
if err != nil {
|
||||
return []core.Log{}, err
|
||||
}
|
||||
logs := ToCoreLogs(gethLogs)
|
||||
logs := vulcCommon.ToCoreLogs(gethLogs)
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
@@ -63,7 +69,7 @@ func (blockchain *Blockchain) GetBlockByNumber(blockNumber int64) (core.Block, e
|
||||
if err != nil {
|
||||
return core.Block{}, err
|
||||
}
|
||||
block, err := ToCoreBlock(gethBlock, blockchain.client)
|
||||
block, err := blockchain.blockConverter.ToCoreBlock(gethBlock)
|
||||
if err != nil {
|
||||
return core.Block{}, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package geth
|
||||
|
||||
import (
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/ethereum"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
|
||||
)
|
||||
|
||||
type ColdImporter struct {
|
||||
blockRepository datastore.BlockRepository
|
||||
converter common.BlockConverter
|
||||
ethDB ethereum.Database
|
||||
receiptRepository datastore.ReceiptRepository
|
||||
}
|
||||
|
||||
func NewColdImporter(ethDB ethereum.Database, blockRepository datastore.BlockRepository, receiptRepository datastore.ReceiptRepository, converter common.BlockConverter) *ColdImporter {
|
||||
return &ColdImporter{
|
||||
blockRepository: blockRepository,
|
||||
converter: converter,
|
||||
ethDB: ethDB,
|
||||
receiptRepository: receiptRepository,
|
||||
}
|
||||
}
|
||||
|
||||
func (ci *ColdImporter) Execute(startingBlockNumber int64, endingBlockNumber int64) error {
|
||||
for i := startingBlockNumber; i <= endingBlockNumber; i++ {
|
||||
hash := ci.ethDB.GetBlockHash(i)
|
||||
|
||||
blockId, err := ci.createBlocksAndTransactions(hash, i)
|
||||
if err != nil {
|
||||
if err == repositories.ErrBlockExists {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
err = ci.createReceiptsAndLogs(hash, i, blockId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ci *ColdImporter) createBlocksAndTransactions(hash []byte, i int64) (int64, error) {
|
||||
block := ci.ethDB.GetBlock(hash, i)
|
||||
coreBlock, err := ci.converter.ToCoreBlock(block)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return ci.blockRepository.CreateOrUpdateBlock(coreBlock)
|
||||
}
|
||||
|
||||
func (ci *ColdImporter) createReceiptsAndLogs(hash []byte, number int64, blockId int64) error {
|
||||
receipts := ci.ethDB.GetBlockReceipts(hash, number)
|
||||
coreReceipts := common.ToCoreReceipts(receipts)
|
||||
return ci.receiptRepository.CreateReceiptsAndLogs(blockId, coreReceipts)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package geth_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
||||
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
|
||||
)
|
||||
|
||||
var _ = Describe("Geth cold importer", func() {
|
||||
var fakeGethBlock *types.Block
|
||||
|
||||
BeforeEach(func() {
|
||||
header := &types.Header{}
|
||||
transactions := []*types.Transaction{}
|
||||
uncles := []*types.Header{}
|
||||
receipts := []*types.Receipt{}
|
||||
fakeGethBlock = types.NewBlock(header, transactions, uncles, receipts)
|
||||
})
|
||||
|
||||
It("fetches blocks from level db and persists them to pg", func() {
|
||||
mockEthereumDatabase := fakes.NewMockEthereumDatabase()
|
||||
mockBlockRepository := fakes.NewMockBlockRepository()
|
||||
mockReceiptRepository := fakes.NewMockReceiptRepository()
|
||||
mockTransactionConverter := fakes.NewMockTransactionConverter()
|
||||
blockConverter := vulcCommon.NewBlockConverter(mockTransactionConverter)
|
||||
|
||||
blockNumber := int64(123)
|
||||
fakeHash := []byte{1, 2, 3, 4, 5}
|
||||
mockEthereumDatabase.SetReturnHash(fakeHash)
|
||||
mockEthereumDatabase.SetReturnBlock(fakeGethBlock)
|
||||
importer := geth.NewColdImporter(mockEthereumDatabase, mockBlockRepository, mockReceiptRepository, blockConverter)
|
||||
|
||||
importer.Execute(blockNumber, blockNumber)
|
||||
|
||||
mockEthereumDatabase.AssertGetBlockHashCalledWith(blockNumber)
|
||||
mockEthereumDatabase.AssertGetBlockCalledWith(fakeHash, blockNumber)
|
||||
mockTransactionConverter.AssertConvertTransactionsToCoreCalledWith(fakeGethBlock)
|
||||
convertedBlock, err := blockConverter.ToCoreBlock(fakeGethBlock)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
mockBlockRepository.AssertCreateOrUpdateBlockCalledWith(convertedBlock)
|
||||
})
|
||||
|
||||
It("fetches receipts from level db and persists them to pg", func() {
|
||||
mockEthereumDatabase := fakes.NewMockEthereumDatabase()
|
||||
mockBlockRepository := fakes.NewMockBlockRepository()
|
||||
mockReceiptRepository := fakes.NewMockReceiptRepository()
|
||||
mockTransactionConverter := fakes.NewMockTransactionConverter()
|
||||
blockConverter := vulcCommon.NewBlockConverter(mockTransactionConverter)
|
||||
|
||||
blockNumber := int64(123)
|
||||
blockId := int64(999)
|
||||
mockBlockRepository.SetCreateOrUpdateBlockReturnVals(blockId, nil)
|
||||
fakeReceipts := types.Receipts{{}}
|
||||
mockEthereumDatabase.SetReturnBlock(fakeGethBlock)
|
||||
mockEthereumDatabase.SetReturnReceipts(fakeReceipts)
|
||||
importer := geth.NewColdImporter(mockEthereumDatabase, mockBlockRepository, mockReceiptRepository, blockConverter)
|
||||
|
||||
importer.Execute(blockNumber, blockNumber)
|
||||
|
||||
expectedReceipts := vulcCommon.ToCoreReceipts(fakeReceipts)
|
||||
mockReceiptRepository.AssertCreateReceiptsAndLogsCalledWith(blockId, expectedReceipts)
|
||||
})
|
||||
|
||||
It("does not fetch receipts if block already exists", func() {
|
||||
mockEthereumDatabase := fakes.NewMockEthereumDatabase()
|
||||
mockBlockRepository := fakes.NewMockBlockRepository()
|
||||
mockReceiptRepository := fakes.NewMockReceiptRepository()
|
||||
mockTransactionConverter := fakes.NewMockTransactionConverter()
|
||||
blockConverter := vulcCommon.NewBlockConverter(mockTransactionConverter)
|
||||
|
||||
mockEthereumDatabase.SetReturnBlock(fakeGethBlock)
|
||||
mockBlockRepository.SetCreateOrUpdateBlockReturnVals(0, repositories.ErrBlockExists)
|
||||
importer := geth.NewColdImporter(mockEthereumDatabase, mockBlockRepository, mockReceiptRepository, blockConverter)
|
||||
|
||||
err := importer.Execute(1, 1)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
mockReceiptRepository.AssertCreateReceiptsAndLogsNotCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,69 @@
|
||||
package cold_db
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ColdDbTransactionConverter struct{}
|
||||
|
||||
func NewColdDbTransactionConverter() *ColdDbTransactionConverter {
|
||||
return &ColdDbTransactionConverter{}
|
||||
}
|
||||
|
||||
func (cdtc *ColdDbTransactionConverter) ConvertTransactionsToCore(gethBlock *types.Block) ([]core.Transaction, error) {
|
||||
var g errgroup.Group
|
||||
coreTransactions := make([]core.Transaction, len(gethBlock.Transactions()))
|
||||
|
||||
for gethTransactionIndex, gethTransaction := range gethBlock.Transactions() {
|
||||
transaction := gethTransaction
|
||||
transactionIndex := uint(gethTransactionIndex)
|
||||
g.Go(func() error {
|
||||
signer := getSigner(transaction)
|
||||
sender, err := signer.Sender(transaction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
coreTransaction := transToCoreTrans(transaction, &sender)
|
||||
coreTransactions[transactionIndex] = coreTransaction
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := g.Wait(); err != nil {
|
||||
return coreTransactions, err
|
||||
}
|
||||
return coreTransactions, nil
|
||||
}
|
||||
|
||||
func getSigner(tx *types.Transaction) types.Signer {
|
||||
v, _, _ := tx.RawSignatureValues()
|
||||
if v.Sign() != 0 && tx.Protected() {
|
||||
return types.NewEIP155Signer(tx.ChainId())
|
||||
}
|
||||
return types.HomesteadSigner{}
|
||||
}
|
||||
|
||||
func transToCoreTrans(transaction *types.Transaction, from *common.Address) core.Transaction {
|
||||
data := hexutil.Encode(transaction.Data())
|
||||
return core.Transaction{
|
||||
Hash: transaction.Hash().Hex(),
|
||||
Nonce: transaction.Nonce(),
|
||||
To: strings.ToLower(addressToHex(transaction.To())),
|
||||
From: strings.ToLower(addressToHex(from)),
|
||||
GasLimit: transaction.Gas(),
|
||||
GasPrice: transaction.GasPrice().Int64(),
|
||||
Value: transaction.Value().String(),
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
func addressToHex(to *common.Address) string {
|
||||
if to == nil {
|
||||
return ""
|
||||
}
|
||||
return to.Hex()
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BlockConverter struct {
|
||||
transactionConverter TransactionConverter
|
||||
}
|
||||
|
||||
func NewBlockConverter(transactionConverter TransactionConverter) BlockConverter {
|
||||
return BlockConverter{transactionConverter: transactionConverter}
|
||||
}
|
||||
|
||||
func (bc BlockConverter) ToCoreBlock(gethBlock *types.Block) (core.Block, error) {
|
||||
transactions, err := bc.transactionConverter.ConvertTransactionsToCore(gethBlock)
|
||||
if err != nil {
|
||||
return core.Block{}, err
|
||||
}
|
||||
coreBlock := core.Block{
|
||||
Difficulty: gethBlock.Difficulty().Int64(),
|
||||
ExtraData: hexutil.Encode(gethBlock.Extra()),
|
||||
GasLimit: gethBlock.GasLimit(),
|
||||
GasUsed: gethBlock.GasUsed(),
|
||||
Hash: gethBlock.Hash().Hex(),
|
||||
Miner: strings.ToLower(gethBlock.Coinbase().Hex()),
|
||||
Nonce: hexutil.Encode(gethBlock.Header().Nonce[:]),
|
||||
Number: gethBlock.Number().Int64(),
|
||||
ParentHash: gethBlock.ParentHash().Hex(),
|
||||
Size: gethBlock.Size().String(),
|
||||
Time: gethBlock.Time().Int64(),
|
||||
Transactions: transactions,
|
||||
UncleHash: gethBlock.UncleHash().Hex(),
|
||||
}
|
||||
coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles())
|
||||
coreBlock.UnclesReward = CalcUnclesReward(coreBlock, gethBlock.Uncles())
|
||||
return coreBlock, nil
|
||||
}
|
||||
+63
-40
@@ -1,15 +1,11 @@
|
||||
package geth_test
|
||||
package common_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -17,7 +13,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
||||
|
||||
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
|
||||
)
|
||||
|
||||
type FakeGethClient struct {
|
||||
@@ -93,27 +91,29 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
}
|
||||
block := types.NewBlock(&header, []*types.Transaction{}, []*types.Header{}, []*types.Receipt{})
|
||||
client := &FakeGethClient{}
|
||||
gethBlock, err := geth.ToCoreBlock(block, client)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(gethBlock.Difficulty).To(Equal(difficulty.Int64()))
|
||||
Expect(gethBlock.GasLimit).To(Equal(gasLimit))
|
||||
Expect(gethBlock.Miner).To(Equal(miner.Hex()))
|
||||
Expect(gethBlock.GasUsed).To(Equal(gasUsed))
|
||||
Expect(gethBlock.Hash).To(Equal(block.Hash().Hex()))
|
||||
Expect(gethBlock.Nonce).To(Equal(hexutil.Encode(header.Nonce[:])))
|
||||
Expect(gethBlock.Number).To(Equal(number))
|
||||
Expect(gethBlock.ParentHash).To(Equal(block.ParentHash().Hex()))
|
||||
Expect(gethBlock.ExtraData).To(Equal(hexutil.Encode(block.Extra())))
|
||||
Expect(gethBlock.Size).To(Equal(block.Size().String()))
|
||||
Expect(gethBlock.Time).To(Equal(time))
|
||||
Expect(gethBlock.UncleHash).To(Equal(block.UncleHash().Hex()))
|
||||
Expect(gethBlock.IsFinal).To(BeFalse())
|
||||
Expect(coreBlock.Difficulty).To(Equal(difficulty.Int64()))
|
||||
Expect(coreBlock.GasLimit).To(Equal(gasLimit))
|
||||
Expect(coreBlock.Miner).To(Equal(miner.Hex()))
|
||||
Expect(coreBlock.GasUsed).To(Equal(gasUsed))
|
||||
Expect(coreBlock.Hash).To(Equal(block.Hash().Hex()))
|
||||
Expect(coreBlock.Nonce).To(Equal(hexutil.Encode(header.Nonce[:])))
|
||||
Expect(coreBlock.Number).To(Equal(number))
|
||||
Expect(coreBlock.ParentHash).To(Equal(block.ParentHash().Hex()))
|
||||
Expect(coreBlock.ExtraData).To(Equal(hexutil.Encode(block.Extra())))
|
||||
Expect(coreBlock.Size).To(Equal(block.Size().String()))
|
||||
Expect(coreBlock.Time).To(Equal(time))
|
||||
Expect(coreBlock.UncleHash).To(Equal(block.UncleHash().Hex()))
|
||||
Expect(coreBlock.IsFinal).To(BeFalse())
|
||||
})
|
||||
|
||||
Describe("The block and uncle rewards calculations", func() {
|
||||
It("calculates block rewards for a block", func() {
|
||||
|
||||
transaction := types.NewTransaction(
|
||||
uint64(226823),
|
||||
common.HexToAddress("0x108fedb097c1dcfed441480170144d8e19bb217f"),
|
||||
@@ -141,10 +141,13 @@ 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, err := geth.ToCoreBlock(block, client)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(geth.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(5.31355))
|
||||
Expect(vulcCommon.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(5.31355))
|
||||
})
|
||||
|
||||
It("calculates the uncles reward for a block", func() {
|
||||
@@ -175,11 +178,13 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
|
||||
client := NewFakeClient(nil)
|
||||
client.AddReceipts(receipts)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := geth.ToCoreBlock(block, client)
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(geth.CalcUnclesReward(coreBlock, block.Uncles())).To(Equal(6.875))
|
||||
Expect(vulcCommon.CalcUnclesReward(coreBlock, block.Uncles())).To(Equal(6.875))
|
||||
})
|
||||
|
||||
It("decreases the static block reward from 5 to 3 for blocks after block 4,269,999", func() {
|
||||
@@ -222,10 +227,13 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
|
||||
client := NewFakeClient(nil)
|
||||
client.AddReceipts(receipts)
|
||||
coreBlock, err := geth.ToCoreBlock(block, client)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(geth.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(3.024990672))
|
||||
Expect(vulcCommon.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(3.024990672))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -234,7 +242,10 @@ 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, err := geth.ToCoreBlock(block, client)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(coreBlock.Transactions)).To(Equal(0))
|
||||
@@ -263,13 +274,16 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
client.AddReceipts([]*types.Receipt{gethReceipt})
|
||||
|
||||
header := types.Header{}
|
||||
gethBlock := types.NewBlock(
|
||||
block := types.NewBlock(
|
||||
&header,
|
||||
[]*types.Transaction{gethTransaction},
|
||||
[]*types.Header{},
|
||||
[]*types.Receipt{gethReceipt},
|
||||
)
|
||||
coreBlock, err := geth.ToCoreBlock(gethBlock, client)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(coreBlock.Transactions)).To(Equal(1))
|
||||
@@ -283,9 +297,8 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
Expect(coreTransaction.Nonce).To(Equal(gethTransaction.Nonce()))
|
||||
|
||||
coreReceipt := coreTransaction.Receipt
|
||||
expectedReceipt := geth.ReceiptToCoreReceipt(gethReceipt)
|
||||
expectedReceipt := vulcCommon.ToCoreReceipt(gethReceipt)
|
||||
Expect(coreReceipt).To(Equal(expectedReceipt))
|
||||
|
||||
})
|
||||
|
||||
It("has an empty 'To' field when transaction creates a new contract", func() {
|
||||
@@ -307,21 +320,23 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
client := NewFakeClient(nil)
|
||||
client.AddReceipts([]*types.Receipt{gethReceipt})
|
||||
|
||||
gethBlock := types.NewBlock(
|
||||
block := types.NewBlock(
|
||||
&types.Header{},
|
||||
[]*types.Transaction{gethTransaction},
|
||||
[]*types.Header{},
|
||||
[]*types.Receipt{gethReceipt},
|
||||
)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := geth.ToCoreBlock(gethBlock, client)
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
coreTransaction := coreBlock.Transactions[0]
|
||||
Expect(coreTransaction.To).To(Equal(""))
|
||||
|
||||
coreReceipt := coreTransaction.Receipt
|
||||
expectedReceipt := geth.ReceiptToCoreReceipt(gethReceipt)
|
||||
expectedReceipt := vulcCommon.ToCoreReceipt(gethReceipt)
|
||||
Expect(coreReceipt).To(Equal(expectedReceipt))
|
||||
})
|
||||
})
|
||||
@@ -330,7 +345,7 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
var gethTransaction *types.Transaction
|
||||
var gethReceipt *types.Receipt
|
||||
var header *types.Header
|
||||
var gethBlock *types.Block
|
||||
var block *types.Block
|
||||
|
||||
BeforeEach(func() {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
@@ -344,7 +359,7 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
)
|
||||
gethReceipt = &types.Receipt{}
|
||||
header = &types.Header{}
|
||||
gethBlock = types.NewBlock(
|
||||
block = types.NewBlock(
|
||||
header,
|
||||
[]*types.Transaction{gethTransaction},
|
||||
[]*types.Header{},
|
||||
@@ -360,14 +375,22 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
It("returns an error when transaction sender call fails", func() {
|
||||
client := NewFakeClient(TransactionSenderError{})
|
||||
client.AddReceipts([]*types.Receipt{})
|
||||
_, err := geth.ToCoreBlock(gethBlock, client)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
_, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
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)
|
||||
transactionConverter := rpc.NewRpcTransactionConverter(client)
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
_, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).To(Equal(TransActionReceiptError{}))
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
package geth
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
@@ -0,0 +1,13 @@
|
||||
package common_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestCommon(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Common Suite")
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package geth
|
||||
package common
|
||||
|
||||
import (
|
||||
"strings"
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
)
|
||||
|
||||
@@ -30,8 +31,7 @@ func ToCoreLog(gethLog types.Log) core.Log {
|
||||
topics := gethLog.Topics
|
||||
hexTopics := makeTopics(topics)
|
||||
return core.Log{
|
||||
Address: strings.ToLower(gethLog.Address.Hex()),
|
||||
|
||||
Address: strings.ToLower(gethLog.Address.Hex()),
|
||||
BlockNumber: int64(gethLog.BlockNumber),
|
||||
Topics: hexTopics,
|
||||
TxHash: gethLog.TxHash.Hex(),
|
||||
@@ -1,4 +1,4 @@
|
||||
package geth_test
|
||||
package common_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
@@ -8,8 +8,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
||||
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
|
||||
)
|
||||
|
||||
var _ = Describe("Conversion of GethLog to core.Log", func() {
|
||||
@@ -41,7 +42,7 @@ var _ = Describe("Conversion of GethLog to core.Log", func() {
|
||||
},
|
||||
}
|
||||
|
||||
coreLog := geth.ToCoreLog(gethLog)
|
||||
coreLog := vulcCommon.ToCoreLog(gethLog)
|
||||
|
||||
Expect(coreLog.Address).To(Equal(expected.Address))
|
||||
Expect(coreLog.BlockNumber).To(Equal(expected.BlockNumber))
|
||||
@@ -81,15 +82,13 @@ var _ = Describe("Conversion of GethLog to core.Log", func() {
|
||||
},
|
||||
}
|
||||
|
||||
expectedOne := geth.ToCoreLog(gethLogOne)
|
||||
expectedTwo := geth.ToCoreLog(gethLogTwo)
|
||||
expectedOne := vulcCommon.ToCoreLog(gethLogOne)
|
||||
expectedTwo := vulcCommon.ToCoreLog(gethLogTwo)
|
||||
|
||||
coreLogs := geth.ToCoreLogs([]types.Log{gethLogOne, gethLogTwo})
|
||||
coreLogs := vulcCommon.ToCoreLogs([]types.Log{gethLogOne, gethLogTwo})
|
||||
|
||||
Expect(len(coreLogs)).To(Equal(2))
|
||||
Expect(coreLogs[0]).To(Equal(expectedOne))
|
||||
Expect(coreLogs[1]).To(Equal(expectedTwo))
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
+9
-8
@@ -1,24 +1,25 @@
|
||||
package geth
|
||||
package common
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"bytes"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
)
|
||||
|
||||
func BigTo64(n *big.Int) int64 {
|
||||
if n != nil {
|
||||
return n.Int64()
|
||||
func ToCoreReceipts(gethReceipts types.Receipts) []core.Receipt {
|
||||
var coreReceipts []core.Receipt
|
||||
for _, receipt := range gethReceipts {
|
||||
coreReceipt := ToCoreReceipt(receipt)
|
||||
coreReceipts = append(coreReceipts, coreReceipt)
|
||||
}
|
||||
return 0
|
||||
return coreReceipts
|
||||
}
|
||||
|
||||
func ReceiptToCoreReceipt(gethReceipt *types.Receipt) core.Receipt {
|
||||
func ToCoreReceipt(gethReceipt *types.Receipt) core.Receipt {
|
||||
bloom := hexutil.Encode(gethReceipt.Bloom.Bytes())
|
||||
var postState string
|
||||
var status int
|
||||
+5
-6
@@ -1,4 +1,4 @@
|
||||
package geth_test
|
||||
package common_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -6,8 +6,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
||||
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
|
||||
)
|
||||
|
||||
var _ = Describe("Conversion of GethReceipt to core.Receipt", func() {
|
||||
@@ -34,7 +35,7 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() {
|
||||
TxHash: receipt.TxHash.Hex(),
|
||||
}
|
||||
|
||||
coreReceipt := geth.ReceiptToCoreReceipt(&receipt)
|
||||
coreReceipt := vulcCommon.ToCoreReceipt(&receipt)
|
||||
Expect(coreReceipt.Bloom).To(Equal(expected.Bloom))
|
||||
Expect(coreReceipt.ContractAddress).To(Equal(expected.ContractAddress))
|
||||
Expect(coreReceipt.CumulativeGasUsed).To(Equal(expected.CumulativeGasUsed))
|
||||
@@ -68,7 +69,7 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() {
|
||||
TxHash: receipt.TxHash.Hex(),
|
||||
}
|
||||
|
||||
coreReceipt := geth.ReceiptToCoreReceipt(&receipt)
|
||||
coreReceipt := vulcCommon.ToCoreReceipt(&receipt)
|
||||
Expect(coreReceipt.Bloom).To(Equal(expected.Bloom))
|
||||
Expect(coreReceipt.ContractAddress).To(Equal(""))
|
||||
Expect(coreReceipt.CumulativeGasUsed).To(Equal(expected.CumulativeGasUsed))
|
||||
@@ -77,7 +78,5 @@ var _ = Describe("Conversion of GethReceipt to core.Receipt", func() {
|
||||
Expect(coreReceipt.StateRoot).To(Equal(expected.StateRoot))
|
||||
Expect(coreReceipt.Status).To(Equal(expected.Status))
|
||||
Expect(coreReceipt.TxHash).To(Equal(expected.TxHash))
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
@@ -0,0 +1,10 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
)
|
||||
|
||||
type TransactionConverter interface {
|
||||
ConvertTransactionsToCore(gethBlock *types.Block) ([]core.Transaction, error)
|
||||
}
|
||||
+16
-32
@@ -1,16 +1,17 @@
|
||||
package geth
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"context"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
@@ -18,32 +19,15 @@ type Client interface {
|
||||
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
|
||||
}
|
||||
|
||||
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()),
|
||||
GasLimit: gethBlock.GasLimit(),
|
||||
GasUsed: gethBlock.GasUsed(),
|
||||
Hash: gethBlock.Hash().Hex(),
|
||||
Miner: strings.ToLower(gethBlock.Coinbase().Hex()),
|
||||
Nonce: hexutil.Encode(gethBlock.Header().Nonce[:]),
|
||||
Number: gethBlock.Number().Int64(),
|
||||
ParentHash: gethBlock.ParentHash().Hex(),
|
||||
Size: gethBlock.Size().String(),
|
||||
Time: gethBlock.Time().Int64(),
|
||||
Transactions: transactions,
|
||||
UncleHash: gethBlock.UncleHash().Hex(),
|
||||
}
|
||||
coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles())
|
||||
coreBlock.UnclesReward = CalcUnclesReward(coreBlock, gethBlock.Uncles())
|
||||
return coreBlock, nil
|
||||
type RpcTransactionConverter struct {
|
||||
client Client
|
||||
}
|
||||
|
||||
func convertTransactionsToCore(gethBlock *types.Block, client Client) ([]core.Transaction, error) {
|
||||
func NewRpcTransactionConverter(client Client) *RpcTransactionConverter {
|
||||
return &RpcTransactionConverter{client: client}
|
||||
}
|
||||
|
||||
func (rtc *RpcTransactionConverter) ConvertTransactionsToCore(gethBlock *types.Block) ([]core.Transaction, error) {
|
||||
var g errgroup.Group
|
||||
coreTransactions := make([]core.Transaction, len(gethBlock.Transactions()))
|
||||
|
||||
@@ -52,13 +36,13 @@ func convertTransactionsToCore(gethBlock *types.Block, client Client) ([]core.Tr
|
||||
transaction := gethTransaction
|
||||
transactionIndex := uint(gethTransactionIndex)
|
||||
g.Go(func() error {
|
||||
from, err := client.TransactionSender(context.Background(), transaction, gethBlock.Hash(), transactionIndex)
|
||||
from, err := rtc.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)
|
||||
coreTransaction, err = appendReceiptToTransaction(rtc.client, coreTransaction)
|
||||
if err != nil {
|
||||
log.Println("receipt: ", err)
|
||||
return err
|
||||
@@ -79,7 +63,7 @@ func appendReceiptToTransaction(client Client, transaction core.Transaction) (co
|
||||
if err != nil {
|
||||
return transaction, err
|
||||
}
|
||||
receipt := ReceiptToCoreReceipt(gethReceipt)
|
||||
receipt := vulcCommon.ToCoreReceipt(gethReceipt)
|
||||
transaction.Receipt = receipt
|
||||
return transaction, nil
|
||||
}
|
||||
@@ -23,6 +23,7 @@ func RetrieveAndUpdateBlocks(blockchain core.Blockchain, blockRepository datasto
|
||||
log.Printf("failed to retrieve block number: %d\n", blockNumber)
|
||||
return 0
|
||||
}
|
||||
// TODO: handle possible error here
|
||||
blockRepository.CreateOrUpdateBlock(block)
|
||||
}
|
||||
return len(blockNumbers)
|
||||
|
||||
Reference in New Issue
Block a user