Add cold import script

This commit is contained in:
Rob Mulholand
2018-05-04 10:54:00 -05:00
parent 462f94d84a
commit 5f6bf32ec1
411 changed files with 81507 additions and 1566 deletions
+19
View File
@@ -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,
}
}
+31
View File
@@ -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)
}
}
+34
View File
@@ -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")
}
+2 -2
View File
@@ -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) {
+10 -7
View File
@@ -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())
+4 -2
View File
@@ -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)
}
+51
View File
@@ -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))
}
+86
View File
@@ -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))
}
+88
View File
@@ -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))
}
+52
View File
@@ -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())
}
+40
View File
@@ -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
View File
@@ -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
}
+58
View File
@@ -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)
}
+85
View File
@@ -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
}
@@ -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))
})
})
@@ -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
@@ -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)
}
@@ -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
}
+1
View File
@@ -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)