Merge pull request #73 from 8thlight/transformer-refactoring

Transformer factory evaluation
This commit is contained in:
Takayuki Goto 2018-10-23 13:43:19 -05:00 committed by GitHub
commit f10bddf353
96 changed files with 1465 additions and 2101 deletions

View File

@ -86,33 +86,33 @@ func getTransformerInititalizers(transformerNames []string) []shared2.Transforme
func buildTransformerInitializerMap() map[string]shared2.TransformerInitializer { func buildTransformerInitializerMap() map[string]shared2.TransformerInitializer {
transformerInitializerMap := make(map[string]shared2.TransformerInitializer) transformerInitializerMap := make(map[string]shared2.TransformerInitializer)
transformerInitializerMap["bite"] = transformers.BiteTransformerInitializer transformerInitializerMap[shared2.BiteLabel] = transformers.BiteTransformerInitializer
transformerInitializerMap["catFileChopLump"] = transformers.CatFileChopLumpTransformerInitializer transformerInitializerMap[shared2.CatFileChopLumpLabel] = transformers.CatFileChopLumpTransformerInitializer
transformerInitializerMap["catFileFlip"] = transformers.CatFileFlipTransformerInitializer transformerInitializerMap[shared2.CatFileFlipLabel] = transformers.CatFileFlipTransformerInitializer
transformerInitializerMap["catFilePitVow"] = transformers.CatFilePitVowTransformerInitializer transformerInitializerMap[shared2.CatFilePitVowLabel] = transformers.CatFilePitVowTransformerInitializer
transformerInitializerMap["deal"] = transformers.DealTransformerInitializer transformerInitializerMap[shared2.DealLabel] = transformers.DealTransformerInitializer
transformerInitializerMap["dent"] = transformers.DentTransformerInitializer transformerInitializerMap[shared2.DentLabel] = transformers.DentTransformerInitializer
transformerInitializerMap["dripDrip"] = transformers.DripDripTransformerInitializer transformerInitializerMap[shared2.DripDripLabel] = transformers.DripDripTransformerInitializer
transformerInitializerMap["dripFileIlk"] = transformers.DripFileIlkTransformerInitializer transformerInitializerMap[shared2.DripFileIlkLabel] = transformers.DripFileIlkTransformerInitializer
transformerInitializerMap["dripFileRepo"] = transformers.DripFileRepoTransformerInitializer transformerInitializerMap[shared2.DripFileRepoLabel] = transformers.DripFileRepoTransformerInitializer
transformerInitializerMap["dripFileVow"] = transformers.DripFileVowTransfromerInitializer transformerInitializerMap[shared2.DripFileVowLabel] = transformers.DripFileVowTransfromerInitializer
transformerInitializerMap["flipKick"] = transformers.FlipKickTransformerInitializer transformerInitializerMap[shared2.FlipKickLabel] = transformers.FlipKickTransformerInitializer
transformerInitializerMap["flopKick"] = transformers.FlopKickTransformerInitializer transformerInitializerMap[shared2.FlopKickLabel] = transformers.FlopKickTransformerInitializer
transformerInitializerMap["frob"] = transformers.FrobTransformerInitializer transformerInitializerMap[shared2.FrobLabel] = transformers.FrobTransformerInitializer
transformerInitializerMap["pitFileDebtCeiling"] = transformers.PitFileDebtCeilingTransformerInitializer transformerInitializerMap[shared2.PitFileDebtCeilingLabel] = transformers.PitFileDebtCeilingTransformerInitializer
transformerInitializerMap["pitFileIlk"] = transformers.PitFileIlkTransformerInitializer transformerInitializerMap[shared2.PitFileIlkLabel] = transformers.PitFileIlkTransformerInitializer
transformerInitializerMap["pitFileStabilityFee"] = transformers.PitFileStabilityFeeTransformerInitializer transformerInitializerMap[shared2.PitFileStabilityFeeLabel] = transformers.PitFileStabilityFeeTransformerInitializer
transformerInitializerMap["priceFeed"] = transformers.PriceFeedTransformerInitializer transformerInitializerMap[shared2.PriceFeedLabel] = transformers.PriceFeedTransformerInitializer
transformerInitializerMap["tend"] = transformers.TendTransformerInitializer transformerInitializerMap[shared2.TendLabel] = transformers.TendTransformerInitializer
transformerInitializerMap["vatGrab"] = transformers.VatGrabTransformerInitializer transformerInitializerMap[shared2.VatGrabLabel] = transformers.VatGrabTransformerInitializer
transformerInitializerMap["vatInit"] = transformers.VatInitTransformerInitializer transformerInitializerMap[shared2.VatInitLabel] = transformers.VatInitTransformerInitializer
transformerInitializerMap["vatMove"] = transformers.VatMoveTransformerInitializer transformerInitializerMap[shared2.VatMoveLabel] = transformers.VatMoveTransformerInitializer
transformerInitializerMap["vatHeal"] = transformers.VatHealTransformerInitializer transformerInitializerMap[shared2.VatHealLabel] = transformers.VatHealTransformerInitializer
transformerInitializerMap["vatFold"] = transformers.VatFoldTransformerInitializer transformerInitializerMap[shared2.VatFoldLabel] = transformers.VatFoldTransformerInitializer
transformerInitializerMap["vatSlip"] = transformers.VatSlipTransformerInitializer transformerInitializerMap[shared2.VatSlipLabel] = transformers.VatSlipTransformerInitializer
transformerInitializerMap["vatToll"] = transformers.VatTollTransformerInitializer transformerInitializerMap[shared2.VatTollLabel] = transformers.VatTollTransformerInitializer
transformerInitializerMap["vatTune"] = transformers.VatTuneTransformerInitializer transformerInitializerMap[shared2.VatTuneLabel] = transformers.VatTuneTransformerInitializer
transformerInitializerMap["vatFlux"] = transformers.VatFluxTransformerInitializer transformerInitializerMap[shared2.VatFluxLabel] = transformers.VatFluxTransformerInitializer
return transformerInitializerMap return transformerInitializerMap
} }

View File

@ -2,8 +2,8 @@
-- PostgreSQL database dump -- PostgreSQL database dump
-- --
-- Dumped from database version 10.3 -- Dumped from database version 10.5
-- Dumped by pg_dump version 10.3 -- Dumped by pg_dump version 10.5
SET statement_timeout = 0; SET statement_timeout = 0;
SET lock_timeout = 0; SET lock_timeout = 0;

View File

@ -12,14 +12,15 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package drip_file package ilk
import "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" import "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
var DripFileConfig = shared.TransformerConfig{ var DripFileIlkConfig = shared.SingleTransformerConfig{
TransformerName: shared.DripFileIlkLabel,
ContractAddresses: []string{shared.DripContractAddress}, ContractAddresses: []string{shared.DripContractAddress},
ContractAbi: shared.DripABI, ContractAbi: shared.DripABI,
Topics: []string{shared.DripFileIlkSignature, shared.DripFileRepoSignature}, Topic: shared.DripFileIlkSignature,
StartingBlockNumber: 0, StartingBlockNumber: 0,
EndingBlockNumber: 10000000, EndingBlockNumber: 10000000,
} }

View File

@ -24,19 +24,16 @@ import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
) )
type Converter interface {
ToModels(ethLogs []types.Log) ([]DripFileIlkModel, error)
}
type DripFileIlkConverter struct{} type DripFileIlkConverter struct{}
func (DripFileIlkConverter) ToModels(ethLogs []types.Log) ([]DripFileIlkModel, error) { func (DripFileIlkConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []DripFileIlkModel var models []interface{}
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := verifyLog(ethLog) err := verifyLog(ethLog)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ilk := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00")) ilk := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00"))
vow := string(bytes.Trim(ethLog.Topics[3].Bytes(), "\x00")) vow := string(bytes.Trim(ethLog.Topics[3].Bytes(), "\x00"))
taxBytes := ethLog.Data[len(ethLog.Data)-shared.DataItemLength:] taxBytes := ethLog.Data[len(ethLog.Data)-shared.DataItemLength:]
@ -45,6 +42,7 @@ func (DripFileIlkConverter) ToModels(ethLogs []types.Log) ([]DripFileIlkModel, e
if err != nil { if err != nil {
return nil, err return nil, err
} }
model := DripFileIlkModel{ model := DripFileIlkModel{
Ilk: ilk, Ilk: ilk,
Vow: vow, Vow: vow,

View File

@ -56,6 +56,6 @@ var _ = Describe("Drip file ilk converter", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1)) Expect(len(models)).To(Equal(1))
Expect(models[0]).To(Equal(test_data.DripFileIlkModel)) Expect(models[0].(ilk.DripFileIlkModel)).To(Equal(test_data.DripFileIlkModel))
}) })
}) })

View File

@ -15,35 +15,34 @@
package ilk package ilk
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type Repository interface {
Create(headerID int64, models []DripFileIlkModel) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type DripFileIlkRepository struct { type DripFileIlkRepository struct {
db *postgres.DB db *postgres.DB
} }
func NewDripFileIlkRepository(db *postgres.DB) DripFileIlkRepository { func (repository DripFileIlkRepository) Create(headerID int64, models []interface{}) error {
return DripFileIlkRepository{db: db}
}
func (repository DripFileIlkRepository) Create(headerID int64, models []DripFileIlkModel) error {
tx, err := repository.db.Begin() tx, err := repository.db.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, model := range models { for _, model := range models {
ilk, ok := model.(DripFileIlkModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, DripFileIlkModel{})
}
_, err = tx.Exec( _, err = tx.Exec(
`INSERT into maker.drip_file_ilk (header_id, ilk, vow, tax, log_idx, tx_idx, raw_log) `INSERT into maker.drip_file_ilk (header_id, ilk, vow, tax, log_idx, tx_idx, raw_log)
VALUES($1, $2, $3, $4::NUMERIC, $5, $6, $7)`, VALUES($1, $2, $3, $4::NUMERIC, $5, $6, $7)`,
headerID, model.Ilk, model.Vow, model.Tax, model.LogIndex, model.TransactionIndex, model.Raw, headerID, ilk.Ilk, ilk.Vow, ilk.Tax, ilk.LogIndex, ilk.TransactionIndex, ilk.Raw,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
@ -51,20 +50,21 @@ func (repository DripFileIlkRepository) Create(headerID int64, models []DripFile
} }
_, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_ilk_checked) _, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_ilk_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET drip_file_ilk_checked = $2`, headerID, true) UPDATE SET drip_file_ilk_checked = $2`, headerID, true)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
return tx.Commit() return tx.Commit()
} }
func (repository DripFileIlkRepository) MarkHeaderChecked(headerID int64) error { func (repository DripFileIlkRepository) MarkHeaderChecked(headerID int64) error {
_, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_ilk_checked) _, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_ilk_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET drip_file_ilk_checked = $2`, headerID, true) UPDATE SET drip_file_ilk_checked = $2`, headerID, true)
return err return err
} }
@ -73,14 +73,18 @@ func (repository DripFileIlkRepository) MissingHeaders(startingBlockNumber, endi
err := repository.db.Select( err := repository.db.Select(
&result, &result,
`SELECT headers.id, headers.block_number FROM headers `SELECT headers.id, headers.block_number FROM headers
LEFT JOIN checked_headers on headers.id = header_id LEFT JOIN checked_headers on headers.id = header_id
WHERE (header_id ISNULL OR drip_file_ilk_checked IS FALSE) WHERE (header_id ISNULL OR drip_file_ilk_checked IS FALSE)
AND headers.block_number >= $1 AND headers.block_number >= $1
AND headers.block_number <= $2 AND headers.block_number <= $2
AND headers.eth_node_fingerprint = $3`, AND headers.eth_node_fingerprint = $3`,
startingBlockNumber, startingBlockNumber,
endingBlockNumber, endingBlockNumber,
repository.db.Node.ID, repository.db.Node.ID,
) )
return result, err return result, err
} }
func (repository *DripFileIlkRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -16,10 +16,8 @@ package ilk_test
import ( import (
"database/sql" "database/sql"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore" "github.com/vulcanize/vulcanizedb/pkg/datastore"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
@ -33,7 +31,7 @@ import (
var _ = Describe("Drip file ilk repository", func() { var _ = Describe("Drip file ilk repository", func() {
var ( var (
db *postgres.DB db *postgres.DB
dripFileIlkRepository ilk.Repository dripFileIlkRepository ilk.DripFileIlkRepository
err error err error
headerRepository datastore.HeaderRepository headerRepository datastore.HeaderRepository
) )
@ -42,7 +40,8 @@ var _ = Describe("Drip file ilk repository", func() {
db = test_config.NewTestDB(test_config.NewTestNode()) db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
dripFileIlkRepository = ilk.NewDripFileIlkRepository(db) dripFileIlkRepository = ilk.DripFileIlkRepository{}
dripFileIlkRepository.SetDB(db)
}) })
Describe("Create", func() { Describe("Create", func() {
@ -52,7 +51,7 @@ var _ = Describe("Drip file ilk repository", func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = dripFileIlkRepository.Create(headerID, []ilk.DripFileIlkModel{test_data.DripFileIlkModel}) err = dripFileIlkRepository.Create(headerID, []interface{}{test_data.DripFileIlkModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -69,7 +68,6 @@ var _ = Describe("Drip file ilk repository", func() {
}) })
It("marks header as checked for logs", func() { It("marks header as checked for logs", func() {
Expect(err).NotTo(HaveOccurred())
var headerChecked bool var headerChecked bool
err = db.Get(&headerChecked, `SELECT drip_file_ilk_checked FROM public.checked_headers WHERE header_id = $1`, headerID) err = db.Get(&headerChecked, `SELECT drip_file_ilk_checked FROM public.checked_headers WHERE header_id = $1`, headerID)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -77,7 +75,7 @@ var _ = Describe("Drip file ilk repository", func() {
}) })
It("does not duplicate drip file events", func() { It("does not duplicate drip file events", func() {
err = dripFileIlkRepository.Create(headerID, []ilk.DripFileIlkModel{test_data.DripFileIlkModel}) err = dripFileIlkRepository.Create(headerID, []interface{}{test_data.DripFileIlkModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
@ -92,6 +90,12 @@ var _ = Describe("Drip file ilk repository", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(sql.ErrNoRows)) Expect(err).To(MatchError(sql.ErrNoRows))
}) })
It("Returns an error if model is of wrong type", func() {
err = dripFileIlkRepository.Create(headerID, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {
@ -139,12 +143,12 @@ var _ = Describe("Drip file ilk repository", func() {
blockNumbers = []int64{startingBlock, dripFileBlock, endingBlock, endingBlock + 1} blockNumbers = []int64{startingBlock, dripFileBlock, endingBlock, endingBlock + 1}
headerIDs = []int64{} headerIDs = []int64{}
for _, n := range blockNumbers { for _, n := range blockNumbers {
headerID, err := headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) headerID, err := headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
headerIDs = append(headerIDs, headerID) headerIDs = append(headerIDs, headerID)
} }
}) })
It("returns headers with no associated drip file event", func() { It("returns headers with no associated drip file event", func() {
@ -179,7 +183,8 @@ var _ = Describe("Drip file ilk repository", func() {
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
dripFileIlkRepositoryTwo := ilk.NewDripFileIlkRepository(dbTwo) dripFileIlkRepositoryTwo := ilk.DripFileIlkRepository{}
dripFileIlkRepositoryTwo.SetDB(dbTwo)
err := dripFileIlkRepository.MarkHeaderChecked(headerIDs[0]) err := dripFileIlkRepository.MarkHeaderChecked(headerIDs[0])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -1,79 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ilk
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type DripFileIlkTransformer struct {
Config shared.TransformerConfig
Converter Converter
Fetcher shared.LogFetcher
Repository Repository
}
type DripFileIlkTransformerInitializer struct {
Config shared.TransformerConfig
}
func (initializer DripFileIlkTransformerInitializer) NewDripFileIlkTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := DripFileIlkConverter{}
fetcher := shared.NewFetcher(blockChain)
repository := NewDripFileIlkRepository(db)
return DripFileIlkTransformer{
Config: initializer.Config,
Converter: converter,
Fetcher: fetcher,
Repository: repository,
}
}
func (transformer DripFileIlkTransformer) Execute() error {
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
return err
}
log.Printf("Fetching drip file ilk event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
topics := [][]common.Hash{{common.HexToHash(shared.DripFileIlkSignature)}}
matchingLogs, err := transformer.Fetcher.FetchLogs(drip_file.DripFileConfig.ContractAddresses, topics, header.BlockNumber)
if err != nil {
return err
}
if len(matchingLogs) < 1 {
err = transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
}
model, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
return err
}
err = transformer.Repository.Create(header.Id, model)
if err != nil {
return err
}
}
return nil
}

View File

@ -19,10 +19,11 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/ilk" "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/ilk"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
@ -31,31 +32,45 @@ import (
) )
var _ = Describe("Drip file ilk transformer", func() { var _ = Describe("Drip file ilk transformer", func() {
It("gets missing headers for block numbers specified in config", func() { var (
repository := &ilk_mocks.MockDripFileIlkRepository{} config = ilk.DripFileIlkConfig
transformer := ilk.DripFileIlkTransformer{ fetcher mocks.MockLogFetcher
Config: drip_file.DripFileConfig, converter ilk_mocks.MockDripFileIlkConverter
Fetcher: &mocks.MockLogFetcher{}, repository ilk_mocks.MockDripFileIlkRepository
Converter: &ilk_mocks.MockDripFileIlkConverter{}, transformer shared.Transformer
Repository: repository, headerOne core.Header
} headerTwo core.Header
)
BeforeEach(func() {
fetcher = mocks.MockLogFetcher{}
converter = ilk_mocks.MockDripFileIlkConverter{}
repository = ilk_mocks.MockDripFileIlkRepository{}
transformer = factories.Transformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}.NewTransformer(nil, nil)
headerOne = core.Header{BlockNumber: rand.Int63(), Id: rand.Int63()}
headerTwo = core.Header{BlockNumber: rand.Int63(), Id: rand.Int63()}
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
})
It("gets missing headers for block numbers specified in config", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedStartingBlockNumber).To(Equal(drip_file.DripFileConfig.StartingBlockNumber)) Expect(repository.PassedStartingBlockNumber).To(Equal(config.StartingBlockNumber))
Expect(repository.PassedEndingBlockNumber).To(Equal(drip_file.DripFileConfig.EndingBlockNumber)) Expect(repository.PassedEndingBlockNumber).To(Equal(config.EndingBlockNumber))
}) })
It("returns error if repository returns error for missing headers", func() { It("returns error if repository returns error for missing headers", func() {
repository := &ilk_mocks.MockDripFileIlkRepository{} repository.SetMissingHeadersError(fakes.FakeError)
repository.SetMissingHeadersErr(fakes.FakeError)
transformer := ilk.DripFileIlkTransformer{
Fetcher: &mocks.MockLogFetcher{},
Converter: &ilk_mocks.MockDripFileIlkConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@ -63,33 +78,18 @@ var _ = Describe("Drip file ilk transformer", func() {
}) })
It("fetches logs for missing headers", func() { It("fetches logs for missing headers", func() {
fetcher := &mocks.MockLogFetcher{} repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
repository := &ilk_mocks.MockDripFileIlkRepository{}
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}, {BlockNumber: 2}})
transformer := ilk.DripFileIlkTransformer{
Fetcher: fetcher,
Converter: &ilk_mocks.MockDripFileIlkConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(Equal([]int64{1, 2})) Expect(fetcher.FetchedBlocks).To(Equal([]int64{headerOne.BlockNumber, headerTwo.BlockNumber}))
Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{drip_file.DripFileConfig.ContractAddresses, drip_file.DripFileConfig.ContractAddresses})) Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{config.ContractAddresses, config.ContractAddresses}))
Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.DripFileIlkSignature)}})) Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.DripFileIlkSignature)}}))
}) })
It("returns error if fetcher returns error", func() { It("returns error if fetcher returns error", func() {
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetcherError(fakes.FakeError) fetcher.SetFetcherError(fakes.FakeError)
repository := &ilk_mocks.MockDripFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := ilk.DripFileIlkTransformer{
Fetcher: fetcher,
Converter: &ilk_mocks.MockDripFileIlkConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -98,34 +98,16 @@ var _ = Describe("Drip file ilk transformer", func() {
}) })
It("marks header checked if no logs returned", func() { It("marks header checked if no logs returned", func() {
mockConverter := &ilk_mocks.MockDripFileIlkConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &ilk_mocks.MockDripFileIlkRepository{}
headerID := int64(123)
mockRepository.SetMissingHeaders([]core.Header{{Id: headerID}})
mockFetcher := &mocks.MockLogFetcher{}
transformer := ilk.DripFileIlkTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mockRepository.AssertMarkHeaderCheckedCalledWith(headerID) repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
}) })
It("returns error if marking header checked returns err", func() { It("returns error if marking header checked returns err", func() {
mockConverter := &ilk_mocks.MockDripFileIlkConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &ilk_mocks.MockDripFileIlkRepository{} repository.SetMarkHeaderCheckedError(fakes.FakeError)
mockRepository.SetMissingHeaders([]core.Header{{Id: int64(123)}})
mockRepository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockFetcher := &mocks.MockLogFetcher{}
transformer := ilk.DripFileIlkTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
@ -134,16 +116,8 @@ var _ = Describe("Drip file ilk transformer", func() {
}) })
It("converts matching logs", func() { It("converts matching logs", func() {
converter := &ilk_mocks.MockDripFileIlkConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileIlkLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileIlkLog})
repository := &ilk_mocks.MockDripFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := ilk.DripFileIlkTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -152,17 +126,9 @@ var _ = Describe("Drip file ilk transformer", func() {
}) })
It("returns error if converter returns error", func() { It("returns error if converter returns error", func() {
converter := &ilk_mocks.MockDripFileIlkConverter{}
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileIlkLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileIlkLog})
repository := &ilk_mocks.MockDripFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := ilk.DripFileIlkTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -171,37 +137,20 @@ var _ = Describe("Drip file ilk transformer", func() {
}) })
It("persists drip file model", func() { It("persists drip file model", func() {
converter := &ilk_mocks.MockDripFileIlkConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileIlkLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileIlkLog})
repository := &ilk_mocks.MockDripFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
fakeHeader := core.Header{BlockNumber: 1, Id: 2}
repository.SetMissingHeaders([]core.Header{fakeHeader})
transformer := ilk.DripFileIlkTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(fakeHeader.Id)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]ilk.DripFileIlkModel{test_data.DripFileIlkModel})) Expect(repository.PassedModels).To(Equal([]interface{}{test_data.DripFileIlkModel}))
}) })
It("returns error if repository returns error for create", func() { It("returns error if repository returns error for create", func() {
converter := &ilk_mocks.MockDripFileIlkConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileIlkLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileIlkLog})
repository := &ilk_mocks.MockDripFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1, Id: 2}})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
transformer := ilk.DripFileIlkTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()

View File

@ -0,0 +1,26 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package repo
import "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
var DripFileRepoConfig = shared.SingleTransformerConfig{
TransformerName: shared.DripFileRepoLabel,
ContractAddresses: []string{shared.DripContractAddress},
ContractAbi: shared.DripABI,
Topic: shared.DripFileRepoSignature,
StartingBlockNumber: 0,
EndingBlockNumber: 10000000,
}

View File

@ -22,25 +22,23 @@ import (
"math/big" "math/big"
) )
type Converter interface {
ToModels(ethLogs []types.Log) ([]DripFileRepoModel, error)
}
type DripFileRepoConverter struct{} type DripFileRepoConverter struct{}
func (DripFileRepoConverter) ToModels(ethLogs []types.Log) ([]DripFileRepoModel, error) { func (DripFileRepoConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []DripFileRepoModel var models []interface{}
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := verifyLog(ethLog) err := verifyLog(ethLog)
if err != nil { if err != nil {
return nil, err return nil, err
} }
what := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00")) what := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00"))
data := big.NewInt(0).SetBytes(ethLog.Topics[3].Bytes()).String() data := big.NewInt(0).SetBytes(ethLog.Topics[3].Bytes()).String()
raw, err := json.Marshal(ethLog) raw, err := json.Marshal(ethLog)
if err != nil { if err != nil {
return nil, err return nil, err
} }
model := DripFileRepoModel{ model := DripFileRepoModel{
What: what, What: what,
Data: data, Data: data,

View File

@ -44,6 +44,6 @@ var _ = Describe("Drip file repo converter", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1)) Expect(len(models)).To(Equal(1))
Expect(models[0]).To(Equal(test_data.DripFileRepoModel)) Expect(models[0].(repo.DripFileRepoModel)).To(Equal(test_data.DripFileRepoModel))
}) })
}) })

View File

@ -15,56 +15,58 @@
package repo package repo
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type Repository interface {
Create(headerID int64, models []DripFileRepoModel) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type DripFileRepoRepository struct { type DripFileRepoRepository struct {
db *postgres.DB db *postgres.DB
} }
func NewDripFileRepoRepository(db *postgres.DB) DripFileRepoRepository { func (repository DripFileRepoRepository) Create(headerID int64, models []interface{}) error {
return DripFileRepoRepository{db: db}
}
func (repository DripFileRepoRepository) Create(headerID int64, models []DripFileRepoModel) error {
tx, err := repository.db.Begin() tx, err := repository.db.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, model := range models { for _, model := range models {
repo, ok := model.(DripFileRepoModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, DripFileRepoModel{})
}
_, err = tx.Exec( _, err = tx.Exec(
`INSERT into maker.drip_file_repo (header_id, what, data, log_idx, tx_idx, raw_log) `INSERT into maker.drip_file_repo (header_id, what, data, log_idx, tx_idx, raw_log)
VALUES($1, $2, $3::NUMERIC, $4, $5, $6)`, VALUES($1, $2, $3::NUMERIC, $4, $5, $6)`,
headerID, model.What, model.Data, model.LogIndex, model.TransactionIndex, model.Raw, headerID, repo.What, repo.Data, repo.LogIndex, repo.TransactionIndex, repo.Raw,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
} }
_, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_repo_checked) _, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_repo_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET drip_file_repo_checked = $2`, headerID, true) UPDATE SET drip_file_repo_checked = $2`, headerID, true)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
return tx.Commit() return tx.Commit()
} }
func (repository DripFileRepoRepository) MarkHeaderChecked(headerID int64) error { func (repository DripFileRepoRepository) MarkHeaderChecked(headerID int64) error {
_, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_repo_checked) _, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_repo_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET drip_file_repo_checked = $2`, headerID, true) UPDATE SET drip_file_repo_checked = $2`, headerID, true)
return err return err
} }
@ -73,14 +75,18 @@ func (repository DripFileRepoRepository) MissingHeaders(startingBlockNumber, end
err := repository.db.Select( err := repository.db.Select(
&result, &result,
`SELECT headers.id, headers.block_number FROM headers `SELECT headers.id, headers.block_number FROM headers
LEFT JOIN checked_headers on headers.id = header_id LEFT JOIN checked_headers on headers.id = header_id
WHERE (header_id ISNULL OR drip_file_repo_checked IS FALSE) WHERE (header_id ISNULL OR drip_file_repo_checked IS FALSE)
AND headers.block_number >= $1 AND headers.block_number >= $1
AND headers.block_number <= $2 AND headers.block_number <= $2
AND headers.eth_node_fingerprint = $3`, AND headers.eth_node_fingerprint = $3`,
startingBlockNumber, startingBlockNumber,
endingBlockNumber, endingBlockNumber,
repository.db.Node.ID, repository.db.Node.ID,
) )
return result, err return result, err
} }
func (repository *DripFileRepoRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -16,6 +16,7 @@ package repo_test
import ( import (
"database/sql" "database/sql"
"math/rand"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -33,7 +34,7 @@ import (
var _ = Describe("Drip file repo repository", func() { var _ = Describe("Drip file repo repository", func() {
var ( var (
db *postgres.DB db *postgres.DB
dripFileRepoRepository repo.Repository dripFileRepoRepository repo.DripFileRepoRepository
err error err error
headerRepository datastore.HeaderRepository headerRepository datastore.HeaderRepository
) )
@ -42,7 +43,8 @@ var _ = Describe("Drip file repo repository", func() {
db = test_config.NewTestDB(core.Node{}) db = test_config.NewTestDB(core.Node{})
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
dripFileRepoRepository = repo.NewDripFileRepoRepository(db) dripFileRepoRepository = repo.DripFileRepoRepository{}
dripFileRepoRepository.SetDB(db)
}) })
Describe("Create", func() { Describe("Create", func() {
@ -52,7 +54,7 @@ var _ = Describe("Drip file repo repository", func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = dripFileRepoRepository.Create(headerID, []repo.DripFileRepoModel{test_data.DripFileRepoModel}) err = dripFileRepoRepository.Create(headerID, []interface{}{test_data.DripFileRepoModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -75,7 +77,7 @@ var _ = Describe("Drip file repo repository", func() {
}) })
It("does not duplicate drip file events", func() { It("does not duplicate drip file events", func() {
err = dripFileRepoRepository.Create(headerID, []repo.DripFileRepoModel{test_data.DripFileRepoModel}) err = dripFileRepoRepository.Create(headerID, []interface{}{test_data.DripFileRepoModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
@ -90,6 +92,12 @@ var _ = Describe("Drip file repo repository", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(sql.ErrNoRows)) Expect(err).To(MatchError(sql.ErrNoRows))
}) })
It("Returns an error if model is of wrong type", func() {
err = dripFileRepoRepository.Create(headerID, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {
@ -130,7 +138,7 @@ var _ = Describe("Drip file repo repository", func() {
) )
BeforeEach(func() { BeforeEach(func() {
startingBlock = GinkgoRandomSeed() startingBlock = rand.Int63()
dripFileBlock = startingBlock + 1 dripFileBlock = startingBlock + 1
endingBlock = startingBlock + 2 endingBlock = startingBlock + 2
@ -176,7 +184,8 @@ var _ = Describe("Drip file repo repository", func() {
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
dripFileRepoRepositoryTwo := repo.NewDripFileRepoRepository(dbTwo) dripFileRepoRepositoryTwo := repo.DripFileRepoRepository{}
dripFileRepoRepositoryTwo.SetDB(dbTwo)
err := dripFileRepoRepository.MarkHeaderChecked(headerIDs[0]) err := dripFileRepoRepository.MarkHeaderChecked(headerIDs[0])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -1,79 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package repo
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type DripFileRepoTransformer struct {
Config shared.TransformerConfig
Converter Converter
Fetcher shared.LogFetcher
Repository Repository
}
type DripFileRepoTransformerInitializer struct {
Config shared.TransformerConfig
}
func (initializer DripFileRepoTransformerInitializer) NewDripFileRepoTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := DripFileRepoConverter{}
fetcher := shared.NewFetcher(blockChain)
repository := NewDripFileRepoRepository(db)
return DripFileRepoTransformer{
Config: initializer.Config,
Converter: converter,
Fetcher: fetcher,
Repository: repository,
}
}
func (transformer DripFileRepoTransformer) Execute() error {
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
return err
}
log.Printf("Fetching drip file repo event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
topics := [][]common.Hash{{common.HexToHash(shared.DripFileRepoSignature)}}
matchingLogs, err := transformer.Fetcher.FetchLogs(drip_file.DripFileConfig.ContractAddresses, topics, header.BlockNumber)
if err != nil {
return err
}
if len(matchingLogs) < 1 {
err = transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
}
model, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
return err
}
err = transformer.Repository.Create(header.Id, model)
if err != nil {
return err
}
}
return nil
}

View File

@ -19,10 +19,11 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/repo" "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/repo"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
@ -31,31 +32,45 @@ import (
) )
var _ = Describe("Drip file repo transformer", func() { var _ = Describe("Drip file repo transformer", func() {
It("gets missing headers for block numbers specified in config", func() { var (
repository := &repo_mocks.MockDripFileRepoRepository{} config = repo.DripFileRepoConfig
transformer := repo.DripFileRepoTransformer{ fetcher mocks.MockLogFetcher
Config: drip_file.DripFileConfig, converter repo_mocks.MockDripFileRepoConverter
Fetcher: &mocks.MockLogFetcher{}, repository repo_mocks.MockDripFileRepoRepository
Converter: &repo_mocks.MockDripFileRepoConverter{}, transformer shared.Transformer
Repository: repository, headerOne core.Header
} headerTwo core.Header
)
BeforeEach(func() {
fetcher = mocks.MockLogFetcher{}
converter = repo_mocks.MockDripFileRepoConverter{}
repository = repo_mocks.MockDripFileRepoRepository{}
transformer = factories.Transformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}.NewTransformer(nil, nil)
headerOne = core.Header{BlockNumber: rand.Int63(), Id: rand.Int63()}
headerTwo = core.Header{BlockNumber: rand.Int63(), Id: rand.Int63()}
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
})
It("gets missing headers for block numbers specified in config", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedStartingBlockNumber).To(Equal(drip_file.DripFileConfig.StartingBlockNumber)) Expect(repository.PassedStartingBlockNumber).To(Equal(config.StartingBlockNumber))
Expect(repository.PassedEndingBlockNumber).To(Equal(drip_file.DripFileConfig.EndingBlockNumber)) Expect(repository.PassedEndingBlockNumber).To(Equal(config.EndingBlockNumber))
}) })
It("returns error if repository returns error for missing headers", func() { It("returns error if repository returns error for missing headers", func() {
repository := &repo_mocks.MockDripFileRepoRepository{} repository.SetMissingHeadersError(fakes.FakeError)
repository.SetMissingHeadersErr(fakes.FakeError)
transformer := repo.DripFileRepoTransformer{
Fetcher: &mocks.MockLogFetcher{},
Converter: &repo_mocks.MockDripFileRepoConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@ -63,33 +78,18 @@ var _ = Describe("Drip file repo transformer", func() {
}) })
It("fetches logs for missing headers", func() { It("fetches logs for missing headers", func() {
fetcher := &mocks.MockLogFetcher{} repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
repository := &repo_mocks.MockDripFileRepoRepository{}
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}, {BlockNumber: 2}})
transformer := repo.DripFileRepoTransformer{
Fetcher: fetcher,
Converter: &repo_mocks.MockDripFileRepoConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(Equal([]int64{1, 2})) Expect(fetcher.FetchedBlocks).To(Equal([]int64{headerOne.BlockNumber, headerTwo.BlockNumber}))
Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{drip_file.DripFileConfig.ContractAddresses, drip_file.DripFileConfig.ContractAddresses})) Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{config.ContractAddresses, config.ContractAddresses}))
Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.DripFileRepoSignature)}})) Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.DripFileRepoSignature)}}))
}) })
It("returns error if fetcher returns error", func() { It("returns error if fetcher returns error", func() {
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetcherError(fakes.FakeError) fetcher.SetFetcherError(fakes.FakeError)
repository := &repo_mocks.MockDripFileRepoRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := repo.DripFileRepoTransformer{
Fetcher: fetcher,
Converter: &repo_mocks.MockDripFileRepoConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -98,34 +98,16 @@ var _ = Describe("Drip file repo transformer", func() {
}) })
It("marks header checked if no logs returned", func() { It("marks header checked if no logs returned", func() {
mockConverter := &repo_mocks.MockDripFileRepoConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &repo_mocks.MockDripFileRepoRepository{}
headerID := int64(123)
mockRepository.SetMissingHeaders([]core.Header{{Id: headerID}})
mockFetcher := &mocks.MockLogFetcher{}
transformer := repo.DripFileRepoTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mockRepository.AssertMarkHeaderCheckedCalledWith(headerID) repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
}) })
It("returns error if marking header checked returns err", func() { It("returns error if marking header checked returns err", func() {
mockConverter := &repo_mocks.MockDripFileRepoConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &repo_mocks.MockDripFileRepoRepository{} repository.SetMarkHeaderCheckedError(fakes.FakeError)
mockRepository.SetMissingHeaders([]core.Header{{Id: int64(123)}})
mockRepository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockFetcher := &mocks.MockLogFetcher{}
transformer := repo.DripFileRepoTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
@ -134,16 +116,8 @@ var _ = Describe("Drip file repo transformer", func() {
}) })
It("converts matching logs", func() { It("converts matching logs", func() {
converter := &repo_mocks.MockDripFileRepoConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileRepoLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileRepoLog})
repository := &repo_mocks.MockDripFileRepoRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := repo.DripFileRepoTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -152,17 +126,9 @@ var _ = Describe("Drip file repo transformer", func() {
}) })
It("returns error if converter returns error", func() { It("returns error if converter returns error", func() {
converter := &repo_mocks.MockDripFileRepoConverter{}
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileRepoLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileRepoLog})
repository := &repo_mocks.MockDripFileRepoRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := repo.DripFileRepoTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -171,37 +137,20 @@ var _ = Describe("Drip file repo transformer", func() {
}) })
It("persists drip file model", func() { It("persists drip file model", func() {
converter := &repo_mocks.MockDripFileRepoConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileRepoLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileRepoLog})
repository := &repo_mocks.MockDripFileRepoRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
fakeHeader := core.Header{BlockNumber: 1, Id: 2}
repository.SetMissingHeaders([]core.Header{fakeHeader})
transformer := repo.DripFileRepoTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(fakeHeader.Id)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]repo.DripFileRepoModel{test_data.DripFileRepoModel})) Expect(repository.PassedModels).To(Equal([]interface{}{test_data.DripFileRepoModel}))
}) })
It("returns error if repository returns error for create", func() { It("returns error if repository returns error for create", func() {
converter := &repo_mocks.MockDripFileRepoConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileRepoLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileRepoLog})
repository := &repo_mocks.MockDripFileRepoRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1, Id: 2}})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
transformer := repo.DripFileRepoTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()

View File

@ -0,0 +1,26 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package vow
import "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
var DripFileVowConfig = shared.SingleTransformerConfig{
TransformerName: shared.DripFileVowLabel,
ContractAddresses: []string{shared.DripContractAddress},
ContractAbi: shared.DripABI,
Topic: shared.DripFileVowSignature,
StartingBlockNumber: 0,
EndingBlockNumber: 10000000,
}

View File

@ -22,25 +22,23 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
type Converter interface {
ToModels(ethLogs []types.Log) ([]DripFileVowModel, error)
}
type DripFileVowConverter struct{} type DripFileVowConverter struct{}
func (DripFileVowConverter) ToModels(ethLogs []types.Log) ([]DripFileVowModel, error) { func (DripFileVowConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []DripFileVowModel var models []interface{}
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := verifyLog(ethLog) err := verifyLog(ethLog)
if err != nil { if err != nil {
return nil, err return nil, err
} }
what := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00")) what := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00"))
data := common.BytesToAddress(ethLog.Topics[3].Bytes()).String() data := common.BytesToAddress(ethLog.Topics[3].Bytes()).String()
raw, err := json.Marshal(ethLog) raw, err := json.Marshal(ethLog)
if err != nil { if err != nil {
return nil, err return nil, err
} }
model := DripFileVowModel{ model := DripFileVowModel{
What: what, What: what,
Data: data, Data: data,

View File

@ -44,6 +44,6 @@ var _ = Describe("Drip file repo converter", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1)) Expect(len(models)).To(Equal(1))
Expect(models[0]).To(Equal(test_data.DripFileVowModel)) Expect(models[0].(vow.DripFileVowModel)).To(Equal(test_data.DripFileVowModel))
}) })
}) })

View File

@ -15,56 +15,57 @@
package vow package vow
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type Repository interface {
Create(headerID int64, models []DripFileVowModel) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type DripFileVowRepository struct { type DripFileVowRepository struct {
db *postgres.DB db *postgres.DB
} }
func NewDripFileVowRepository(db *postgres.DB) DripFileVowRepository { func (repository DripFileVowRepository) Create(headerID int64, models []interface{}) error {
return DripFileVowRepository{db: db}
}
func (repository DripFileVowRepository) Create(headerID int64, models []DripFileVowModel) error {
tx, err := repository.db.Begin() tx, err := repository.db.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, model := range models { for _, model := range models {
vow, ok := model.(DripFileVowModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, DripFileVowModel{})
}
_, err = tx.Exec( _, err = tx.Exec(
`INSERT into maker.drip_file_vow (header_id, what, data, log_idx, tx_idx, raw_log) `INSERT into maker.drip_file_vow (header_id, what, data, log_idx, tx_idx, raw_log)
VALUES($1, $2, $3, $4, $5, $6)`, VALUES($1, $2, $3, $4, $5, $6)`,
headerID, model.What, model.Data, model.LogIndex, model.TransactionIndex, model.Raw, headerID, vow.What, vow.Data, vow.LogIndex, vow.TransactionIndex, vow.Raw,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
} }
_, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_vow_checked) _, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_vow_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET drip_file_vow_checked = $2`, headerID, true) UPDATE SET drip_file_vow_checked = $2`, headerID, true)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
return tx.Commit() return tx.Commit()
} }
func (repository DripFileVowRepository) MarkHeaderChecked(headerID int64) error { func (repository DripFileVowRepository) MarkHeaderChecked(headerID int64) error {
_, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_vow_checked) _, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, drip_file_vow_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET drip_file_vow_checked = $2`, headerID, true) UPDATE SET drip_file_vow_checked = $2`, headerID, true)
return err return err
} }
@ -73,14 +74,18 @@ func (repository DripFileVowRepository) MissingHeaders(startingBlockNumber, endi
err := repository.db.Select( err := repository.db.Select(
&result, &result,
`SELECT headers.id, headers.block_number FROM headers `SELECT headers.id, headers.block_number FROM headers
LEFT JOIN checked_headers on headers.id = header_id LEFT JOIN checked_headers on headers.id = header_id
WHERE (header_id ISNULL OR drip_file_vow_checked IS FALSE) WHERE (header_id ISNULL OR drip_file_vow_checked IS FALSE)
AND headers.block_number >= $1 AND headers.block_number >= $1
AND headers.block_number <= $2 AND headers.block_number <= $2
AND headers.eth_node_fingerprint = $3`, AND headers.eth_node_fingerprint = $3`,
startingBlockNumber, startingBlockNumber,
endingBlockNumber, endingBlockNumber,
repository.db.Node.ID, repository.db.Node.ID,
) )
return result, err return result, err
} }
func (repository *DripFileVowRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -16,6 +16,7 @@ package vow_test
import ( import (
"database/sql" "database/sql"
"math/rand"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -33,7 +34,7 @@ import (
var _ = Describe("Drip file vow repository", func() { var _ = Describe("Drip file vow repository", func() {
var ( var (
db *postgres.DB db *postgres.DB
dripFileVowRepository vow.Repository dripFileVowRepository vow.DripFileVowRepository
err error err error
headerRepository datastore.HeaderRepository headerRepository datastore.HeaderRepository
) )
@ -42,7 +43,8 @@ var _ = Describe("Drip file vow repository", func() {
db = test_config.NewTestDB(core.Node{}) db = test_config.NewTestDB(core.Node{})
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
dripFileVowRepository = vow.NewDripFileVowRepository(db) dripFileVowRepository = vow.DripFileVowRepository{}
dripFileVowRepository.SetDB(db)
}) })
Describe("Create", func() { Describe("Create", func() {
@ -52,7 +54,7 @@ var _ = Describe("Drip file vow repository", func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = dripFileVowRepository.Create(headerID, []vow.DripFileVowModel{test_data.DripFileVowModel}) err = dripFileVowRepository.Create(headerID, []interface{}{test_data.DripFileVowModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -75,7 +77,7 @@ var _ = Describe("Drip file vow repository", func() {
}) })
It("does not duplicate drip file events", func() { It("does not duplicate drip file events", func() {
err = dripFileVowRepository.Create(headerID, []vow.DripFileVowModel{test_data.DripFileVowModel}) err = dripFileVowRepository.Create(headerID, []interface{}{test_data.DripFileVowModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
@ -90,6 +92,12 @@ var _ = Describe("Drip file vow repository", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(sql.ErrNoRows)) Expect(err).To(MatchError(sql.ErrNoRows))
}) })
It("Returns an error if model is of wrong type", func() {
err = dripFileVowRepository.Create(headerID, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {
@ -130,7 +138,7 @@ var _ = Describe("Drip file vow repository", func() {
) )
BeforeEach(func() { BeforeEach(func() {
startingBlock = GinkgoRandomSeed() startingBlock = rand.Int63()
dripFileBlock = startingBlock + 1 dripFileBlock = startingBlock + 1
endingBlock = startingBlock + 2 endingBlock = startingBlock + 2
@ -176,7 +184,8 @@ var _ = Describe("Drip file vow repository", func() {
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
dripFileVowRepositoryTwo := vow.NewDripFileVowRepository(dbTwo) dripFileVowRepositoryTwo := vow.DripFileVowRepository{}
dripFileVowRepositoryTwo.SetDB(dbTwo)
err := dripFileVowRepository.MarkHeaderChecked(headerIDs[0]) err := dripFileVowRepository.MarkHeaderChecked(headerIDs[0])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -1,79 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package vow
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type DripFileVowTransformerInitializer struct {
Config shared.TransformerConfig
}
func (initializer DripFileVowTransformerInitializer) NewDripFileVowTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := DripFileVowConverter{}
fetcher := shared.NewFetcher(blockChain)
repository := NewDripFileVowRepository(db)
return DripFileVowTransformer{
Config: initializer.Config,
Converter: converter,
Fetcher: fetcher,
Repository: repository,
}
}
type DripFileVowTransformer struct {
Config shared.TransformerConfig
Converter Converter
Fetcher shared.LogFetcher
Repository Repository
}
func (transformer DripFileVowTransformer) Execute() error {
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
return err
}
log.Printf("Fetching drip file vow event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
topics := [][]common.Hash{{common.HexToHash(shared.DripFileVowSignature)}}
matchingLogs, err := transformer.Fetcher.FetchLogs(drip_file.DripFileConfig.ContractAddresses, topics, header.BlockNumber)
if err != nil {
return err
}
if len(matchingLogs) < 1 {
err = transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
}
model, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
return err
}
err = transformer.Repository.Create(header.Id, model)
if err != nil {
return err
}
}
return nil
}

View File

@ -19,10 +19,11 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow" "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
@ -31,31 +32,45 @@ import (
) )
var _ = Describe("Drip file vow transformer", func() { var _ = Describe("Drip file vow transformer", func() {
It("gets missing headers for block numbers specified in config", func() { var (
repository := &vow_mocks.MockDripFileVowRepository{} config = vow.DripFileVowConfig
transformer := vow.DripFileVowTransformer{ fetcher mocks.MockLogFetcher
Config: drip_file.DripFileConfig, converter vow_mocks.MockDripFileVowConverter
Fetcher: &mocks.MockLogFetcher{}, repository vow_mocks.MockDripFileVowRepository
Converter: &vow_mocks.MockDripFileVowConverter{}, transformer shared.Transformer
Repository: repository, headerOne core.Header
} headerTwo core.Header
)
BeforeEach(func() {
fetcher = mocks.MockLogFetcher{}
converter = vow_mocks.MockDripFileVowConverter{}
repository = vow_mocks.MockDripFileVowRepository{}
transformer = factories.Transformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}.NewTransformer(nil, nil)
headerOne = core.Header{BlockNumber: rand.Int63(), Id: rand.Int63()}
headerTwo = core.Header{BlockNumber: rand.Int63(), Id: rand.Int63()}
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
})
It("gets missing headers for block numbers specified in config", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedStartingBlockNumber).To(Equal(drip_file.DripFileConfig.StartingBlockNumber)) Expect(repository.PassedStartingBlockNumber).To(Equal(config.StartingBlockNumber))
Expect(repository.PassedEndingBlockNumber).To(Equal(drip_file.DripFileConfig.EndingBlockNumber)) Expect(repository.PassedEndingBlockNumber).To(Equal(config.EndingBlockNumber))
}) })
It("returns error if repository returns error for missing headers", func() { It("returns error if repository returns error for missing headers", func() {
repository := &vow_mocks.MockDripFileVowRepository{} repository.SetMissingHeadersError(fakes.FakeError)
repository.SetMissingHeadersErr(fakes.FakeError)
transformer := vow.DripFileVowTransformer{
Fetcher: &mocks.MockLogFetcher{},
Converter: &vow_mocks.MockDripFileVowConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@ -63,33 +78,18 @@ var _ = Describe("Drip file vow transformer", func() {
}) })
It("fetches logs for missing headers", func() { It("fetches logs for missing headers", func() {
fetcher := &mocks.MockLogFetcher{} repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
repository := &vow_mocks.MockDripFileVowRepository{}
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}, {BlockNumber: 2}})
transformer := vow.DripFileVowTransformer{
Fetcher: fetcher,
Converter: &vow_mocks.MockDripFileVowConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(Equal([]int64{1, 2})) Expect(fetcher.FetchedBlocks).To(Equal([]int64{headerOne.BlockNumber, headerTwo.BlockNumber}))
Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{drip_file.DripFileConfig.ContractAddresses, drip_file.DripFileConfig.ContractAddresses})) Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{config.ContractAddresses, config.ContractAddresses}))
Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.DripFileVowSignature)}})) Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.DripFileVowSignature)}}))
}) })
It("returns error if fetcher returns error", func() { It("returns error if fetcher returns error", func() {
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetcherError(fakes.FakeError) fetcher.SetFetcherError(fakes.FakeError)
repository := &vow_mocks.MockDripFileVowRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := vow.DripFileVowTransformer{
Fetcher: fetcher,
Converter: &vow_mocks.MockDripFileVowConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -98,34 +98,16 @@ var _ = Describe("Drip file vow transformer", func() {
}) })
It("marks header checked if no logs returned", func() { It("marks header checked if no logs returned", func() {
mockConverter := &vow_mocks.MockDripFileVowConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &vow_mocks.MockDripFileVowRepository{}
headerID := int64(123)
mockRepository.SetMissingHeaders([]core.Header{{Id: headerID}})
mockFetcher := &mocks.MockLogFetcher{}
transformer := vow.DripFileVowTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mockRepository.AssertMarkHeaderCheckedCalledWith(headerID) repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
}) })
It("returns error if marking header checked returns err", func() { It("returns error if marking header checked returns err", func() {
mockConverter := &vow_mocks.MockDripFileVowConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &vow_mocks.MockDripFileVowRepository{} repository.SetMarkHeaderCheckedError(fakes.FakeError)
mockRepository.SetMissingHeaders([]core.Header{{Id: int64(123)}})
mockRepository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockFetcher := &mocks.MockLogFetcher{}
transformer := vow.DripFileVowTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
@ -134,16 +116,8 @@ var _ = Describe("Drip file vow transformer", func() {
}) })
It("converts matching logs", func() { It("converts matching logs", func() {
converter := &vow_mocks.MockDripFileVowConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileVowLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileVowLog})
repository := &vow_mocks.MockDripFileVowRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := vow.DripFileVowTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -152,17 +126,9 @@ var _ = Describe("Drip file vow transformer", func() {
}) })
It("returns error if converter returns error", func() { It("returns error if converter returns error", func() {
converter := &vow_mocks.MockDripFileVowConverter{}
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileVowLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileVowLog})
repository := &vow_mocks.MockDripFileVowRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := vow.DripFileVowTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -171,37 +137,20 @@ var _ = Describe("Drip file vow transformer", func() {
}) })
It("persists drip file model", func() { It("persists drip file model", func() {
converter := &vow_mocks.MockDripFileVowConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileVowLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileVowLog})
repository := &vow_mocks.MockDripFileVowRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
fakeHeader := core.Header{BlockNumber: 1, Id: 2}
repository.SetMissingHeaders([]core.Header{fakeHeader})
transformer := vow.DripFileVowTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(fakeHeader.Id)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]vow.DripFileVowModel{test_data.DripFileVowModel})) Expect(repository.PassedModels).To(Equal([]interface{}{test_data.DripFileVowModel}))
}) })
It("returns error if repository returns error for create", func() { It("returns error if repository returns error for create", func() {
converter := &vow_mocks.MockDripFileVowConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileVowLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthDripFileVowLog})
repository := &vow_mocks.MockDripFileVowRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1, Id: 2}})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
transformer := vow.DripFileVowTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()

View File

@ -0,0 +1,97 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package factories
import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type Transformer struct {
Config shared.SingleTransformerConfig
Converter Converter
Repository Repository
Fetcher shared.SettableLogFetcher
}
type Converter interface {
ToModels(ethLog []types.Log) ([]interface{}, error)
}
type Repository interface {
Create(headerID int64, models []interface{}) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
SetDB(db *postgres.DB)
}
func (transformer Transformer) NewTransformer(db *postgres.DB, bc core.BlockChain) shared.Transformer {
transformer.Repository.SetDB(db)
transformer.Fetcher.SetBC(bc)
return transformer
}
func (transformer Transformer) Execute() error {
transformerName := transformer.Config.TransformerName
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
log.Printf("Error fetching mising headers in %v transformer: %v \n", transformerName, err)
return err
}
// Grab event signature from transformer config
// (Double-array structure required for go-ethereum FilterQuery)
var topic = [][]common.Hash{{common.HexToHash(transformer.Config.Topic)}}
log.Printf("Fetching %v event logs for %d headers \n", transformerName, len(missingHeaders))
for _, header := range missingHeaders {
// Fetch the missing logs for a given header
matchingLogs, err := transformer.Fetcher.FetchLogs(transformer.Config.ContractAddresses, topic, header.BlockNumber)
if err != nil {
log.Printf("Error fetching matching logs in %v transformer: %v", transformerName, err)
return err
}
// No matching logs, mark the header as checked for this type of logs
if len(matchingLogs) < 1 {
err := transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
log.Printf("Error marking header as checked in %v: %v", transformerName, err)
return err
}
// Continue with the next header; nothing to persist
continue
}
models, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
log.Printf("Error converting logs in %v: %v", transformerName, err)
return err
}
err = transformer.Repository.Create(header.Id, models)
if err != nil {
log.Printf("Error persisting %v record: %v", transformerName, err)
return err
}
}
return nil
}

View File

@ -17,8 +17,9 @@ package integration_tests
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow" "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow"
"github.com/vulcanize/vulcanizedb/test_config" "github.com/vulcanize/vulcanizedb/test_config"
) )
@ -26,7 +27,7 @@ import (
var _ = Describe("Drip File Vow Transformer", func() { var _ = Describe("Drip File Vow Transformer", func() {
It("transforms DripFileVow log events", func() { It("transforms DripFileVow log events", func() {
blockNumber := int64(8762197) blockNumber := int64(8762197)
config := drip_file.DripFileConfig config := vow.DripFileVowConfig
config.StartingBlockNumber = blockNumber config.StartingBlockNumber = blockNumber
config.EndingBlockNumber = blockNumber config.EndingBlockNumber = blockNumber
@ -41,8 +42,13 @@ var _ = Describe("Drip File Vow Transformer", func() {
err = persistHeader(rpcClient, db, blockNumber) err = persistHeader(rpcClient, db, blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
initializer := vow.DripFileVowTransformerInitializer{Config: config} initializer := factories.Transformer{
transformer := initializer.NewDripFileVowTransformer(db, blockchain) Config: config,
Fetcher: &shared.Fetcher{},
Converter: &vow.DripFileVowConverter{},
Repository: &vow.DripFileVowRepository{},
}
transformer := initializer.NewTransformer(db, blockchain)
err = transformer.Execute() err = transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -17,8 +17,9 @@ package integration_tests
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling" "github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling"
"github.com/vulcanize/vulcanizedb/test_config" "github.com/vulcanize/vulcanizedb/test_config"
) )
@ -26,7 +27,7 @@ import (
var _ = Describe("PitFileDebtCeiling Transformer", func() { var _ = Describe("PitFileDebtCeiling Transformer", func() {
It("fetches and transforms a PitFileDebtCeiling event from Kovan chain", func() { It("fetches and transforms a PitFileDebtCeiling event from Kovan chain", func() {
blockNumber := int64(8535578) blockNumber := int64(8535578)
config := pit_file.PitFileConfig config := debt_ceiling.DebtCeilingFileConfig
config.StartingBlockNumber = blockNumber config.StartingBlockNumber = blockNumber
config.EndingBlockNumber = blockNumber config.EndingBlockNumber = blockNumber
@ -41,8 +42,13 @@ var _ = Describe("PitFileDebtCeiling Transformer", func() {
err = persistHeader(rpcClient, db, blockNumber) err = persistHeader(rpcClient, db, blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
initializer := debt_ceiling.PitFileDebtCeilingTransformerInitializer{Config: config} initializer := factories.Transformer{
transformer := initializer.NewPitFileDebtCeilingTransformer(db, blockchain) Config: config,
Fetcher: &shared.Fetcher{},
Converter: &debt_ceiling.PitFileDebtCeilingConverter{},
Repository: &debt_ceiling.PitFileDebtCeilingRepository{},
}
transformer := initializer.NewTransformer(db, blockchain)
err = transformer.Execute() err = transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -17,8 +17,9 @@ package integration_tests
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/ilk" "github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/ilk"
"github.com/vulcanize/vulcanizedb/test_config" "github.com/vulcanize/vulcanizedb/test_config"
) )
@ -26,7 +27,7 @@ import (
var _ = Describe("PitFileIlk Transformer", func() { var _ = Describe("PitFileIlk Transformer", func() {
It("fetches and transforms a PitFileIlk event from Kovan chain", func() { It("fetches and transforms a PitFileIlk event from Kovan chain", func() {
blockNumber := int64(9103223) blockNumber := int64(9103223)
config := pit_file.PitFileConfig config := ilk.IlkFileConfig
config.StartingBlockNumber = blockNumber config.StartingBlockNumber = blockNumber
config.EndingBlockNumber = blockNumber config.EndingBlockNumber = blockNumber
@ -41,8 +42,13 @@ var _ = Describe("PitFileIlk Transformer", func() {
err = persistHeader(rpcClient, db, blockNumber) err = persistHeader(rpcClient, db, blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
initializer := ilk.PitFileIlkTransformerInitializer{Config: config} initializer := factories.Transformer{
transformer := initializer.NewPitFileIlkTransformer(db, blockchain) Config: config,
Fetcher: &shared.Fetcher{},
Converter: &ilk.PitFileIlkConverter{},
Repository: &ilk.PitFileIlkRepository{},
}
transformer := initializer.NewTransformer(db, blockchain)
err = transformer.Execute() err = transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -17,8 +17,9 @@ package integration_tests
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/stability_fee" "github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/stability_fee"
"github.com/vulcanize/vulcanizedb/test_config" "github.com/vulcanize/vulcanizedb/test_config"
) )
@ -26,7 +27,7 @@ import (
var _ = Describe("PitFileStabilityFee Transformer", func() { var _ = Describe("PitFileStabilityFee Transformer", func() {
It("fetches and transforms a PitFileStabilityFee event from Kovan chain", func() { It("fetches and transforms a PitFileStabilityFee event from Kovan chain", func() {
blockNumber := int64(8535544) blockNumber := int64(8535544)
config := pit_file.PitFileConfig config := stability_fee.StabilityFeeFileConfig
config.StartingBlockNumber = blockNumber config.StartingBlockNumber = blockNumber
config.EndingBlockNumber = blockNumber config.EndingBlockNumber = blockNumber
@ -41,8 +42,13 @@ var _ = Describe("PitFileStabilityFee Transformer", func() {
err = persistHeader(rpcClient, db, blockNumber) err = persistHeader(rpcClient, db, blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
initializer := stability_fee.PitFileStabilityFeeTransformerInitializer{Config: config} initializer := factories.Transformer{
transformer := initializer.NewPitFileStabilityFeeTransformer(db, blockchain) Config: config,
Fetcher: &shared.Fetcher{},
Converter: &stability_fee.PitFileStabilityFeeConverter{},
Repository: &stability_fee.PitFileStabilityFeeRepository{},
}
transformer := initializer.NewTransformer(db, blockchain)
err = transformer.Execute() err = transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -17,6 +17,8 @@ package integration_tests
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/tend" "github.com/vulcanize/vulcanizedb/pkg/transformers/tend"
"github.com/vulcanize/vulcanizedb/test_config" "github.com/vulcanize/vulcanizedb/test_config"
@ -40,8 +42,13 @@ var _ = Describe("Tend Transformer", func() {
err = persistHeader(rpcClient, db, blockNumber) err = persistHeader(rpcClient, db, blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
initializer := tend.TendTransformerInitializer{Config: config} initializer := factories.Transformer{
transformer := initializer.NewTendTransformer(db, blockchain) Config: config,
Fetcher: &shared.Fetcher{},
Converter: &tend.TendConverter{},
Repository: &tend.TendRepository{},
}
transformer := initializer.NewTransformer(db, blockchain)
err = transformer.Execute() err = transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -74,8 +81,13 @@ var _ = Describe("Tend Transformer", func() {
err = persistHeader(rpcClient, db, blockNumber) err = persistHeader(rpcClient, db, blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
initializer := tend.TendTransformerInitializer{Config: config} initializer := factories.Transformer{
transformer := initializer.NewTendTransformer(db, blockchain) Config: config,
Fetcher: &shared.Fetcher{},
Converter: &tend.TendConverter{},
Repository: &tend.TendRepository{},
}
transformer := initializer.NewTransformer(db, blockchain)
err = transformer.Execute() err = transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -17,6 +17,8 @@ package integration_tests
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/vat_init" "github.com/vulcanize/vulcanizedb/pkg/transformers/vat_init"
"github.com/vulcanize/vulcanizedb/test_config" "github.com/vulcanize/vulcanizedb/test_config"
@ -40,8 +42,13 @@ var _ = Describe("VatInit Transformer", func() {
err = persistHeader(rpcClient, db, blockNumber) err = persistHeader(rpcClient, db, blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
initializer := vat_init.VatInitTransformerInitializer{Config: config} initializer := factories.Transformer{
transformer := initializer.NewVatInitTransformer(db, blockchain) Config: config,
Fetcher: &shared.Fetcher{},
Converter: &vat_init.VatInitConverter{},
Repository: &vat_init.VatInitRepository{},
}
transformer := initializer.NewTransformer(db, blockchain)
err = transformer.Execute() err = transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -18,6 +18,8 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/vat_move" "github.com/vulcanize/vulcanizedb/pkg/transformers/vat_move"
"github.com/vulcanize/vulcanizedb/test_config" "github.com/vulcanize/vulcanizedb/test_config"
@ -41,8 +43,13 @@ var _ = Describe("VatMove Transformer", func() {
err = persistHeader(rpcClient, db, blockNumber) err = persistHeader(rpcClient, db, blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
initializer := vat_move.VatMoveTransformerInitializer{Config: config} initializer := factories.Transformer{
transformer := initializer.NewVatMoveTransformer(db, blockchain) Config: config,
Fetcher: &shared.Fetcher{},
Converter: &vat_move.VatMoveConverter{},
Repository: &vat_move.VatMoveRepository{},
}
transformer := initializer.NewTransformer(db, blockchain)
err = transformer.Execute() err = transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -12,16 +12,17 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package pit_file package debt_ceiling
import ( import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
) )
var PitFileConfig = shared.TransformerConfig{ var DebtCeilingFileConfig = shared.SingleTransformerConfig{
TransformerName: shared.PitFileDebtCeilingLabel,
ContractAddresses: []string{shared.PitContractAddress}, ContractAddresses: []string{shared.PitContractAddress},
ContractAbi: shared.PitABI, ContractAbi: shared.PitABI,
Topics: []string{shared.PitFileIlkSignature, shared.PitFileDebtCeilingSignature, shared.PitFileStabilityFeeSignature}, Topic: shared.PitFileDebtCeilingSignature,
StartingBlockNumber: 0, StartingBlockNumber: 0,
EndingBlockNumber: 10000000, EndingBlockNumber: 10000000,
} }

View File

@ -24,14 +24,10 @@ import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
) )
type Converter interface {
ToModels(ethLogs []types.Log) ([]PitFileDebtCeilingModel, error)
}
type PitFileDebtCeilingConverter struct{} type PitFileDebtCeilingConverter struct{}
func (PitFileDebtCeilingConverter) ToModels(ethLogs []types.Log) ([]PitFileDebtCeilingModel, error) { func (PitFileDebtCeilingConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []PitFileDebtCeilingModel var models []interface{}
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := verifyLog(ethLog) err := verifyLog(ethLog)
if err != nil { if err != nil {

View File

@ -17,10 +17,10 @@ package debt_ceiling_test
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
) )
@ -54,6 +54,6 @@ var _ = Describe("Pit file debt ceiling converter", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1)) Expect(len(models)).To(Equal(1))
Expect(models[0]).To(Equal(test_data.PitFileDebtCeilingModel)) Expect(models[0].(debt_ceiling.PitFileDebtCeilingModel)).To(Equal(test_data.PitFileDebtCeilingModel))
}) })
}) })

View File

@ -15,58 +15,58 @@
package debt_ceiling package debt_ceiling
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type Repository interface {
Create(headerID int64, models []PitFileDebtCeilingModel) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type PitFileDebtCeilingRepository struct { type PitFileDebtCeilingRepository struct {
db *postgres.DB db *postgres.DB
} }
func NewPitFileDebtCeilingRepository(db *postgres.DB) PitFileDebtCeilingRepository { func (repository PitFileDebtCeilingRepository) Create(headerID int64, models []interface{}) error {
return PitFileDebtCeilingRepository{
db: db,
}
}
func (repository PitFileDebtCeilingRepository) Create(headerID int64, models []PitFileDebtCeilingModel) error {
tx, err := repository.db.Begin() tx, err := repository.db.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, model := range models { for _, model := range models {
pitFileDC, ok := model.(PitFileDebtCeilingModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, PitFileDebtCeilingModel{})
}
_, err = tx.Exec( _, err = tx.Exec(
`INSERT into maker.pit_file_debt_ceiling (header_id, what, data, tx_idx, raw_log) `INSERT into maker.pit_file_debt_ceiling (header_id, what, data, tx_idx, raw_log)
VALUES($1, $2, $3::NUMERIC, $4, $5)`, VALUES($1, $2, $3::NUMERIC, $4, $5)`,
headerID, model.What, model.Data, model.TransactionIndex, model.Raw, headerID, pitFileDC.What, pitFileDC.Data, pitFileDC.TransactionIndex, pitFileDC.Raw,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
} }
_, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, pit_file_debt_ceiling_checked) _, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, pit_file_debt_ceiling_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET pit_file_debt_ceiling_checked = $2`, headerID, true) UPDATE SET pit_file_debt_ceiling_checked = $2`, headerID, true)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
return tx.Commit() return tx.Commit()
} }
func (repository PitFileDebtCeilingRepository) MarkHeaderChecked(headerID int64) error { func (repository PitFileDebtCeilingRepository) MarkHeaderChecked(headerID int64) error {
_, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, pit_file_debt_ceiling_checked) _, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, pit_file_debt_ceiling_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET pit_file_debt_ceiling_checked = $2`, headerID, true) UPDATE SET pit_file_debt_ceiling_checked = $2`, headerID, true)
return err return err
} }
@ -75,14 +75,18 @@ func (repository PitFileDebtCeilingRepository) MissingHeaders(startingBlockNumbe
err := repository.db.Select( err := repository.db.Select(
&result, &result,
`SELECT headers.id, headers.block_number FROM headers `SELECT headers.id, headers.block_number FROM headers
LEFT JOIN checked_headers on headers.id = header_id LEFT JOIN checked_headers on headers.id = header_id
WHERE (header_id ISNULL OR pit_file_debt_ceiling_checked IS FALSE) WHERE (header_id ISNULL OR pit_file_debt_ceiling_checked IS FALSE)
AND headers.block_number >= $1 AND headers.block_number >= $1
AND headers.block_number <= $2 AND headers.block_number <= $2
AND headers.eth_node_fingerprint = $3`, AND headers.eth_node_fingerprint = $3`,
startingBlockNumber, startingBlockNumber,
endingBlockNumber, endingBlockNumber,
repository.db.Node.ID, repository.db.Node.ID,
) )
return result, err return result, err
} }
func (repository *PitFileDebtCeilingRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -16,6 +16,7 @@ package debt_ceiling_test
import ( import (
"database/sql" "database/sql"
"math/rand"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -32,17 +33,18 @@ import (
var _ = Describe("Pit file debt ceiling repository", func() { var _ = Describe("Pit file debt ceiling repository", func() {
var ( var (
db *postgres.DB db *postgres.DB
pitFileRepository debt_ceiling.Repository pitFileDebtCeilingRepository debt_ceiling.PitFileDebtCeilingRepository
err error err error
headerRepository datastore.HeaderRepository headerRepository datastore.HeaderRepository
) )
BeforeEach(func() { BeforeEach(func() {
db = test_config.NewTestDB(core.Node{}) db = test_config.NewTestDB(core.Node{})
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
pitFileRepository = debt_ceiling.NewPitFileDebtCeilingRepository(db) pitFileDebtCeilingRepository = debt_ceiling.PitFileDebtCeilingRepository{}
pitFileDebtCeilingRepository.SetDB(db)
}) })
Describe("Create", func() { Describe("Create", func() {
@ -52,7 +54,7 @@ var _ = Describe("Pit file debt ceiling repository", func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = pitFileRepository.Create(headerID, []debt_ceiling.PitFileDebtCeilingModel{test_data.PitFileDebtCeilingModel}) err = pitFileDebtCeilingRepository.Create(headerID, []interface{}{test_data.PitFileDebtCeilingModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -74,7 +76,7 @@ var _ = Describe("Pit file debt ceiling repository", func() {
}) })
It("does not duplicate pit file events", func() { It("does not duplicate pit file events", func() {
err = pitFileRepository.Create(headerID, []debt_ceiling.PitFileDebtCeilingModel{test_data.PitFileDebtCeilingModel}) err = pitFileDebtCeilingRepository.Create(headerID, []interface{}{test_data.PitFileDebtCeilingModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
@ -89,6 +91,12 @@ var _ = Describe("Pit file debt ceiling repository", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(sql.ErrNoRows)) Expect(err).To(MatchError(sql.ErrNoRows))
}) })
It("Returns an error if model is of wrong type", func() {
err = pitFileDebtCeilingRepository.Create(headerID, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {
@ -100,7 +108,7 @@ var _ = Describe("Pit file debt ceiling repository", func() {
}) })
It("creates a row for a new headerID", func() { It("creates a row for a new headerID", func() {
err = pitFileRepository.MarkHeaderChecked(headerID) err = pitFileDebtCeilingRepository.MarkHeaderChecked(headerID)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
var headerChecked bool var headerChecked bool
@ -112,7 +120,7 @@ var _ = Describe("Pit file debt ceiling repository", func() {
It("updates row when headerID already exists", func() { It("updates row when headerID already exists", func() {
_, err = db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerID) _, err = db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerID)
err = pitFileRepository.MarkHeaderChecked(headerID) err = pitFileDebtCeilingRepository.MarkHeaderChecked(headerID)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
var headerChecked bool var headerChecked bool
@ -129,7 +137,7 @@ var _ = Describe("Pit file debt ceiling repository", func() {
) )
BeforeEach(func() { BeforeEach(func() {
startingBlock = GinkgoRandomSeed() startingBlock = rand.Int63()
pitFileBlock = startingBlock + 1 pitFileBlock = startingBlock + 1
endingBlock = startingBlock + 2 endingBlock = startingBlock + 2
@ -144,10 +152,11 @@ var _ = Describe("Pit file debt ceiling repository", func() {
}) })
It("returns headers that haven't been checked", func() { It("returns headers that haven't been checked", func() {
err := pitFileRepository.MarkHeaderChecked(headerIDs[1])
err := pitFileDebtCeilingRepository.MarkHeaderChecked(headerIDs[1])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
headers, err := pitFileRepository.MissingHeaders(startingBlock, endingBlock) headers, err := pitFileDebtCeilingRepository.MissingHeaders(startingBlock, endingBlock)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(headers)).To(Equal(2)) Expect(len(headers)).To(Equal(2))
@ -159,7 +168,7 @@ var _ = Describe("Pit file debt ceiling repository", func() {
_, err := db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerIDs[1]) _, err := db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerIDs[1])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
headers, err := pitFileRepository.MissingHeaders(startingBlock, endingBlock) headers, err := pitFileDebtCeilingRepository.MissingHeaders(startingBlock, endingBlock)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(headers)).To(Equal(3)) Expect(len(headers)).To(Equal(3))
@ -175,16 +184,16 @@ var _ = Describe("Pit file debt ceiling repository", func() {
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
pitFileRepository := debt_ceiling.NewPitFileDebtCeilingRepository(db) pitFileDebtCeilingRepositoryTwo := debt_ceiling.PitFileDebtCeilingRepository{}
pitFileRepositoryTwo := debt_ceiling.NewPitFileDebtCeilingRepository(dbTwo) pitFileDebtCeilingRepositoryTwo.SetDB(dbTwo)
err := pitFileRepository.MarkHeaderChecked(headerIDs[0]) err := pitFileDebtCeilingRepository.MarkHeaderChecked(headerIDs[0])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
nodeOneMissingHeaders, err := pitFileRepository.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1]) nodeOneMissingHeaders, err := pitFileDebtCeilingRepository.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(nodeOneMissingHeaders)).To(Equal(len(blockNumbers) - 1)) Expect(len(nodeOneMissingHeaders)).To(Equal(len(blockNumbers) - 1))
nodeTwoMissingHeaders, err := pitFileRepositoryTwo.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1]) nodeTwoMissingHeaders, err := pitFileDebtCeilingRepositoryTwo.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(nodeTwoMissingHeaders)).To(Equal(len(blockNumbers))) Expect(len(nodeTwoMissingHeaders)).To(Equal(len(blockNumbers)))
}) })

View File

@ -1,79 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package debt_ceiling
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type PitFileDebtCeilingTransformer struct {
Config shared.TransformerConfig
Converter Converter
Fetcher shared.LogFetcher
Repository Repository
}
type PitFileDebtCeilingTransformerInitializer struct {
Config shared.TransformerConfig
}
func (initializer PitFileDebtCeilingTransformerInitializer) NewPitFileDebtCeilingTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := PitFileDebtCeilingConverter{}
fetcher := shared.NewFetcher(blockChain)
repository := NewPitFileDebtCeilingRepository(db)
return PitFileDebtCeilingTransformer{
Config: initializer.Config,
Converter: converter,
Fetcher: fetcher,
Repository: repository,
}
}
func (transformer PitFileDebtCeilingTransformer) Execute() error {
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
return err
}
log.Printf("Fetching pit file debt ceiling event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
topics := [][]common.Hash{{common.HexToHash(shared.PitFileDebtCeilingSignature)}}
matchingLogs, err := transformer.Fetcher.FetchLogs(pit_file.PitFileConfig.ContractAddresses, topics, header.BlockNumber)
if err != nil {
return err
}
if len(matchingLogs) < 1 {
err = transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
}
model, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
return err
}
err = transformer.Repository.Create(header.Id, model)
if err != nil {
return err
}
}
return nil
}

View File

@ -19,10 +19,11 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling" "github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
@ -31,31 +32,45 @@ import (
) )
var _ = Describe("Pit file debt ceiling transformer", func() { var _ = Describe("Pit file debt ceiling transformer", func() {
It("gets missing headers for block numbers specified in config", func() { var (
repository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{} config = debt_ceiling.DebtCeilingFileConfig
transformer := debt_ceiling.PitFileDebtCeilingTransformer{ fetcher mocks.MockLogFetcher
Config: pit_file.PitFileConfig, converter debt_ceiling_mocks.MockPitFileDebtCeilingConverter
Fetcher: &mocks.MockLogFetcher{}, repository debt_ceiling_mocks.MockPitFileDebtCeilingRepository
Converter: &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{}, transformer shared.Transformer
Repository: repository, headerOne core.Header
} headerTwo core.Header
)
BeforeEach(func() {
fetcher = mocks.MockLogFetcher{}
converter = debt_ceiling_mocks.MockPitFileDebtCeilingConverter{}
repository = debt_ceiling_mocks.MockPitFileDebtCeilingRepository{}
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
headerTwo = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
transformer = factories.Transformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}.NewTransformer(nil, nil)
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
})
It("gets missing headers for block numbers specified in config", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedStartingBlockNumber).To(Equal(pit_file.PitFileConfig.StartingBlockNumber)) Expect(repository.PassedStartingBlockNumber).To(Equal(config.StartingBlockNumber))
Expect(repository.PassedEndingBlockNumber).To(Equal(pit_file.PitFileConfig.EndingBlockNumber)) Expect(repository.PassedEndingBlockNumber).To(Equal(config.EndingBlockNumber))
}) })
It("returns error if repository returns error for missing headers", func() { It("returns error if repository returns error for missing headers", func() {
repository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{} repository.SetMissingHeadersError(fakes.FakeError)
repository.SetMissingHeadersErr(fakes.FakeError)
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Fetcher: &mocks.MockLogFetcher{},
Converter: &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@ -63,34 +78,18 @@ var _ = Describe("Pit file debt ceiling transformer", func() {
}) })
It("fetches logs for missing headers", func() { It("fetches logs for missing headers", func() {
fetcher := &mocks.MockLogFetcher{} repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
repository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{}
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}, {BlockNumber: 2}})
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Fetcher: fetcher,
Converter: &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(Equal([]int64{1, 2})) Expect(fetcher.FetchedBlocks).To(Equal([]int64{headerOne.BlockNumber, headerTwo.BlockNumber}))
Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{pit_file.PitFileConfig.ContractAddresses, pit_file.PitFileConfig.ContractAddresses})) Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{config.ContractAddresses, config.ContractAddresses}))
Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.PitFileDebtCeilingSignature)}})) Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.PitFileDebtCeilingSignature)}}))
}) })
It("returns error if fetcher returns error", func() { It("returns error if fetcher returns error", func() {
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetcherError(fakes.FakeError) fetcher.SetFetcherError(fakes.FakeError)
repository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Fetcher: fetcher,
Converter: &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@ -98,34 +97,17 @@ var _ = Describe("Pit file debt ceiling transformer", func() {
}) })
It("marks header checked if no logs returned", func() { It("marks header checked if no logs returned", func() {
mockConverter := &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{}
headerID := int64(123)
mockRepository.SetMissingHeaders([]core.Header{{Id: headerID}})
mockFetcher := &mocks.MockLogFetcher{}
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mockRepository.AssertMarkHeaderCheckedCalledWith(headerID) repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
}) })
It("returns error if marking header checked returns err", func() { It("returns error if marking header checked returns err", func() {
mockConverter := &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{} repository.SetMarkHeaderCheckedError(fakes.FakeError)
mockRepository.SetMissingHeaders([]core.Header{{Id: int64(123)}})
mockRepository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockFetcher := &mocks.MockLogFetcher{}
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
@ -134,16 +116,8 @@ var _ = Describe("Pit file debt ceiling transformer", func() {
}) })
It("converts matching logs", func() { It("converts matching logs", func() {
converter := &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileDebtCeilingLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileDebtCeilingLog})
repository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -152,17 +126,9 @@ var _ = Describe("Pit file debt ceiling transformer", func() {
}) })
It("returns error if converter returns error", func() { It("returns error if converter returns error", func() {
converter := &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{}
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileDebtCeilingLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileDebtCeilingLog})
repository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -171,37 +137,20 @@ var _ = Describe("Pit file debt ceiling transformer", func() {
}) })
It("persists pit file model", func() { It("persists pit file model", func() {
converter := &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileDebtCeilingLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileDebtCeilingLog})
repository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
fakeHeader := core.Header{BlockNumber: 1, Id: 2}
repository.SetMissingHeaders([]core.Header{fakeHeader})
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(fakeHeader.Id)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]debt_ceiling.PitFileDebtCeilingModel{test_data.PitFileDebtCeilingModel})) Expect(repository.PassedModels).To(Equal([]interface{}{test_data.PitFileDebtCeilingModel}))
}) })
It("returns error if repository returns error for create", func() { It("returns error if repository returns error for create", func() {
converter := &debt_ceiling_mocks.MockPitFileDebtCeilingConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileDebtCeilingLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileDebtCeilingLog})
repository := &debt_ceiling_mocks.MockPitFileDebtCeilingRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1, Id: 2}})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
transformer := debt_ceiling.PitFileDebtCeilingTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()

View File

@ -0,0 +1,28 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ilk
import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
var IlkFileConfig = shared.SingleTransformerConfig{
TransformerName: shared.PitFileIlkLabel,
ContractAddresses: []string{shared.PitContractAddress},
ContractAbi: shared.PitABI,
Topic: shared.PitFileIlkSignature,
StartingBlockNumber: 0,
EndingBlockNumber: 10000000,
}

View File

@ -24,14 +24,10 @@ import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
) )
type Converter interface {
ToModels(ethLogs []types.Log) ([]PitFileIlkModel, error)
}
type PitFileIlkConverter struct{} type PitFileIlkConverter struct{}
func (PitFileIlkConverter) ToModels(ethLogs []types.Log) ([]PitFileIlkModel, error) { func (PitFileIlkConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []PitFileIlkModel var models []interface{}
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := verifyLog(ethLog) err := verifyLog(ethLog)
if err != nil { if err != nil {

View File

@ -54,6 +54,6 @@ var _ = Describe("Pit file ilk converter", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1)) Expect(len(models)).To(Equal(1))
Expect(models[0]).To(Equal(test_data.PitFileIlkModel)) Expect(models[0].(ilk.PitFileIlkModel)).To(Equal(test_data.PitFileIlkModel))
}) })
}) })

View File

@ -15,36 +15,32 @@
package ilk package ilk
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type Repository interface {
Create(headerID int64, models []PitFileIlkModel) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type PitFileIlkRepository struct { type PitFileIlkRepository struct {
db *postgres.DB db *postgres.DB
} }
func NewPitFileIlkRepository(db *postgres.DB) PitFileIlkRepository { func (repository PitFileIlkRepository) Create(headerID int64, models []interface{}) error {
return PitFileIlkRepository{
db: db,
}
}
func (repository PitFileIlkRepository) Create(headerID int64, models []PitFileIlkModel) error {
tx, err := repository.db.Begin() tx, err := repository.db.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, model := range models { for _, model := range models {
pitFileIlk, ok := model.(PitFileIlkModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, PitFileIlkModel{})
}
_, err = tx.Exec( _, err = tx.Exec(
`INSERT into maker.pit_file_ilk (header_id, ilk, what, data, tx_idx, raw_log) `INSERT into maker.pit_file_ilk (header_id, ilk, what, data, tx_idx, raw_log)
VALUES($1, $2, $3, $4::NUMERIC, $5, $6)`, VALUES($1, $2, $3, $4::NUMERIC, $5, $6)`,
headerID, model.Ilk, model.What, model.Data, model.TransactionIndex, model.Raw, headerID, pitFileIlk.Ilk, pitFileIlk.What, pitFileIlk.Data, pitFileIlk.TransactionIndex, pitFileIlk.Raw,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
@ -75,14 +71,18 @@ func (repository PitFileIlkRepository) MissingHeaders(startingBlockNumber, endin
err := repository.db.Select( err := repository.db.Select(
&result, &result,
`SELECT headers.id, headers.block_number FROM headers `SELECT headers.id, headers.block_number FROM headers
LEFT JOIN checked_headers on headers.id = header_id LEFT JOIN checked_headers on headers.id = header_id
WHERE (header_id ISNULL OR pit_file_ilk_checked IS FALSE) WHERE (header_id ISNULL OR pit_file_ilk_checked IS FALSE)
AND headers.block_number >= $1 AND headers.block_number >= $1
AND headers.block_number <= $2 AND headers.block_number <= $2
AND headers.eth_node_fingerprint = $3`, AND headers.eth_node_fingerprint = $3`,
startingBlockNumber, startingBlockNumber,
endingBlockNumber, endingBlockNumber,
repository.db.Node.ID, repository.db.Node.ID,
) )
return result, err return result, err
} }
func (repository *PitFileIlkRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -16,6 +16,7 @@ package ilk_test
import ( import (
"database/sql" "database/sql"
"math/rand"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -33,7 +34,7 @@ import (
var _ = Describe("Pit file ilk repository", func() { var _ = Describe("Pit file ilk repository", func() {
var ( var (
db *postgres.DB db *postgres.DB
pitFileRepository ilk.Repository pitFileRepository ilk.PitFileIlkRepository
err error err error
headerRepository datastore.HeaderRepository headerRepository datastore.HeaderRepository
) )
@ -42,7 +43,8 @@ var _ = Describe("Pit file ilk repository", func() {
db = test_config.NewTestDB(core.Node{}) db = test_config.NewTestDB(core.Node{})
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
pitFileRepository = ilk.NewPitFileIlkRepository(db) pitFileRepository = ilk.PitFileIlkRepository{}
pitFileRepository.SetDB(db)
}) })
Describe("Create", func() { Describe("Create", func() {
@ -52,7 +54,7 @@ var _ = Describe("Pit file ilk repository", func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = pitFileRepository.Create(headerID, []ilk.PitFileIlkModel{test_data.PitFileIlkModel}) err = pitFileRepository.Create(headerID, []interface{}{test_data.PitFileIlkModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -75,7 +77,7 @@ var _ = Describe("Pit file ilk repository", func() {
}) })
It("does not duplicate pit file ilk events", func() { It("does not duplicate pit file ilk events", func() {
err = pitFileRepository.Create(headerID, []ilk.PitFileIlkModel{test_data.PitFileIlkModel}) err = pitFileRepository.Create(headerID, []interface{}{test_data.PitFileIlkModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
@ -90,6 +92,12 @@ var _ = Describe("Pit file ilk repository", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(sql.ErrNoRows)) Expect(err).To(MatchError(sql.ErrNoRows))
}) })
It("Returns an error if model is of wrong type", func() {
err = pitFileRepository.Create(headerID, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {
@ -130,7 +138,7 @@ var _ = Describe("Pit file ilk repository", func() {
) )
BeforeEach(func() { BeforeEach(func() {
startingBlock = GinkgoRandomSeed() startingBlock = rand.Int63()
pitFileBlock = startingBlock + 1 pitFileBlock = startingBlock + 1
endingBlock = startingBlock + 2 endingBlock = startingBlock + 2
@ -176,7 +184,9 @@ var _ = Describe("Pit file ilk repository", func() {
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
pitFileRepositoryTwo := ilk.NewPitFileIlkRepository(dbTwo)
pitFileRepositoryTwo := ilk.PitFileIlkRepository{}
pitFileRepositoryTwo.SetDB(dbTwo)
err := pitFileRepository.MarkHeaderChecked(headerIDs[0]) err := pitFileRepository.MarkHeaderChecked(headerIDs[0])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -1,79 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ilk
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type PitFileIlkTransformer struct {
Config shared.TransformerConfig
Converter Converter
Fetcher shared.LogFetcher
Repository Repository
}
type PitFileIlkTransformerInitializer struct {
Config shared.TransformerConfig
}
func (initializer PitFileIlkTransformerInitializer) NewPitFileIlkTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := PitFileIlkConverter{}
fetcher := shared.NewFetcher(blockChain)
repository := NewPitFileIlkRepository(db)
return PitFileIlkTransformer{
Config: initializer.Config,
Converter: converter,
Fetcher: fetcher,
Repository: repository,
}
}
func (transformer PitFileIlkTransformer) Execute() error {
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
return err
}
log.Printf("Fetching pit file ilk event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
topics := [][]common.Hash{{common.HexToHash(shared.PitFileIlkSignature)}}
matchingLogs, err := transformer.Fetcher.FetchLogs(pit_file.PitFileConfig.ContractAddresses, topics, header.BlockNumber)
if err != nil {
return err
}
if len(matchingLogs) < 1 {
err = transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
}
models, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
return err
}
err = transformer.Repository.Create(header.Id, models)
if err != nil {
return err
}
}
return nil
}

View File

@ -19,42 +19,58 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/ilk" "github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/ilk"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks"
pit_file_ilk_mocks "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks/pit_file/ilk" ilk_mocks "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks/pit_file/ilk"
) )
var _ = Describe("Pit file ilk transformer", func() { var _ = Describe("Pit file ilk transformer", func() {
It("gets missing headers for block numbers specified in config", func() { var (
repository := &pit_file_ilk_mocks.MockPitFileIlkRepository{} config = ilk.IlkFileConfig
transformer := ilk.PitFileIlkTransformer{ fetcher mocks.MockLogFetcher
Config: pit_file.PitFileConfig, converter ilk_mocks.MockPitFileIlkConverter
Fetcher: &mocks.MockLogFetcher{}, repository ilk_mocks.MockPitFileIlkRepository
Converter: &pit_file_ilk_mocks.MockPitFileIlkConverter{}, transformer shared.Transformer
Repository: repository, headerOne core.Header
} headerTwo core.Header
)
BeforeEach(func() {
fetcher = mocks.MockLogFetcher{}
converter = ilk_mocks.MockPitFileIlkConverter{}
repository = ilk_mocks.MockPitFileIlkRepository{}
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
headerTwo = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
transformer = factories.Transformer{
Config: config,
Converter: &converter,
Repository: &repository,
Fetcher: &fetcher,
}.NewTransformer(nil, nil)
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
})
It("gets missing headers for block numbers specified in config", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedStartingBlockNumber).To(Equal(pit_file.PitFileConfig.StartingBlockNumber)) Expect(repository.PassedStartingBlockNumber).To(Equal(config.StartingBlockNumber))
Expect(repository.PassedEndingBlockNumber).To(Equal(pit_file.PitFileConfig.EndingBlockNumber)) Expect(repository.PassedEndingBlockNumber).To(Equal(config.EndingBlockNumber))
}) })
It("returns error if repository returns error for missing headers", func() { It("returns error if repository returns error for missing headers", func() {
repository := &pit_file_ilk_mocks.MockPitFileIlkRepository{} repository.SetMissingHeadersError(fakes.FakeError)
repository.SetMissingHeadersErr(fakes.FakeError)
transformer := ilk.PitFileIlkTransformer{
Fetcher: &mocks.MockLogFetcher{},
Converter: &pit_file_ilk_mocks.MockPitFileIlkConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -63,33 +79,19 @@ var _ = Describe("Pit file ilk transformer", func() {
}) })
It("fetches logs for missing headers", func() { It("fetches logs for missing headers", func() {
fetcher := &mocks.MockLogFetcher{} repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
repository := &pit_file_ilk_mocks.MockPitFileIlkRepository{}
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}, {BlockNumber: 2}})
transformer := ilk.PitFileIlkTransformer{
Fetcher: fetcher,
Converter: &pit_file_ilk_mocks.MockPitFileIlkConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(Equal([]int64{1, 2})) Expect(fetcher.FetchedBlocks).To(Equal([]int64{headerOne.BlockNumber, headerTwo.BlockNumber}))
Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{pit_file.PitFileConfig.ContractAddresses, pit_file.PitFileConfig.ContractAddresses})) Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{config.ContractAddresses, config.ContractAddresses}))
Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.PitFileIlkSignature)}})) Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.PitFileIlkSignature)}}))
}) })
It("returns error if fetcher returns error", func() { It("returns error if fetcher returns error", func() {
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetcherError(fakes.FakeError) fetcher.SetFetcherError(fakes.FakeError)
repository := &pit_file_ilk_mocks.MockPitFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := ilk.PitFileIlkTransformer{
Fetcher: fetcher,
Converter: &pit_file_ilk_mocks.MockPitFileIlkConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -98,34 +100,17 @@ var _ = Describe("Pit file ilk transformer", func() {
}) })
It("marks header checked if no logs returned", func() { It("marks header checked if no logs returned", func() {
mockConverter := &pit_file_ilk_mocks.MockPitFileIlkConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &pit_file_ilk_mocks.MockPitFileIlkRepository{}
headerID := int64(123)
mockRepository.SetMissingHeaders([]core.Header{{Id: headerID}})
mockFetcher := &mocks.MockLogFetcher{}
transformer := ilk.PitFileIlkTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mockRepository.AssertMarkHeaderCheckedCalledWith(headerID) repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
}) })
It("returns error if marking header checked returns err", func() { It("returns error if marking header checked returns err", func() {
mockConverter := &pit_file_ilk_mocks.MockPitFileIlkConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &pit_file_ilk_mocks.MockPitFileIlkRepository{} repository.SetMarkHeaderCheckedError(fakes.FakeError)
mockRepository.SetMissingHeaders([]core.Header{{Id: int64(123)}})
mockRepository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockFetcher := &mocks.MockLogFetcher{}
transformer := ilk.PitFileIlkTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
@ -134,16 +119,8 @@ var _ = Describe("Pit file ilk transformer", func() {
}) })
It("converts matching logs", func() { It("converts matching logs", func() {
converter := &pit_file_ilk_mocks.MockPitFileIlkConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileIlkLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileIlkLog})
repository := &pit_file_ilk_mocks.MockPitFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := ilk.PitFileIlkTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -152,17 +129,9 @@ var _ = Describe("Pit file ilk transformer", func() {
}) })
It("returns error if converter returns error", func() { It("returns error if converter returns error", func() {
converter := &pit_file_ilk_mocks.MockPitFileIlkConverter{}
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileIlkLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileIlkLog})
repository := &pit_file_ilk_mocks.MockPitFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := ilk.PitFileIlkTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -171,37 +140,20 @@ var _ = Describe("Pit file ilk transformer", func() {
}) })
It("persists pit file model", func() { It("persists pit file model", func() {
converter := &pit_file_ilk_mocks.MockPitFileIlkConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileIlkLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileIlkLog})
repository := &pit_file_ilk_mocks.MockPitFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
fakeHeader := core.Header{BlockNumber: 1, Id: 2}
repository.SetMissingHeaders([]core.Header{fakeHeader})
transformer := ilk.PitFileIlkTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(fakeHeader.Id)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]ilk.PitFileIlkModel{test_data.PitFileIlkModel})) Expect(repository.PassedModels).To(Equal([]interface{}{test_data.PitFileIlkModel}))
}) })
It("returns error if repository returns error for create", func() { It("returns error if repository returns error for create", func() {
converter := &pit_file_ilk_mocks.MockPitFileIlkConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileIlkLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileIlkLog})
repository := &pit_file_ilk_mocks.MockPitFileIlkRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1, Id: 2}})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
transformer := ilk.PitFileIlkTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()

View File

@ -0,0 +1,28 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package stability_fee
import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
var StabilityFeeFileConfig = shared.SingleTransformerConfig{
TransformerName: shared.PitFileStabilityFeeLabel,
ContractAddresses: []string{shared.PitContractAddress},
ContractAbi: shared.PitABI,
Topic: shared.PitFileStabilityFeeSignature,
StartingBlockNumber: 0,
EndingBlockNumber: 10000000,
}

View File

@ -23,14 +23,10 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
type Converter interface {
ToModels(ethLogs []types.Log) ([]PitFileStabilityFeeModel, error)
}
type PitFileStabilityFeeConverter struct{} type PitFileStabilityFeeConverter struct{}
func (PitFileStabilityFeeConverter) ToModels(ethLogs []types.Log) ([]PitFileStabilityFeeModel, error) { func (PitFileStabilityFeeConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []PitFileStabilityFeeModel var models []interface{}
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := verifyLog(ethLog) err := verifyLog(ethLog)
if err != nil { if err != nil {

View File

@ -15,50 +15,50 @@
package stability_fee package stability_fee
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type Repository interface {
Create(headerID int64, models []PitFileStabilityFeeModel) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type PitFileStabilityFeeRepository struct { type PitFileStabilityFeeRepository struct {
db *postgres.DB db *postgres.DB
} }
func NewPitFileStabilityFeeRepository(db *postgres.DB) PitFileStabilityFeeRepository { func (repository PitFileStabilityFeeRepository) Create(headerID int64, models []interface{}) error {
return PitFileStabilityFeeRepository{
db: db,
}
}
func (repository PitFileStabilityFeeRepository) Create(headerID int64, models []PitFileStabilityFeeModel) error {
tx, err := repository.db.Begin() tx, err := repository.db.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, model := range models { for _, model := range models {
pitFileSF, ok := model.(PitFileStabilityFeeModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, PitFileStabilityFeeModel{})
}
_, err = tx.Exec( _, err = tx.Exec(
`INSERT into maker.pit_file_stability_fee (header_id, what, data, tx_idx, raw_log) `INSERT into maker.pit_file_stability_fee (header_id, what, data, tx_idx, raw_log)
VALUES($1, $2, $3, $4, $5)`, VALUES($1, $2, $3, $4, $5)`,
headerID, model.What, model.Data, model.TransactionIndex, model.Raw, headerID, pitFileSF.What, pitFileSF.Data, pitFileSF.TransactionIndex, pitFileSF.Raw,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
} }
_, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, pit_file_stability_fee_checked) _, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, pit_file_stability_fee_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET pit_file_stability_fee_checked = $2`, headerID, true) UPDATE SET pit_file_stability_fee_checked = $2`, headerID, true)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
} }
return tx.Commit() return tx.Commit()
} }
@ -86,3 +86,7 @@ func (repository PitFileStabilityFeeRepository) MissingHeaders(startingBlockNumb
) )
return result, err return result, err
} }
func (repository *PitFileStabilityFeeRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -16,6 +16,7 @@ package stability_fee_test
import ( import (
"database/sql" "database/sql"
"math/rand"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -32,17 +33,18 @@ import (
var _ = Describe("Pit file stability fee repository", func() { var _ = Describe("Pit file stability fee repository", func() {
var ( var (
db *postgres.DB db *postgres.DB
pitFileRepository stability_fee.Repository pitFileStabilityFeeRepository stability_fee.PitFileStabilityFeeRepository
err error err error
headerRepository datastore.HeaderRepository headerRepository datastore.HeaderRepository
) )
BeforeEach(func() { BeforeEach(func() {
db = test_config.NewTestDB(core.Node{}) db = test_config.NewTestDB(core.Node{})
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
pitFileRepository = stability_fee.NewPitFileStabilityFeeRepository(db) pitFileStabilityFeeRepository = stability_fee.PitFileStabilityFeeRepository{}
pitFileStabilityFeeRepository.SetDB(db)
}) })
Describe("Create", func() { Describe("Create", func() {
@ -52,7 +54,7 @@ var _ = Describe("Pit file stability fee repository", func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = pitFileRepository.Create(headerID, []stability_fee.PitFileStabilityFeeModel{test_data.PitFileStabilityFeeModel}) err = pitFileStabilityFeeRepository.Create(headerID, []interface{}{test_data.PitFileStabilityFeeModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -74,7 +76,7 @@ var _ = Describe("Pit file stability fee repository", func() {
}) })
It("does not duplicate pit file events", func() { It("does not duplicate pit file events", func() {
err = pitFileRepository.Create(headerID, []stability_fee.PitFileStabilityFeeModel{test_data.PitFileStabilityFeeModel}) err = pitFileStabilityFeeRepository.Create(headerID, []interface{}{test_data.PitFileStabilityFeeModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
@ -89,6 +91,12 @@ var _ = Describe("Pit file stability fee repository", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(sql.ErrNoRows)) Expect(err).To(MatchError(sql.ErrNoRows))
}) })
It("Returns an error if model is of wrong type", func() {
err = pitFileStabilityFeeRepository.Create(headerID, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {
@ -100,7 +108,7 @@ var _ = Describe("Pit file stability fee repository", func() {
}) })
It("creates a row for a new headerID", func() { It("creates a row for a new headerID", func() {
err = pitFileRepository.MarkHeaderChecked(headerID) err = pitFileStabilityFeeRepository.MarkHeaderChecked(headerID)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
var headerChecked bool var headerChecked bool
@ -112,7 +120,7 @@ var _ = Describe("Pit file stability fee repository", func() {
It("updates row when headerID already exists", func() { It("updates row when headerID already exists", func() {
_, err = db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerID) _, err = db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerID)
err = pitFileRepository.MarkHeaderChecked(headerID) err = pitFileStabilityFeeRepository.MarkHeaderChecked(headerID)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
var headerChecked bool var headerChecked bool
@ -129,7 +137,7 @@ var _ = Describe("Pit file stability fee repository", func() {
) )
BeforeEach(func() { BeforeEach(func() {
startingBlock = GinkgoRandomSeed() startingBlock = rand.Int63()
pitFileBlock = startingBlock + 1 pitFileBlock = startingBlock + 1
endingBlock = startingBlock + 2 endingBlock = startingBlock + 2
@ -144,10 +152,10 @@ var _ = Describe("Pit file stability fee repository", func() {
}) })
It("returns headers that haven't been checked", func() { It("returns headers that haven't been checked", func() {
err := pitFileRepository.MarkHeaderChecked(headerIDs[1]) err = pitFileStabilityFeeRepository.MarkHeaderChecked(headerIDs[1])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
headers, err := pitFileRepository.MissingHeaders(startingBlock, endingBlock) headers, err := pitFileStabilityFeeRepository.MissingHeaders(startingBlock, endingBlock)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(headers)).To(Equal(2)) Expect(len(headers)).To(Equal(2))
@ -156,10 +164,10 @@ var _ = Describe("Pit file stability fee repository", func() {
}) })
It("only treats headers as checked if pit file stability fee logs have been checked", func() { It("only treats headers as checked if pit file stability fee logs have been checked", func() {
_, err := db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerIDs[1]) _, err = db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerIDs[1])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
headers, err := pitFileRepository.MissingHeaders(startingBlock, endingBlock) headers, err := pitFileStabilityFeeRepository.MissingHeaders(startingBlock, endingBlock)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(headers)).To(Equal(3)) Expect(len(headers)).To(Equal(3))
@ -175,11 +183,13 @@ var _ = Describe("Pit file stability fee repository", func() {
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
pitFileRepositoryTwo := stability_fee.NewPitFileStabilityFeeRepository(dbTwo)
err := pitFileRepository.MarkHeaderChecked(headerIDs[0]) pitFileRepositoryTwo := stability_fee.PitFileStabilityFeeRepository{}
pitFileRepositoryTwo.SetDB(dbTwo)
err = pitFileStabilityFeeRepository.MarkHeaderChecked(headerIDs[0])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
nodeOneMissingHeaders, err := pitFileRepository.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1]) nodeOneMissingHeaders, err := pitFileStabilityFeeRepository.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(nodeOneMissingHeaders)).To(Equal(len(blockNumbers) - 1)) Expect(len(nodeOneMissingHeaders)).To(Equal(len(blockNumbers) - 1))

View File

@ -1,79 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package stability_fee
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type PitFileStabilityFeeTransformer struct {
Config shared.TransformerConfig
Converter Converter
Fetcher shared.LogFetcher
Repository Repository
}
type PitFileStabilityFeeTransformerInitializer struct {
Config shared.TransformerConfig
}
func (initializer PitFileStabilityFeeTransformerInitializer) NewPitFileStabilityFeeTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := PitFileStabilityFeeConverter{}
fetcher := shared.NewFetcher(blockChain)
repository := NewPitFileStabilityFeeRepository(db)
return PitFileStabilityFeeTransformer{
Config: initializer.Config,
Converter: converter,
Fetcher: fetcher,
Repository: repository,
}
}
func (transformer PitFileStabilityFeeTransformer) Execute() error {
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
return err
}
log.Printf("Fetching pit file stability fee event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
topics := [][]common.Hash{{common.HexToHash(shared.PitFileStabilityFeeSignature)}}
matchingLogs, err := transformer.Fetcher.FetchLogs(pit_file.PitFileConfig.ContractAddresses, topics, header.BlockNumber)
if err != nil {
return err
}
if len(matchingLogs) < 1 {
err = transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
}
models, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
return err
}
err = transformer.Repository.Create(header.Id, models)
if err != nil {
return err
}
}
return nil
}

View File

@ -19,11 +19,12 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/stability_fee"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/stability_fee"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks"
@ -31,31 +32,45 @@ import (
) )
var _ = Describe("Pit file stability fee transformer", func() { var _ = Describe("Pit file stability fee transformer", func() {
It("gets missing headers for block numbers specified in config", func() { var (
repository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{} config = stability_fee.StabilityFeeFileConfig
transformer := stability_fee.PitFileStabilityFeeTransformer{ fetcher mocks.MockLogFetcher
Config: pit_file.PitFileConfig, converter stability_fee_mocks.MockPitFileStabilityFeeConverter
Fetcher: &mocks.MockLogFetcher{}, repository stability_fee_mocks.MockPitFileStabilityFeeRepository
Converter: &stability_fee_mocks.MockPitFileStabilityFeeConverter{}, transformer shared.Transformer
Repository: repository, headerOne core.Header
} headerTwo core.Header
)
BeforeEach(func() {
fetcher = mocks.MockLogFetcher{}
converter = stability_fee_mocks.MockPitFileStabilityFeeConverter{}
repository = stability_fee_mocks.MockPitFileStabilityFeeRepository{}
transformer = factories.Transformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}.NewTransformer(nil, nil)
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
headerTwo = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
})
It("gets missing headers for block numbers specified in config", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedStartingBlockNumber).To(Equal(pit_file.PitFileConfig.StartingBlockNumber)) Expect(repository.PassedStartingBlockNumber).To(Equal(config.StartingBlockNumber))
Expect(repository.PassedEndingBlockNumber).To(Equal(pit_file.PitFileConfig.EndingBlockNumber)) Expect(repository.PassedEndingBlockNumber).To(Equal(config.EndingBlockNumber))
}) })
It("returns error if repository returns error for missing headers", func() { It("returns error if repository returns error for missing headers", func() {
repository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{}
repository.SetMissingHeadersErr(fakes.FakeError) repository.SetMissingHeadersErr(fakes.FakeError)
transformer := stability_fee.PitFileStabilityFeeTransformer{
Fetcher: &mocks.MockLogFetcher{},
Converter: &stability_fee_mocks.MockPitFileStabilityFeeConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@ -63,33 +78,19 @@ var _ = Describe("Pit file stability fee transformer", func() {
}) })
It("fetches logs for missing headers", func() { It("fetches logs for missing headers", func() {
fetcher := &mocks.MockLogFetcher{} repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
repository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{}
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}, {BlockNumber: 2}})
transformer := stability_fee.PitFileStabilityFeeTransformer{
Fetcher: fetcher,
Converter: &stability_fee_mocks.MockPitFileStabilityFeeConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(Equal([]int64{1, 2})) Expect(fetcher.FetchedBlocks).To(Equal([]int64{headerOne.BlockNumber, headerTwo.BlockNumber}))
Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{pit_file.PitFileConfig.ContractAddresses, pit_file.PitFileConfig.ContractAddresses})) Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{
config.ContractAddresses, config.ContractAddresses}))
Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.PitFileStabilityFeeSignature)}})) Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.PitFileStabilityFeeSignature)}}))
}) })
It("returns error if fetcher returns error", func() { It("returns error if fetcher returns error", func() {
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetcherError(fakes.FakeError) fetcher.SetFetcherError(fakes.FakeError)
repository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := stability_fee.PitFileStabilityFeeTransformer{
Fetcher: fetcher,
Converter: &stability_fee_mocks.MockPitFileStabilityFeeConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -98,34 +99,17 @@ var _ = Describe("Pit file stability fee transformer", func() {
}) })
It("marks header checked if no logs returned", func() { It("marks header checked if no logs returned", func() {
mockConverter := &stability_fee_mocks.MockPitFileStabilityFeeConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{}
headerID := int64(123)
mockRepository.SetMissingHeaders([]core.Header{{Id: headerID}})
mockFetcher := &mocks.MockLogFetcher{}
transformer := stability_fee.PitFileStabilityFeeTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mockRepository.AssertMarkHeaderCheckedCalledWith(headerID) repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
}) })
It("returns error if marking header checked returns err", func() { It("returns error if marking header checked returns err", func() {
mockConverter := &stability_fee_mocks.MockPitFileStabilityFeeConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{} repository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockRepository.SetMissingHeaders([]core.Header{{Id: int64(123)}})
mockRepository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockFetcher := &mocks.MockLogFetcher{}
transformer := stability_fee.PitFileStabilityFeeTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
@ -134,16 +118,8 @@ var _ = Describe("Pit file stability fee transformer", func() {
}) })
It("converts matching logs", func() { It("converts matching logs", func() {
converter := &stability_fee_mocks.MockPitFileStabilityFeeConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileStabilityFeeLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileStabilityFeeLog})
repository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := stability_fee.PitFileStabilityFeeTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -152,17 +128,9 @@ var _ = Describe("Pit file stability fee transformer", func() {
}) })
It("returns error if converter returns error", func() { It("returns error if converter returns error", func() {
converter := &stability_fee_mocks.MockPitFileStabilityFeeConverter{}
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileStabilityFeeLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileStabilityFeeLog})
repository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := stability_fee.PitFileStabilityFeeTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -171,37 +139,20 @@ var _ = Describe("Pit file stability fee transformer", func() {
}) })
It("persists pit file model", func() { It("persists pit file model", func() {
converter := &stability_fee_mocks.MockPitFileStabilityFeeConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileStabilityFeeLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileStabilityFeeLog})
repository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
fakeHeader := core.Header{BlockNumber: 1, Id: 2}
repository.SetMissingHeaders([]core.Header{fakeHeader})
transformer := stability_fee.PitFileStabilityFeeTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(fakeHeader.Id)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]stability_fee.PitFileStabilityFeeModel{test_data.PitFileStabilityFeeModel})) Expect(repository.PassedModels).To(Equal([]interface{}{test_data.PitFileStabilityFeeModel}))
}) })
It("returns error if repository returns error for create", func() { It("returns error if repository returns error for create", func() {
converter := &stability_fee_mocks.MockPitFileStabilityFeeConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileStabilityFeeLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthPitFileStabilityFeeLog})
repository := &stability_fee_mocks.MockPitFileStabilityFeeRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1, Id: 2}})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
transformer := stability_fee.PitFileStabilityFeeTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()

View File

@ -102,4 +102,32 @@ var (
VatTollSignature = GetLogNoteSignature(vatTollMethod) VatTollSignature = GetLogNoteSignature(vatTollMethod)
VatTuneSignature = GetLogNoteSignature(vatTuneMethod) VatTuneSignature = GetLogNoteSignature(vatTuneMethod)
VatFluxSignature = GetLogNoteSignature(vatFluxMethod) VatFluxSignature = GetLogNoteSignature(vatFluxMethod)
BiteLabel = "bite"
DealLabel = "deal"
CatFileChopLumpLabel = "catFileChopLump"
CatFileFlipLabel = "catFileFlip"
CatFilePitVowLabel = "catFilePitVow"
DentLabel = "dent"
DripDripLabel = "dripDrip"
DripFileIlkLabel = "dripFileIlk"
DripFileRepoLabel = "dripFileRepo"
DripFileVowLabel = "dripFileVow"
FlipKickLabel = "flipKick"
FlopKickLabel = "flopKick"
FrobLabel = "frob"
PitFileDebtCeilingLabel = "pitFileDebtCeiling"
PitFileIlkLabel = "pitFileIlk"
PitFileStabilityFeeLabel = "pitFileStabilityFee"
PriceFeedLabel = "priceFeed"
TendLabel = "tend"
VatHealLabel = "vatHeal"
VatGrabLabel = "vatGrab"
VatInitLabel = "vatInit"
VatMoveLabel = "vatMove"
VatFoldLabel = "vatFold"
VatSlipLabel = "vatSlip"
VatTollLabel = "vatToll"
VatTuneLabel = "vatTune"
VatFluxLabel = "vatFlux"
) )

View File

@ -28,10 +28,19 @@ type LogFetcher interface {
FetchLogs(contractAddresses []string, topics [][]common.Hash, blockNumber int64) ([]types.Log, error) FetchLogs(contractAddresses []string, topics [][]common.Hash, blockNumber int64) ([]types.Log, error)
} }
type SettableLogFetcher interface {
LogFetcher
SetBC(bc core.BlockChain)
}
type Fetcher struct { type Fetcher struct {
blockChain core.BlockChain blockChain core.BlockChain
} }
func (fetcher *Fetcher) SetBC(bc core.BlockChain) {
fetcher.blockChain = bc
}
func NewFetcher(blockchain core.BlockChain) Fetcher { func NewFetcher(blockchain core.BlockChain) Fetcher {
return Fetcher{ return Fetcher{
blockChain: blockchain, blockChain: blockchain,

View File

@ -28,9 +28,19 @@ type Transformer interface {
type TransformerInitializer func(db *postgres.DB, blockChain core.BlockChain) Transformer type TransformerInitializer func(db *postgres.DB, blockChain core.BlockChain) Transformer
type TransformerConfig struct { type TransformerConfig struct {
TransformerName string
ContractAddresses []string ContractAddresses []string
ContractAbi string ContractAbi string
Topics []string Topics []string // TODO Change this to single topic
StartingBlockNumber int64
EndingBlockNumber int64
}
type SingleTransformerConfig struct {
TransformerName string
ContractAddresses []string
ContractAbi string
Topic string
StartingBlockNumber int64 StartingBlockNumber int64
EndingBlockNumber int64 EndingBlockNumber int64
} }

View File

@ -16,10 +16,11 @@ package tend
import "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" import "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
var TendConfig = shared.TransformerConfig{ var TendConfig = shared.SingleTransformerConfig{
TransformerName: shared.TendLabel,
ContractAddresses: []string{shared.FlipperContractAddress}, ContractAddresses: []string{shared.FlipperContractAddress},
ContractAbi: shared.FlipperABI, ContractAbi: shared.FlipperABI,
Topics: []string{shared.TendFunctionSignature}, Topic: shared.TendFunctionSignature,
StartingBlockNumber: 0, StartingBlockNumber: 0,
EndingBlockNumber: 10000000, EndingBlockNumber: 10000000,
} }

View File

@ -23,17 +23,9 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
type Converter interface {
ToModels(ethLogs []types.Log) ([]TendModel, error)
}
type TendConverter struct{} type TendConverter struct{}
func NewTendConverter() TendConverter { func (TendConverter) ToModels(ethLogs []types.Log) (results []interface{}, err error) {
return TendConverter{}
}
func (c TendConverter) ToModels(ethLogs []types.Log) (results []TendModel, err error) {
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := validateLog(ethLog) err := validateLog(ethLog)
if err != nil { if err != nil {

View File

@ -28,7 +28,7 @@ var _ = Describe("Tend TendConverter", func() {
var converter tend.TendConverter var converter tend.TendConverter
BeforeEach(func() { BeforeEach(func() {
converter = tend.NewTendConverter() converter = tend.TendConverter{}
}) })
Describe("ToModels", func() { Describe("ToModels", func() {

View File

@ -15,35 +15,34 @@
package tend package tend
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type Repository interface {
Create(headerId int64, tends []TendModel) error
MarkHeaderChecked(headerId int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type TendRepository struct { type TendRepository struct {
DB *postgres.DB db *postgres.DB
} }
func NewTendRepository(db *postgres.DB) TendRepository { func (repository TendRepository) Create(headerId int64, models []interface{}) error {
return TendRepository{DB: db} tx, err := repository.db.Begin()
}
func (r TendRepository) Create(headerId int64, tends []TendModel) error {
tx, err := r.DB.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, tend := range tends {
for _, model := range models {
tend, ok := model.(TendModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, TendModel{})
}
_, err = tx.Exec( _, err = tx.Exec(
`INSERT into maker.tend (header_id, bid_id, lot, bid, guy, tic, tx_idx, raw_log) `INSERT into maker.tend (header_id, bid_id, lot, bid, guy, tic, tx_idx, raw_log)
VALUES($1, $2, $3, $4, $5, $6, $7, $8)`, VALUES($1, $2, $3, $4, $5, $6, $7, $8)`,
headerId, tend.BidId, tend.Lot, tend.Bid, tend.Guy, tend.Tic, tend.TransactionIndex, tend.Raw, headerId, tend.BidId, tend.Lot, tend.Bid, tend.Guy, tend.Tic, tend.TransactionIndex, tend.Raw,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
@ -53,6 +52,7 @@ func (r TendRepository) Create(headerId int64, tends []TendModel) error {
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET tend_checked = $2`, headerId, true) UPDATE SET tend_checked = $2`, headerId, true)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return err return err
@ -60,28 +60,32 @@ func (r TendRepository) Create(headerId int64, tends []TendModel) error {
return tx.Commit() return tx.Commit()
} }
func (r TendRepository) MarkHeaderChecked(headerId int64) error { func (repository TendRepository) MarkHeaderChecked(headerId int64) error {
_, err := r.DB.Exec(`INSERT INTO public.checked_headers (header_id, tend_checked) _, err := repository.db.Exec(`INSERT INTO public.checked_headers (header_id, tend_checked)
VALUES ($1, $2) VALUES ($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
UPDATE SET tend_checked = $2`, headerId, true) UPDATE SET tend_checked = $2`, headerId, true)
return err return err
} }
func (r TendRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository TendRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
var result []core.Header var result []core.Header
err := r.DB.Select( err := repository.db.Select(
&result, &result,
`SELECT headers.id, headers.block_number FROM headers `SELECT headers.id, headers.block_number FROM headers
LEFT JOIN checked_headers on headers.id = header_id LEFT JOIN checked_headers on headers.id = header_id
WHERE (header_id ISNULL OR tend_checked IS FALSE) WHERE (header_id ISNULL OR tend_checked IS FALSE)
AND headers.block_number >= $1 AND headers.block_number >= $1
AND headers.block_number <= $2 AND headers.block_number <= $2
AND headers.eth_node_fingerprint = $3`, AND headers.eth_node_fingerprint = $3`,
startingBlockNumber, startingBlockNumber,
endingBlockNumber, endingBlockNumber,
r.DB.Node.ID, repository.db.Node.ID,
) )
return result, err return result, err
} }
func (repository *TendRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -17,6 +17,7 @@ package tend_test
import ( import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
@ -32,6 +33,7 @@ var _ = Describe("TendRepository", func() {
db *postgres.DB db *postgres.DB
tendRepository tend.TendRepository tendRepository tend.TendRepository
headerRepository repositories.HeaderRepository headerRepository repositories.HeaderRepository
headerId int64
err error err error
) )
@ -40,17 +42,16 @@ var _ = Describe("TendRepository", func() {
db = test_config.NewTestDB(node) db = test_config.NewTestDB(node)
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
tendRepository = tend.NewTendRepository(db) tendRepository = tend.TendRepository{}
tendRepository.SetDB(db)
}) })
Describe("Create", func() { Describe("Create", func() {
var headerId int64
BeforeEach(func() { BeforeEach(func() {
headerId, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerId, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err := tendRepository.Create(headerId, []tend.TendModel{test_data.TendModel}) err = tendRepository.Create(headerId, []interface{}{test_data.TendModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -81,8 +82,7 @@ var _ = Describe("TendRepository", func() {
}) })
It("returns an error if inserting a tend record fails", func() { It("returns an error if inserting a tend record fails", func() {
err = tendRepository.Create(headerId, []tend.TendModel{test_data.TendModel}) err = tendRepository.Create(headerId, []interface{}{test_data.TendModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
}) })
@ -100,11 +100,15 @@ var _ = Describe("TendRepository", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(count).To(Equal(0)) Expect(count).To(Equal(0))
}) })
It("Returns an error if model is of wrong type", func() {
err = tendRepository.Create(headerId, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {
var headerId int64
BeforeEach(func() { BeforeEach(func() {
headerId, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerId, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -140,7 +144,7 @@ var _ = Describe("TendRepository", func() {
) )
BeforeEach(func() { BeforeEach(func() {
tendBlock = GinkgoRandomSeed() tendBlock = rand.Int63()
startingBlock = tendBlock - 1 startingBlock = tendBlock - 1
endingBlock = tendBlock + 1 endingBlock = tendBlock + 1
outOfRangeBlock = tendBlock + 2 outOfRangeBlock = tendBlock + 2
@ -182,7 +186,8 @@ var _ = Describe("TendRepository", func() {
node2 := core.Node{} node2 := core.Node{}
db2 := test_config.NewTestDB(node2) db2 := test_config.NewTestDB(node2)
headerRepository2 := repositories.NewHeaderRepository(db2) headerRepository2 := repositories.NewHeaderRepository(db2)
tendRepository2 := tend.NewTendRepository(db2) tendRepository2 := tend.TendRepository{}
tendRepository2.SetDB(db2)
for _, number := range []int64{startingBlock, tendBlock, endingBlock} { for _, number := range []int64{startingBlock, tendBlock, endingBlock} {
headerRepository2.CreateOrUpdateHeader(fakes.GetFakeHeader(number)) headerRepository2.CreateOrUpdateHeader(fakes.GetFakeHeader(number))

View File

@ -1,88 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tend
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type TendTransformer struct {
Repository Repository
Fetcher shared.LogFetcher
Converter Converter
Config shared.TransformerConfig
}
type TendTransformerInitializer struct {
Config shared.TransformerConfig
}
func (i TendTransformerInitializer) NewTendTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := NewTendConverter()
fetcher := shared.NewFetcher(blockChain)
repository := NewTendRepository(db)
return TendTransformer{
Fetcher: fetcher,
Repository: repository,
Converter: converter,
Config: i.Config,
}
}
func (t TendTransformer) Execute() error {
config := t.Config
topics := [][]common.Hash{{common.HexToHash(shared.TendFunctionSignature)}}
missingHeaders, err := t.Repository.MissingHeaders(config.StartingBlockNumber, config.EndingBlockNumber)
if err != nil {
log.Println("Error fetching missing headers:", err)
return err
}
log.Printf("Fetching tend event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
ethLogs, err := t.Fetcher.FetchLogs(config.ContractAddresses, topics, header.BlockNumber)
if err != nil {
log.Println("Error fetching matching logs:", err)
return err
}
if len(ethLogs) < 1 {
err := t.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
}
models, err := t.Converter.ToModels(ethLogs)
if err != nil {
log.Println("Error converting logs:", err)
return err
}
err = t.Repository.Create(header.Id, models)
if err != nil {
log.Println("Error persisting tend record:", err)
return err
}
}
return nil
}

View File

@ -15,6 +15,7 @@
package tend_test package tend_test
import ( import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"math/rand" "math/rand"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -32,24 +33,33 @@ import (
) )
var _ = Describe("Tend Transformer", func() { var _ = Describe("Tend Transformer", func() {
var repository tend_mocks.MockTendRepository var (
var fetcher mocks.MockLogFetcher config = tend.TendConfig
var converter tend_mocks.MockTendConverter converter tend_mocks.MockTendConverter
var transformer tend.TendTransformer repository tend_mocks.MockTendRepository
var blockNumber1 = rand.Int63() fetcher mocks.MockLogFetcher
var blockNumber2 = rand.Int63() transformer shared.Transformer
headerOne core.Header
headerTwo core.Header
)
BeforeEach(func() { BeforeEach(func() {
converter = tend_mocks.MockTendConverter{}
repository = tend_mocks.MockTendRepository{} repository = tend_mocks.MockTendRepository{}
fetcher = mocks.MockLogFetcher{} fetcher = mocks.MockLogFetcher{}
converter = tend_mocks.MockTendConverter{} headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
headerTwo = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
transformer = tend.TendTransformer{ transformer = factories.Transformer{
Repository: &repository, Config: config,
Fetcher: &fetcher, Fetcher: &fetcher,
Converter: &converter, Converter: &converter,
Config: tend.TendConfig, Repository: &repository,
} }.NewTransformer(nil, nil)
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
}) })
It("gets missing headers for blocks in the configured range", func() { It("gets missing headers for blocks in the configured range", func() {
@ -68,12 +78,12 @@ var _ = Describe("Tend Transformer", func() {
}) })
It("fetches eth logs for each missing header", func() { It("fetches eth logs for each missing header", func() {
repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1}, {BlockNumber: blockNumber2}}) repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
expectedTopics := [][]common.Hash{{common.HexToHash(shared.TendFunctionSignature)}} expectedTopics := [][]common.Hash{{common.HexToHash(shared.TendFunctionSignature)}}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(Equal([]int64{blockNumber1, blockNumber2})) Expect(fetcher.FetchedBlocks).To(Equal([]int64{headerOne.BlockNumber, headerTwo.BlockNumber}))
Expect(fetcher.FetchedTopics).To(Equal(expectedTopics)) Expect(fetcher.FetchedTopics).To(Equal(expectedTopics))
Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{tend.TendConfig.ContractAddresses, tend.TendConfig.ContractAddresses})) Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{tend.TendConfig.ContractAddresses, tend.TendConfig.ContractAddresses}))
}) })
@ -88,34 +98,17 @@ var _ = Describe("Tend Transformer", func() {
}) })
It("marks header checked if no logs returned", func() { It("marks header checked if no logs returned", func() {
mockConverter := &tend_mocks.MockTendConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &tend_mocks.MockTendRepository{}
headerID := int64(123)
mockRepository.SetMissingHeaders([]core.Header{{Id: headerID}})
mockFetcher := &mocks.MockLogFetcher{}
transformer := tend.TendTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mockRepository.AssertMarkHeaderCheckedCalledWith(headerID) repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
}) })
It("returns error if marking header checked returns err", func() { It("returns error if marking header checked returns err", func() {
mockConverter := &tend_mocks.MockTendConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &tend_mocks.MockTendRepository{} repository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockRepository.SetMissingHeaders([]core.Header{{Id: int64(123)}})
mockRepository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockFetcher := &mocks.MockLogFetcher{}
transformer := tend.TendTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
@ -124,37 +117,37 @@ var _ = Describe("Tend Transformer", func() {
}) })
It("converts an eth log to a Model", func() { It("converts an eth log to a Model", func() {
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}}) repository.SetMissingHeaders([]core.Header{headerOne})
fetcher.SetFetchedLogs([]types.Log{test_data.TendLogNote}) fetcher.SetFetchedLogs([]types.Log{test_data.TendLogNote})
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(converter.LogsToConvert).To(Equal([]types.Log{test_data.TendLogNote})) Expect(converter.PassedLogs).To(Equal([]types.Log{test_data.TendLogNote}))
}) })
It("returns an error if converter fails", func() { It("returns an error if converter fails", func() {
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}}) repository.SetMissingHeaders([]core.Header{headerOne})
fetcher.SetFetchedLogs([]types.Log{test_data.TendLogNote}) fetcher.SetFetchedLogs([]types.Log{test_data.TendLogNote})
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
err := transformer.Execute() err := transformer.Execute()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError)) Expect(err).To(MatchError(fakes.FakeError))
}) })
It("persists the tend record", func() { It("persists the tend record", func() {
headerId := int64(1) repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1, Id: headerId}})
fetcher.SetFetchedLogs([]types.Log{test_data.TendLogNote}) fetcher.SetFetchedLogs([]types.Log{test_data.TendLogNote})
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(headerId)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedTendModel).To(Equal(test_data.TendModel)) Expect(repository.PassedTendModel).To(Equal(test_data.TendModel))
}) })
It("returns error if persisting tend record fails", func() { It("returns error if persisting tend record fails", func() {
repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1}}) repository.SetMissingHeaders([]core.Header{headerOne})
fetcher.SetFetchedLogs([]types.Log{test_data.TendLogNote}) fetcher.SetFetchedLogs([]types.Log{test_data.TendLogNote})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
err := transformer.Execute() err := transformer.Execute()

View File

@ -16,20 +16,19 @@ package ilk
import ( import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/ilk"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
) )
type MockDripFileIlkConverter struct { type MockDripFileIlkConverter struct {
converterErr error converterError error
PassedLogs []types.Log PassedLogs []types.Log
} }
func (converter *MockDripFileIlkConverter) ToModels(ethLogs []types.Log) ([]ilk.DripFileIlkModel, error) { func (converter *MockDripFileIlkConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
converter.PassedLogs = ethLogs converter.PassedLogs = ethLogs
return []ilk.DripFileIlkModel{test_data.DripFileIlkModel}, converter.converterErr return []interface{}{test_data.DripFileIlkModel}, converter.converterError
} }
func (converter *MockDripFileIlkConverter) SetConverterError(e error) { func (converter *MockDripFileIlkConverter) SetConverterError(e error) {
converter.converterErr = e converter.converterError = e
} }

View File

@ -16,46 +16,47 @@ package ilk
import ( import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/ilk"
) )
type MockDripFileIlkRepository struct { type MockDripFileIlkRepository struct {
createErr error createError error
markHeaderCheckedErr error markHeaderCheckedError error
markHeaderCheckedPassedHeaderID int64 markHeaderCheckedPassedHeaderID int64
missingHeaders []core.Header missingHeaders []core.Header
missingHeadersErr error missingHeadersError error
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedHeaderID int64 PassedHeaderID int64
PassedModels []ilk.DripFileIlkModel PassedModels []interface{}
SetDbCalled bool
} }
func (repository *MockDripFileIlkRepository) Create(headerID int64, models []ilk.DripFileIlkModel) error { func (repository *MockDripFileIlkRepository) Create(headerID int64, models []interface{}) error {
repository.PassedHeaderID = headerID repository.PassedHeaderID = headerID
repository.PassedModels = models repository.PassedModels = models
return repository.createErr return repository.createError
} }
func (repository *MockDripFileIlkRepository) MarkHeaderChecked(headerID int64) error { func (repository *MockDripFileIlkRepository) MarkHeaderChecked(headerID int64) error {
repository.markHeaderCheckedPassedHeaderID = headerID repository.markHeaderCheckedPassedHeaderID = headerID
return repository.markHeaderCheckedErr return repository.markHeaderCheckedError
} }
func (repository *MockDripFileIlkRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository *MockDripFileIlkRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
repository.PassedStartingBlockNumber = startingBlockNumber repository.PassedStartingBlockNumber = startingBlockNumber
repository.PassedEndingBlockNumber = endingBlockNumber repository.PassedEndingBlockNumber = endingBlockNumber
return repository.missingHeaders, repository.missingHeadersErr return repository.missingHeaders, repository.missingHeadersError
} }
func (repository *MockDripFileIlkRepository) SetMarkHeaderCheckedErr(e error) { func (repository *MockDripFileIlkRepository) SetMarkHeaderCheckedError(e error) {
repository.markHeaderCheckedErr = e repository.markHeaderCheckedError = e
} }
func (repository *MockDripFileIlkRepository) SetMissingHeadersErr(e error) { func (repository *MockDripFileIlkRepository) SetMissingHeadersError(e error) {
repository.missingHeadersErr = e repository.missingHeadersError = e
} }
func (repository *MockDripFileIlkRepository) SetMissingHeaders(headers []core.Header) { func (repository *MockDripFileIlkRepository) SetMissingHeaders(headers []core.Header) {
@ -63,8 +64,12 @@ func (repository *MockDripFileIlkRepository) SetMissingHeaders(headers []core.He
} }
func (repository *MockDripFileIlkRepository) SetCreateError(e error) { func (repository *MockDripFileIlkRepository) SetCreateError(e error) {
repository.createErr = e repository.createError = e
} }
func (repository *MockDripFileIlkRepository) AssertMarkHeaderCheckedCalledWith(i int64) { func (repository *MockDripFileIlkRepository) AssertMarkHeaderCheckedCalledWith(i int64) {
Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i)) Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i))
} }
func (repository *MockDripFileIlkRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -16,20 +16,19 @@ package repo
import ( import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/repo"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
) )
type MockDripFileRepoConverter struct { type MockDripFileRepoConverter struct {
converterErr error converterError error
PassedLogs []types.Log PassedLogs []types.Log
} }
func (converter *MockDripFileRepoConverter) ToModels(ethLogs []types.Log) ([]repo.DripFileRepoModel, error) { func (converter *MockDripFileRepoConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
converter.PassedLogs = ethLogs converter.PassedLogs = ethLogs
return []repo.DripFileRepoModel{test_data.DripFileRepoModel}, converter.converterErr return []interface{}{test_data.DripFileRepoModel}, converter.converterError
} }
func (converter *MockDripFileRepoConverter) SetConverterError(e error) { func (converter *MockDripFileRepoConverter) SetConverterError(e error) {
converter.converterErr = e converter.converterError = e
} }

View File

@ -16,46 +16,47 @@ package repo
import ( import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/repo"
) )
type MockDripFileRepoRepository struct { type MockDripFileRepoRepository struct {
createErr error createError error
markHeaderCheckedErr error markHeaderCheckedError error
markHeaderCheckedPassedHeaderID int64 markHeaderCheckedPassedHeaderID int64
missingHeaders []core.Header missingHeaders []core.Header
missingHeadersErr error missingHeadersError error
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedHeaderID int64 PassedHeaderID int64
PassedModels []repo.DripFileRepoModel PassedModels []interface{}
SetDbCalled bool
} }
func (repository *MockDripFileRepoRepository) Create(headerID int64, models []repo.DripFileRepoModel) error { func (repository *MockDripFileRepoRepository) Create(headerID int64, models []interface{}) error {
repository.PassedHeaderID = headerID repository.PassedHeaderID = headerID
repository.PassedModels = models repository.PassedModels = models
return repository.createErr return repository.createError
} }
func (repository *MockDripFileRepoRepository) MarkHeaderChecked(headerID int64) error { func (repository *MockDripFileRepoRepository) MarkHeaderChecked(headerID int64) error {
repository.markHeaderCheckedPassedHeaderID = headerID repository.markHeaderCheckedPassedHeaderID = headerID
return repository.markHeaderCheckedErr return repository.markHeaderCheckedError
} }
func (repository *MockDripFileRepoRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository *MockDripFileRepoRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
repository.PassedStartingBlockNumber = startingBlockNumber repository.PassedStartingBlockNumber = startingBlockNumber
repository.PassedEndingBlockNumber = endingBlockNumber repository.PassedEndingBlockNumber = endingBlockNumber
return repository.missingHeaders, repository.missingHeadersErr return repository.missingHeaders, repository.missingHeadersError
} }
func (repository *MockDripFileRepoRepository) SetMarkHeaderCheckedErr(e error) { func (repository *MockDripFileRepoRepository) SetMarkHeaderCheckedError(e error) {
repository.markHeaderCheckedErr = e repository.markHeaderCheckedError = e
} }
func (repository *MockDripFileRepoRepository) SetMissingHeadersErr(e error) { func (repository *MockDripFileRepoRepository) SetMissingHeadersError(e error) {
repository.missingHeadersErr = e repository.missingHeadersError = e
} }
func (repository *MockDripFileRepoRepository) SetMissingHeaders(headers []core.Header) { func (repository *MockDripFileRepoRepository) SetMissingHeaders(headers []core.Header) {
@ -63,8 +64,13 @@ func (repository *MockDripFileRepoRepository) SetMissingHeaders(headers []core.H
} }
func (repository *MockDripFileRepoRepository) SetCreateError(e error) { func (repository *MockDripFileRepoRepository) SetCreateError(e error) {
repository.createErr = e repository.createError = e
} }
func (repository *MockDripFileRepoRepository) AssertMarkHeaderCheckedCalledWith(i int64) { func (repository *MockDripFileRepoRepository) AssertMarkHeaderCheckedCalledWith(i int64) {
Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i)) Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i))
} }
func (repository *MockDripFileRepoRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -16,7 +16,6 @@ package vow
import ( import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
) )
@ -25,9 +24,9 @@ type MockDripFileVowConverter struct {
PassedLogs []types.Log PassedLogs []types.Log
} }
func (converter *MockDripFileVowConverter) ToModels(ethLogs []types.Log) ([]vow.DripFileVowModel, error) { func (converter *MockDripFileVowConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
converter.PassedLogs = ethLogs converter.PassedLogs = ethLogs
return []vow.DripFileVowModel{test_data.DripFileVowModel}, converter.converterErr return []interface{}{test_data.DripFileVowModel}, converter.converterErr
} }
func (converter *MockDripFileVowConverter) SetConverterError(e error) { func (converter *MockDripFileVowConverter) SetConverterError(e error) {

View File

@ -16,46 +16,47 @@ package vow
import ( import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow"
) )
type MockDripFileVowRepository struct { type MockDripFileVowRepository struct {
createErr error createError error
markHeaderCheckedErr error markHeaderCheckedError error
markHeaderCheckedPassedHeaderID int64 markHeaderCheckedPassedHeaderID int64
missingHeaders []core.Header missingHeaders []core.Header
missingHeadersErr error missingHeadersError error
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedHeaderID int64 PassedHeaderID int64
PassedModels []vow.DripFileVowModel PassedModels []interface{}
SetDbCalled bool
} }
func (repository *MockDripFileVowRepository) Create(headerID int64, models []vow.DripFileVowModel) error { func (repository *MockDripFileVowRepository) Create(headerID int64, models []interface{}) error {
repository.PassedHeaderID = headerID repository.PassedHeaderID = headerID
repository.PassedModels = models repository.PassedModels = models
return repository.createErr return repository.createError
} }
func (repository *MockDripFileVowRepository) MarkHeaderChecked(headerID int64) error { func (repository *MockDripFileVowRepository) MarkHeaderChecked(headerID int64) error {
repository.markHeaderCheckedPassedHeaderID = headerID repository.markHeaderCheckedPassedHeaderID = headerID
return repository.markHeaderCheckedErr return repository.markHeaderCheckedError
} }
func (repository *MockDripFileVowRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository *MockDripFileVowRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
repository.PassedStartingBlockNumber = startingBlockNumber repository.PassedStartingBlockNumber = startingBlockNumber
repository.PassedEndingBlockNumber = endingBlockNumber repository.PassedEndingBlockNumber = endingBlockNumber
return repository.missingHeaders, repository.missingHeadersErr return repository.missingHeaders, repository.missingHeadersError
} }
func (repository *MockDripFileVowRepository) SetMarkHeaderCheckedErr(e error) { func (repository *MockDripFileVowRepository) SetMarkHeaderCheckedError(e error) {
repository.markHeaderCheckedErr = e repository.markHeaderCheckedError = e
} }
func (repository *MockDripFileVowRepository) SetMissingHeadersErr(e error) { func (repository *MockDripFileVowRepository) SetMissingHeadersError(e error) {
repository.missingHeadersErr = e repository.missingHeadersError = e
} }
func (repository *MockDripFileVowRepository) SetMissingHeaders(headers []core.Header) { func (repository *MockDripFileVowRepository) SetMissingHeaders(headers []core.Header) {
@ -63,8 +64,12 @@ func (repository *MockDripFileVowRepository) SetMissingHeaders(headers []core.He
} }
func (repository *MockDripFileVowRepository) SetCreateError(e error) { func (repository *MockDripFileVowRepository) SetCreateError(e error) {
repository.createErr = e repository.createError = e
} }
func (repository *MockDripFileVowRepository) AssertMarkHeaderCheckedCalledWith(i int64) { func (repository *MockDripFileVowRepository) AssertMarkHeaderCheckedCalledWith(i int64) {
Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i)) Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i))
} }
func (repository *MockDripFileVowRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -17,6 +17,7 @@ package mocks
import ( import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/core"
) )
type MockLogFetcher struct { type MockLogFetcher struct {
@ -25,6 +26,7 @@ type MockLogFetcher struct {
FetchedBlocks []int64 FetchedBlocks []int64
fetcherError error fetcherError error
FetchedLogs []types.Log FetchedLogs []types.Log
SetBcCalled bool
} }
func (mlf *MockLogFetcher) FetchLogs(contractAddresses []string, topics [][]common.Hash, blockNumber int64) ([]types.Log, error) { func (mlf *MockLogFetcher) FetchLogs(contractAddresses []string, topics [][]common.Hash, blockNumber int64) ([]types.Log, error) {
@ -35,6 +37,10 @@ func (mlf *MockLogFetcher) FetchLogs(contractAddresses []string, topics [][]comm
return mlf.FetchedLogs, mlf.fetcherError return mlf.FetchedLogs, mlf.fetcherError
} }
func (mlf *MockLogFetcher) SetBC(bc core.BlockChain) {
mlf.SetBcCalled = true
}
func (mlf *MockLogFetcher) SetFetcherError(err error) { func (mlf *MockLogFetcher) SetFetcherError(err error) {
mlf.fetcherError = err mlf.fetcherError = err
} }

View File

@ -17,20 +17,19 @@ package debt_ceiling
import ( import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
) )
type MockPitFileDebtCeilingConverter struct { type MockPitFileDebtCeilingConverter struct {
converterErr error converterError error
PassedLogs []types.Log PassedLogs []types.Log
} }
func (converter *MockPitFileDebtCeilingConverter) ToModels(ethLogs []types.Log) ([]debt_ceiling.PitFileDebtCeilingModel, error) { func (converter *MockPitFileDebtCeilingConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
converter.PassedLogs = ethLogs converter.PassedLogs = ethLogs
return []debt_ceiling.PitFileDebtCeilingModel{test_data.PitFileDebtCeilingModel}, converter.converterErr return []interface{}{test_data.PitFileDebtCeilingModel}, converter.converterError
} }
func (converter *MockPitFileDebtCeilingConverter) SetConverterError(e error) { func (converter *MockPitFileDebtCeilingConverter) SetConverterError(e error) {
converter.converterErr = e converter.converterError = e
} }

View File

@ -16,46 +16,47 @@ package debt_ceiling
import ( import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling"
) )
type MockPitFileDebtCeilingRepository struct { type MockPitFileDebtCeilingRepository struct {
createErr error createError error
markHeaderCheckedErr error markHeaderCheckedError error
markHeaderCheckedPassedHeaderID int64 markHeaderCheckedPassedHeaderID int64
missingHeaders []core.Header missingHeaders []core.Header
missingHeadersErr error missingHeadersError error
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedHeaderID int64 PassedHeaderID int64
PassedModels []debt_ceiling.PitFileDebtCeilingModel PassedModels []interface{}
SetDbCalled bool
} }
func (repository *MockPitFileDebtCeilingRepository) MarkHeaderChecked(headerID int64) error { func (repository *MockPitFileDebtCeilingRepository) MarkHeaderChecked(headerID int64) error {
repository.markHeaderCheckedPassedHeaderID = headerID repository.markHeaderCheckedPassedHeaderID = headerID
return repository.markHeaderCheckedErr return repository.markHeaderCheckedError
} }
func (repository *MockPitFileDebtCeilingRepository) Create(headerID int64, models []debt_ceiling.PitFileDebtCeilingModel) error { func (repository *MockPitFileDebtCeilingRepository) Create(headerID int64, models []interface{}) error {
repository.PassedHeaderID = headerID repository.PassedHeaderID = headerID
repository.PassedModels = models repository.PassedModels = models
return repository.createErr return repository.createError
} }
func (repository *MockPitFileDebtCeilingRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository *MockPitFileDebtCeilingRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
repository.PassedStartingBlockNumber = startingBlockNumber repository.PassedStartingBlockNumber = startingBlockNumber
repository.PassedEndingBlockNumber = endingBlockNumber repository.PassedEndingBlockNumber = endingBlockNumber
return repository.missingHeaders, repository.missingHeadersErr return repository.missingHeaders, repository.missingHeadersError
} }
func (repository *MockPitFileDebtCeilingRepository) SetMarkHeaderCheckedErr(e error) { func (repository *MockPitFileDebtCeilingRepository) SetMarkHeaderCheckedError(e error) {
repository.markHeaderCheckedErr = e repository.markHeaderCheckedError = e
} }
func (repository *MockPitFileDebtCeilingRepository) SetMissingHeadersErr(e error) { func (repository *MockPitFileDebtCeilingRepository) SetMissingHeadersError(e error) {
repository.missingHeadersErr = e repository.missingHeadersError = e
} }
func (repository *MockPitFileDebtCeilingRepository) SetMissingHeaders(headers []core.Header) { func (repository *MockPitFileDebtCeilingRepository) SetMissingHeaders(headers []core.Header) {
@ -63,9 +64,13 @@ func (repository *MockPitFileDebtCeilingRepository) SetMissingHeaders(headers []
} }
func (repository *MockPitFileDebtCeilingRepository) SetCreateError(e error) { func (repository *MockPitFileDebtCeilingRepository) SetCreateError(e error) {
repository.createErr = e repository.createError = e
} }
func (repository *MockPitFileDebtCeilingRepository) AssertMarkHeaderCheckedCalledWith(i int64) { func (repository *MockPitFileDebtCeilingRepository) AssertMarkHeaderCheckedCalledWith(i int64) {
Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i)) Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i))
} }
func (repository *MockPitFileDebtCeilingRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -17,7 +17,6 @@ package ilk
import ( import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/ilk"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
) )
@ -30,7 +29,7 @@ func (converter *MockPitFileIlkConverter) SetConverterError(err error) {
converter.converterError = err converter.converterError = err
} }
func (converter *MockPitFileIlkConverter) ToModels(ethLogs []types.Log) ([]ilk.PitFileIlkModel, error) { func (converter *MockPitFileIlkConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
converter.PassedLogs = ethLogs converter.PassedLogs = ethLogs
return []ilk.PitFileIlkModel{test_data.PitFileIlkModel}, converter.converterError return []interface{}{test_data.PitFileIlkModel}, converter.converterError
} }

View File

@ -16,40 +16,41 @@ package ilk
import ( import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/ilk"
) )
type MockPitFileIlkRepository struct { type MockPitFileIlkRepository struct {
createError error createError error
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedModels []ilk.PitFileIlkModel PassedModels []interface{}
PassedHeaderID int64 PassedHeaderID int64
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
markHeaderCheckedErr error markHeaderCheckedError error
markHeaderCheckedPassedHeaderID int64 markHeaderCheckedPassedHeaderID int64
missingHeaders []core.Header missingHeaders []core.Header
missingHeadersErr error missingHeadersError error
SetDbCalled bool
} }
func (repository *MockPitFileIlkRepository) SetCreateError(err error) { func (repository *MockPitFileIlkRepository) SetCreateError(err error) {
repository.createError = err repository.createError = err
} }
func (repository *MockPitFileIlkRepository) SetMarkHeaderCheckedErr(e error) { func (repository *MockPitFileIlkRepository) SetMarkHeaderCheckedError(e error) {
repository.markHeaderCheckedErr = e repository.markHeaderCheckedError = e
} }
func (repository *MockPitFileIlkRepository) SetMissingHeadersErr(err error) { func (repository *MockPitFileIlkRepository) SetMissingHeadersError(err error) {
repository.missingHeadersErr = err repository.missingHeadersError = err
} }
func (repository *MockPitFileIlkRepository) SetMissingHeaders(headers []core.Header) { func (repository *MockPitFileIlkRepository) SetMissingHeaders(headers []core.Header) {
repository.missingHeaders = headers repository.missingHeaders = headers
} }
func (repository *MockPitFileIlkRepository) Create(headerID int64, models []ilk.PitFileIlkModel) error { func (repository *MockPitFileIlkRepository) Create(headerID int64, models []interface{}) error {
repository.PassedHeaderID = headerID repository.PassedHeaderID = headerID
repository.PassedModels = models repository.PassedModels = models
return repository.createError return repository.createError
@ -57,15 +58,19 @@ func (repository *MockPitFileIlkRepository) Create(headerID int64, models []ilk.
func (repository *MockPitFileIlkRepository) MarkHeaderChecked(headerID int64) error { func (repository *MockPitFileIlkRepository) MarkHeaderChecked(headerID int64) error {
repository.markHeaderCheckedPassedHeaderID = headerID repository.markHeaderCheckedPassedHeaderID = headerID
return repository.markHeaderCheckedErr return repository.markHeaderCheckedError
} }
func (repository *MockPitFileIlkRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository *MockPitFileIlkRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
repository.PassedStartingBlockNumber = startingBlockNumber repository.PassedStartingBlockNumber = startingBlockNumber
repository.PassedEndingBlockNumber = endingBlockNumber repository.PassedEndingBlockNumber = endingBlockNumber
return repository.missingHeaders, repository.missingHeadersErr return repository.missingHeaders, repository.missingHeadersError
} }
func (repository *MockPitFileIlkRepository) AssertMarkHeaderCheckedCalledWith(i int64) { func (repository *MockPitFileIlkRepository) AssertMarkHeaderCheckedCalledWith(i int64) {
Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i)) Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i))
} }
func (repository *MockPitFileIlkRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -17,20 +17,19 @@ package stability_fee
import ( import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/stability_fee"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
) )
type MockPitFileStabilityFeeConverter struct { type MockPitFileStabilityFeeConverter struct {
converterErr error converterError error
PassedLogs []types.Log PassedLogs []types.Log
} }
func (converter *MockPitFileStabilityFeeConverter) ToModels(ethLogs []types.Log) ([]stability_fee.PitFileStabilityFeeModel, error) { func (converter *MockPitFileStabilityFeeConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
converter.PassedLogs = ethLogs converter.PassedLogs = ethLogs
return []stability_fee.PitFileStabilityFeeModel{test_data.PitFileStabilityFeeModel}, converter.converterErr return []interface{}{test_data.PitFileStabilityFeeModel}, converter.converterError
} }
func (converter *MockPitFileStabilityFeeConverter) SetConverterError(e error) { func (converter *MockPitFileStabilityFeeConverter) SetConverterError(e error) {
converter.converterErr = e converter.converterError = e
} }

View File

@ -16,46 +16,47 @@ package stability_fee
import ( import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/stability_fee"
) )
type MockPitFileStabilityFeeRepository struct { type MockPitFileStabilityFeeRepository struct {
createErr error createError error
markHeaderCheckedErr error markHeaderCheckedError error
markHeaderCheckedPassedHeaderID int64 markHeaderCheckedPassedHeaderID int64
missingHeaders []core.Header missingHeaders []core.Header
missingHeadersErr error missingHeadersError error
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedHeaderID int64 PassedHeaderID int64
PassedModels []stability_fee.PitFileStabilityFeeModel PassedModels []interface{}
SetDbCalled bool
} }
func (repository *MockPitFileStabilityFeeRepository) Create(headerID int64, models []stability_fee.PitFileStabilityFeeModel) error { func (repository *MockPitFileStabilityFeeRepository) Create(headerID int64, models []interface{}) error {
repository.PassedModels = models repository.PassedModels = models
repository.PassedHeaderID = headerID repository.PassedHeaderID = headerID
return repository.createErr return repository.createError
} }
func (repository *MockPitFileStabilityFeeRepository) MarkHeaderChecked(headerID int64) error { func (repository *MockPitFileStabilityFeeRepository) MarkHeaderChecked(headerID int64) error {
repository.markHeaderCheckedPassedHeaderID = headerID repository.markHeaderCheckedPassedHeaderID = headerID
return repository.markHeaderCheckedErr return repository.markHeaderCheckedError
} }
func (repository *MockPitFileStabilityFeeRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository *MockPitFileStabilityFeeRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
repository.PassedStartingBlockNumber = startingBlockNumber repository.PassedStartingBlockNumber = startingBlockNumber
repository.PassedEndingBlockNumber = endingBlockNumber repository.PassedEndingBlockNumber = endingBlockNumber
return repository.missingHeaders, repository.missingHeadersErr return repository.missingHeaders, repository.missingHeadersError
} }
func (repository *MockPitFileStabilityFeeRepository) SetMarkHeaderCheckedErr(e error) { func (repository *MockPitFileStabilityFeeRepository) SetMarkHeaderCheckedErr(e error) {
repository.markHeaderCheckedErr = e repository.markHeaderCheckedError = e
} }
func (repository *MockPitFileStabilityFeeRepository) SetMissingHeadersErr(e error) { func (repository *MockPitFileStabilityFeeRepository) SetMissingHeadersErr(e error) {
repository.missingHeadersErr = e repository.missingHeadersError = e
} }
func (repository *MockPitFileStabilityFeeRepository) SetMissingHeaders(headers []core.Header) { func (repository *MockPitFileStabilityFeeRepository) SetMissingHeaders(headers []core.Header) {
@ -63,9 +64,13 @@ func (repository *MockPitFileStabilityFeeRepository) SetMissingHeaders(headers [
} }
func (repository *MockPitFileStabilityFeeRepository) SetCreateError(e error) { func (repository *MockPitFileStabilityFeeRepository) SetCreateError(e error) {
repository.createErr = e repository.createError = e
} }
func (repository *MockPitFileStabilityFeeRepository) AssertMarkHeaderCheckedCalledWith(i int64) { func (repository *MockPitFileStabilityFeeRepository) AssertMarkHeaderCheckedCalledWith(i int64) {
Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i)) Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i))
} }
func (repository *MockPitFileStabilityFeeRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -17,20 +17,19 @@ package tend
import ( import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/tend"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
) )
type MockTendConverter struct { type MockTendConverter struct {
LogsToConvert []types.Log PassedLogs []types.Log
ConverterError error ConverterError error
} }
func (c *MockTendConverter) ToModels(ethLogs []types.Log) ([]tend.TendModel, error) { func (converter *MockTendConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
c.LogsToConvert = append(c.LogsToConvert, ethLogs...) converter.PassedLogs = ethLogs
return []tend.TendModel{test_data.TendModel}, c.ConverterError return []interface{}{test_data.TendModel}, converter.ConverterError
} }
func (c *MockTendConverter) SetConverterError(err error) { func (converter *MockTendConverter) SetConverterError(err error) {
c.ConverterError = err converter.ConverterError = err
} }

View File

@ -16,9 +16,9 @@ package tend
import ( import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/tend"
) )
type MockTendRepository struct { type MockTendRepository struct {
@ -26,14 +26,15 @@ type MockTendRepository struct {
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedHeaderID int64 PassedHeaderID int64
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
PassedTendModel tend.TendModel PassedTendModel interface{}
markHeaderCheckedErr error markHeaderCheckedError error
markHeaderCheckedPassedHeaderId int64 markHeaderCheckedPassedHeaderId int64
missingHeaders []core.Header missingHeaders []core.Header
missingHeadersErr error missingHeadersError error
SetDbCalled bool
} }
func (repository *MockTendRepository) Create(headerId int64, tend []tend.TendModel) error { func (repository *MockTendRepository) Create(headerId int64, tend []interface{}) error {
repository.PassedHeaderID = headerId repository.PassedHeaderID = headerId
repository.PassedTendModel = tend[0] repository.PassedTendModel = tend[0]
return repository.createError return repository.createError
@ -44,11 +45,11 @@ func (repository *MockTendRepository) SetCreateError(err error) {
} }
func (repository *MockTendRepository) SetMarkHeaderCheckedErr(err error) { func (repository *MockTendRepository) SetMarkHeaderCheckedErr(err error) {
repository.markHeaderCheckedErr = err repository.markHeaderCheckedError = err
} }
func (repository *MockTendRepository) SetMissingHeadersErr(err error) { func (repository *MockTendRepository) SetMissingHeadersErr(err error) {
repository.missingHeadersErr = err repository.missingHeadersError = err
} }
func (repository *MockTendRepository) SetMissingHeaders(headers []core.Header) { func (repository *MockTendRepository) SetMissingHeaders(headers []core.Header) {
@ -57,15 +58,19 @@ func (repository *MockTendRepository) SetMissingHeaders(headers []core.Header) {
func (repository *MockTendRepository) MarkHeaderChecked(headerId int64) error { func (repository *MockTendRepository) MarkHeaderChecked(headerId int64) error {
repository.markHeaderCheckedPassedHeaderId = headerId repository.markHeaderCheckedPassedHeaderId = headerId
return repository.markHeaderCheckedErr return repository.markHeaderCheckedError
} }
func (repository *MockTendRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository *MockTendRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
repository.PassedStartingBlockNumber = startingBlockNumber repository.PassedStartingBlockNumber = startingBlockNumber
repository.PassedEndingBlockNumber = endingBlockNumber repository.PassedEndingBlockNumber = endingBlockNumber
return repository.missingHeaders, repository.missingHeadersErr return repository.missingHeaders, repository.missingHeadersError
} }
func (repository *MockTendRepository) AssertMarkHeaderCheckedCalledWith(headerId int64) { func (repository *MockTendRepository) AssertMarkHeaderCheckedCalledWith(headerId int64) {
Expect(repository.markHeaderCheckedPassedHeaderId).To(Equal(headerId)) Expect(repository.markHeaderCheckedPassedHeaderId).To(Equal(headerId))
} }
func (repository *MockTendRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -18,19 +18,18 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/vat_init"
) )
type MockVatInitConverter struct { type MockVatInitConverter struct {
converterErr error converterError error
PassedLogs []types.Log PassedLogs []types.Log
} }
func (converter *MockVatInitConverter) ToModels(ethLogs []types.Log) ([]vat_init.VatInitModel, error) { func (converter *MockVatInitConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
converter.PassedLogs = ethLogs converter.PassedLogs = ethLogs
return []vat_init.VatInitModel{test_data.VatInitModel}, converter.converterErr return []interface{}{test_data.VatInitModel}, converter.converterError
} }
func (converter *MockVatInitConverter) SetConverterError(e error) { func (converter *MockVatInitConverter) SetConverterError(e error) {
converter.converterErr = e converter.converterError = e
} }

View File

@ -16,46 +16,47 @@ package vat_init
import ( import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/vat_init"
) )
type MockVatInitRepository struct { type MockVatInitRepository struct {
createErr error createError error
markHeaderCheckedErr error markHeaderCheckedError error
markHeaderCheckedPassedHeaderID int64 markHeaderCheckedPassedHeaderID int64
missingHeaders []core.Header missingHeaders []core.Header
missingHeadersErr error missingHeadersError error
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedHeaderID int64 PassedHeaderID int64
PassedModels []vat_init.VatInitModel PassedModels []interface{}
SetDbCalled bool
} }
func (repository *MockVatInitRepository) Create(headerID int64, models []vat_init.VatInitModel) error { func (repository *MockVatInitRepository) Create(headerID int64, models []interface{}) error {
repository.PassedHeaderID = headerID repository.PassedHeaderID = headerID
repository.PassedModels = models repository.PassedModels = models
return repository.createErr return repository.createError
} }
func (repository *MockVatInitRepository) MarkHeaderChecked(headerID int64) error { func (repository *MockVatInitRepository) MarkHeaderChecked(headerID int64) error {
repository.markHeaderCheckedPassedHeaderID = headerID repository.markHeaderCheckedPassedHeaderID = headerID
return repository.markHeaderCheckedErr return repository.markHeaderCheckedError
} }
func (repository *MockVatInitRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { func (repository *MockVatInitRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
repository.PassedStartingBlockNumber = startingBlockNumber repository.PassedStartingBlockNumber = startingBlockNumber
repository.PassedEndingBlockNumber = endingBlockNumber repository.PassedEndingBlockNumber = endingBlockNumber
return repository.missingHeaders, repository.missingHeadersErr return repository.missingHeaders, repository.missingHeadersError
} }
func (repository *MockVatInitRepository) SetMarkHeaderCheckedErr(e error) { func (repository *MockVatInitRepository) SetMarkHeaderCheckedError(e error) {
repository.markHeaderCheckedErr = e repository.markHeaderCheckedError = e
} }
func (repository *MockVatInitRepository) SetMissingHeadersErr(e error) { func (repository *MockVatInitRepository) SetMissingHeadersError(e error) {
repository.missingHeadersErr = e repository.missingHeadersError = e
} }
func (repository *MockVatInitRepository) SetMissingHeaders(headers []core.Header) { func (repository *MockVatInitRepository) SetMissingHeaders(headers []core.Header) {
@ -63,9 +64,13 @@ func (repository *MockVatInitRepository) SetMissingHeaders(headers []core.Header
} }
func (repository *MockVatInitRepository) SetCreateError(e error) { func (repository *MockVatInitRepository) SetCreateError(e error) {
repository.createErr = e repository.createError = e
} }
func (repository *MockVatInitRepository) AssertMarkHeaderCheckedCalledWith(i int64) { func (repository *MockVatInitRepository) AssertMarkHeaderCheckedCalledWith(i int64) {
Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i)) Expect(repository.markHeaderCheckedPassedHeaderID).To(Equal(i))
} }
func (repository *MockVatInitRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -17,7 +17,6 @@ package vat_move
import ( import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/vat_move"
) )
type MockVatMoveConverter struct { type MockVatMoveConverter struct {
@ -25,9 +24,9 @@ type MockVatMoveConverter struct {
PassedLogs []types.Log PassedLogs []types.Log
} }
func (converter *MockVatMoveConverter) ToModels(ethLogs []types.Log) ([]vat_move.VatMoveModel, error) { func (converter *MockVatMoveConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
converter.PassedLogs = ethLogs converter.PassedLogs = ethLogs
return []vat_move.VatMoveModel{test_data.VatMoveModel}, converter.converterError return []interface{}{test_data.VatMoveModel}, converter.converterError
} }
func (converter *MockVatMoveConverter) SetConverterError(e error) { func (converter *MockVatMoveConverter) SetConverterError(e error) {

View File

@ -16,7 +16,7 @@ package vat_move
import ( import (
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/vat_move" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type MockVatMoveRepository struct { type MockVatMoveRepository struct {
@ -26,12 +26,13 @@ type MockVatMoveRepository struct {
PassedStartingBlockNumber int64 PassedStartingBlockNumber int64
PassedEndingBlockNumber int64 PassedEndingBlockNumber int64
PassedHeaderID int64 PassedHeaderID int64
PassedModels []vat_move.VatMoveModel PassedModels []interface{}
CheckedHeaderIDs []int64 CheckedHeaderIDs []int64
CheckedHeaderError error CheckedHeaderError error
SetDbCalled bool
} }
func (repository *MockVatMoveRepository) Create(headerID int64, models []vat_move.VatMoveModel) error { func (repository *MockVatMoveRepository) Create(headerID int64, models []interface{}) error {
repository.PassedHeaderID = headerID repository.PassedHeaderID = headerID
repository.PassedModels = models repository.PassedModels = models
return repository.createError return repository.createError
@ -63,3 +64,7 @@ func (repository *MockVatMoveRepository) MarkHeaderChecked(headerId int64) error
func (repository *MockVatMoveRepository) SetCheckedHeaderError(e error) { func (repository *MockVatMoveRepository) SetCheckedHeaderError(e error) {
repository.CheckedHeaderError = e repository.CheckedHeaderError = e
} }
func (repository *MockVatMoveRepository) SetDB(db *postgres.DB) {
repository.SetDbCalled = true
}

View File

@ -0,0 +1,17 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package test_data
type WrongModel struct{}

View File

@ -23,14 +23,13 @@ import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/deal" "github.com/vulcanize/vulcanizedb/pkg/transformers/deal"
"github.com/vulcanize/vulcanizedb/pkg/transformers/dent" "github.com/vulcanize/vulcanizedb/pkg/transformers/dent"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_drip" "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_drip"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file"
ilk2 "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/ilk" ilk2 "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/ilk"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/repo" "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/repo"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow" "github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/flip_kick" "github.com/vulcanize/vulcanizedb/pkg/transformers/flip_kick"
"github.com/vulcanize/vulcanizedb/pkg/transformers/flop_kick" "github.com/vulcanize/vulcanizedb/pkg/transformers/flop_kick"
"github.com/vulcanize/vulcanizedb/pkg/transformers/frob" "github.com/vulcanize/vulcanizedb/pkg/transformers/frob"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling" "github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/debt_ceiling"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/ilk" "github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/ilk"
"github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/stability_fee" "github.com/vulcanize/vulcanizedb/pkg/transformers/pit_file/stability_fee"
@ -49,36 +48,86 @@ import (
) )
var ( var (
BiteTransformerInitializer = bite.BiteTransformerInitializer{Config: bite.BiteConfig}.NewBiteTransformer BiteTransformerInitializer = bite.BiteTransformerInitializer{Config: bite.BiteConfig}.NewBiteTransformer
catFileConfig = cat_file.CatFileConfig catFileConfig = cat_file.CatFileConfig
CatFileChopLumpTransformerInitializer = chop_lump.CatFileChopLumpTransformerInitializer{Config: catFileConfig}.NewCatFileChopLumpTransformer CatFileChopLumpTransformerInitializer = chop_lump.CatFileChopLumpTransformerInitializer{Config: catFileConfig}.NewCatFileChopLumpTransformer
CatFileFlipTransformerInitializer = flip.CatFileFlipTransformerInitializer{Config: catFileConfig}.NewCatFileFlipTransformer CatFileFlipTransformerInitializer = flip.CatFileFlipTransformerInitializer{Config: catFileConfig}.NewCatFileFlipTransformer
CatFilePitVowTransformerInitializer = pit_vow.CatFilePitVowTransformerInitializer{Config: catFileConfig}.NewCatFilePitVowTransformer CatFilePitVowTransformerInitializer = pit_vow.CatFilePitVowTransformerInitializer{Config: catFileConfig}.NewCatFilePitVowTransformer
DealTransformerInitializer = deal.DealTransformerInitializer{Config: deal.Config}.NewDealTransformer DealTransformerInitializer = deal.DealTransformerInitializer{Config: deal.Config}.NewDealTransformer
DentTransformerInitializer = dent.DentTransformerInitializer{Config: dent.DentConfig}.NewDentTransformer DentTransformerInitializer = dent.DentTransformerInitializer{Config: dent.DentConfig}.NewDentTransformer
DripDripTransformerInitializer = drip_drip.DripDripTransformerInitializer{Config: drip_drip.DripDripConfig}.NewDripDripTransformer DripDripTransformerInitializer = drip_drip.DripDripTransformerInitializer{Config: drip_drip.DripDripConfig}.NewDripDripTransformer
dripFileConfig = drip_file.DripFileConfig DripFileIlkTransformerInitializer = factories.Transformer{
DripFileIlkTransformerInitializer = ilk2.DripFileIlkTransformerInitializer{Config: dripFileConfig}.NewDripFileIlkTransformer Config: ilk2.DripFileIlkConfig,
DripFileRepoTransformerInitializer = repo.DripFileRepoTransformerInitializer{Config: dripFileConfig}.NewDripFileRepoTransformer Converter: &ilk2.DripFileIlkConverter{},
DripFileVowTransfromerInitializer = vow.DripFileVowTransformerInitializer{Config: dripFileConfig}.NewDripFileVowTransformer Repository: &ilk2.DripFileIlkRepository{},
FlipKickTransformerInitializer = flip_kick.FlipKickTransformerInitializer{Config: flip_kick.FlipKickConfig}.NewFlipKickTransformer Fetcher: &shared.Fetcher{},
FlopKickTransformerInitializer = flop_kick.FlopKickTransformerInitializer{Config: flop_kick.Config}.NewFlopKickTransformer }.NewTransformer
FrobTransformerInitializer = frob.FrobTransformerInitializer{Config: frob.FrobConfig}.NewFrobTransformer
pitFileConfig = pit_file.PitFileConfig DripFileRepoTransformerInitializer = factories.Transformer{
PitFileDebtCeilingTransformerInitializer = debt_ceiling.PitFileDebtCeilingTransformerInitializer{Config: pitFileConfig}.NewPitFileDebtCeilingTransformer Config: repo.DripFileRepoConfig,
PitFileIlkTransformerInitializer = ilk.PitFileIlkTransformerInitializer{Config: pitFileConfig}.NewPitFileIlkTransformer Converter: &repo.DripFileRepoConverter{},
PitFileStabilityFeeTransformerInitializer = stability_fee.PitFileStabilityFeeTransformerInitializer{Config: pitFileConfig}.NewPitFileStabilityFeeTransformer Repository: &repo.DripFileRepoRepository{},
PriceFeedTransformerInitializer = price_feeds.PriceFeedTransformerInitializer{Config: price_feeds.PriceFeedConfig}.NewPriceFeedTransformer Fetcher: &shared.Fetcher{},
TendTransformerInitializer = tend.TendTransformerInitializer{Config: tend.TendConfig}.NewTendTransformer }.NewTransformer
VatGrabTransformerInitializer = vat_grab.VatGrabTransformerInitializer{Config: vat_grab.VatGrabConfig}.NewVatGrabTransformer
VatInitTransformerInitializer = vat_init.VatInitTransformerInitializer{Config: vat_init.VatInitConfig}.NewVatInitTransformer DripFileVowTransfromerInitializer = factories.Transformer{
VatMoveTransformerInitializer = vat_move.VatMoveTransformerInitializer{Config: vat_move.VatMoveConfig}.NewVatMoveTransformer Config: vow.DripFileVowConfig,
VatHealTransformerInitializer = vat_heal.VatHealTransformerInitializer{Config: vat_heal.VatHealConfig}.NewVatHealTransformer Converter: &vow.DripFileVowConverter{},
VatFoldTransformerInitializer = vat_fold.VatFoldTransformerInitializer{Config: vat_fold.VatFoldConfig}.NewVatFoldTransformer Repository: &vow.DripFileVowRepository{},
VatSlipTransformerInitializer = vat_slip.VatSlipTransformerInitializer{Config: vat_slip.VatSlipConfig}.NewVatSlipTransformer Fetcher: &shared.Fetcher{},
VatTollTransformerInitializer = vat_toll.VatTollTransformerInitializer{Config: vat_toll.VatTollConfig}.NewVatTollTransformer }.NewTransformer
VatTuneTransformerInitializer = vat_tune.VatTuneTransformerInitializer{Config: vat_tune.VatTuneConfig}.NewVatTuneTransformer
VatFluxTransformerInitializer = vat_flux.VatFluxTransformerInitializer{Config: vat_flux.VatFluxConfig}.NewVatFluxTransformer FlipKickTransformerInitializer = flip_kick.FlipKickTransformerInitializer{Config: flip_kick.FlipKickConfig}.NewFlipKickTransformer
FlopKickTransformerInitializer = flop_kick.FlopKickTransformerInitializer{Config: flop_kick.Config}.NewFlopKickTransformer
FrobTransformerInitializer = frob.FrobTransformerInitializer{Config: frob.FrobConfig}.NewFrobTransformer
PitFileDebtCeilingTransformerInitializer = factories.Transformer{
Config: debt_ceiling.DebtCeilingFileConfig,
Converter: &debt_ceiling.PitFileDebtCeilingConverter{},
Repository: &debt_ceiling.PitFileDebtCeilingRepository{},
Fetcher: &shared.Fetcher{},
}.NewTransformer
PitFileIlkTransformerInitializer = factories.Transformer{
Config: ilk.IlkFileConfig,
Converter: &ilk.PitFileIlkConverter{},
Repository: &ilk.PitFileIlkRepository{},
Fetcher: &shared.Fetcher{},
}.NewTransformer
PitFileStabilityFeeTransformerInitializer = factories.Transformer{
Config: stability_fee.StabilityFeeFileConfig,
Converter: &stability_fee.PitFileStabilityFeeConverter{},
Repository: &stability_fee.PitFileStabilityFeeRepository{},
Fetcher: &shared.Fetcher{},
}.NewTransformer
PriceFeedTransformerInitializer = price_feeds.PriceFeedTransformerInitializer{Config: price_feeds.PriceFeedConfig}.NewPriceFeedTransformer
TendTransformerInitializer = factories.Transformer{
Config: tend.TendConfig,
Converter: &tend.TendConverter{},
Repository: &tend.TendRepository{},
Fetcher: &shared.Fetcher{},
}.NewTransformer
VatInitTransformerInitializer = factories.Transformer{
Config: vat_init.VatInitConfig,
Converter: &vat_init.VatInitConverter{},
Repository: &vat_init.VatInitRepository{},
Fetcher: &shared.Fetcher{},
}.NewTransformer
VatGrabTransformerInitializer = vat_grab.VatGrabTransformerInitializer{Config: vat_grab.VatGrabConfig}.NewVatGrabTransformer
VatHealTransformerInitializer = vat_heal.VatHealTransformerInitializer{Config: vat_heal.VatHealConfig}.NewVatHealTransformer
VatFoldTransformerInitializer = vat_fold.VatFoldTransformerInitializer{Config: vat_fold.VatFoldConfig}.NewVatFoldTransformer
VatMoveTransformerInitializer = factories.Transformer{
Config: vat_move.VatMoveConfig,
Converter: &vat_move.VatMoveConverter{},
Repository: &vat_move.VatMoveRepository{},
Fetcher: &shared.Fetcher{},
}.NewTransformer
VatSlipTransformerInitializer = vat_slip.VatSlipTransformerInitializer{Config: vat_slip.VatSlipConfig}.NewVatSlipTransformer
VatTollTransformerInitializer = vat_toll.VatTollTransformerInitializer{Config: vat_toll.VatTollConfig}.NewVatTollTransformer
VatTuneTransformerInitializer = vat_tune.VatTuneTransformerInitializer{Config: vat_tune.VatTuneConfig}.NewVatTuneTransformer
VatFluxTransformerInitializer = vat_flux.VatFluxTransformerInitializer{Config: vat_flux.VatFluxConfig}.NewVatFluxTransformer
) )
func TransformerInitializers() []shared.TransformerInitializer { func TransformerInitializers() []shared.TransformerInitializer {

View File

@ -18,10 +18,11 @@ import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
) )
var VatInitConfig = shared.TransformerConfig{ var VatInitConfig = shared.SingleTransformerConfig{
TransformerName: shared.VatInitLabel,
ContractAddresses: []string{shared.VatContractAddress}, ContractAddresses: []string{shared.VatContractAddress},
ContractAbi: shared.VatABI, ContractAbi: shared.VatABI,
Topics: []string{shared.VatInitSignature}, Topic: shared.VatInitSignature,
StartingBlockNumber: 0, StartingBlockNumber: 0,
EndingBlockNumber: 10000000, EndingBlockNumber: 10000000,
} }

View File

@ -18,18 +18,13 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
type Converter interface {
ToModels(ethLogs []types.Log) ([]VatInitModel, error)
}
type VatInitConverter struct{} type VatInitConverter struct{}
func (VatInitConverter) ToModels(ethLogs []types.Log) ([]VatInitModel, error) { func (VatInitConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []VatInitModel var models []interface{}
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := verifyLog(ethLog) err := verifyLog(ethLog)
if err != nil { if err != nil {

View File

@ -24,18 +24,20 @@ import (
) )
var _ = Describe("Vat init converter", func() { var _ = Describe("Vat init converter", func() {
It("returns err if log missing topics", func() { var converter vat_init.VatInitConverter
converter := vat_init.VatInitConverter{}
badLog := types.Log{}
BeforeEach(func() {
converter = vat_init.VatInitConverter{}
})
It("returns err if log missing topics", func() {
badLog := types.Log{}
_, err := converter.ToModels([]types.Log{badLog}) _, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
It("converts a log to an model", func() { It("converts a log to an model", func() {
converter := vat_init.VatInitConverter{}
models, err := converter.ToModels([]types.Log{test_data.EthVatInitLog}) models, err := converter.ToModels([]types.Log{test_data.EthVatInitLog})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -15,42 +15,42 @@
package vat_init package vat_init
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"log"
) )
type Repository interface {
Create(headerID int64, models []VatInitModel) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
}
type VatInitRepository struct { type VatInitRepository struct {
db *postgres.DB db *postgres.DB
} }
func NewVatInitRepository(db *postgres.DB) VatInitRepository { func (repository VatInitRepository) Create(headerID int64, models []interface{}) error {
return VatInitRepository{
db: db,
}
}
func (repository VatInitRepository) Create(headerID int64, models []VatInitModel) error {
tx, err := repository.db.Begin() tx, err := repository.db.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, model := range models { for _, model := range models {
vatInit, ok := model.(VatInitModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, VatInitModel{})
}
log.Printf("VatInit model: %v", vatInit)
_, err = tx.Exec( _, err = tx.Exec(
`INSERT into maker.vat_init (header_id, ilk, tx_idx, raw_log) `INSERT INTO maker.vat_init (header_id, ilk, tx_idx, raw_log)
VALUES($1, $2, $3, $4)`, VALUES($1, $2, $3, $4)`,
headerID, model.Ilk, model.TransactionIndex, model.Raw, headerID, vatInit.Ilk, vatInit.TransactionIndex, vatInit.Raw,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
log.Printf("Error: %v \n", err)
return err return err
} }
} }
_, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, vat_init_checked) _, err = tx.Exec(`INSERT INTO public.checked_headers (header_id, vat_init_checked)
VALUES($1, $2) VALUES($1, $2)
ON CONFLICT (header_id) DO ON CONFLICT (header_id) DO
@ -87,3 +87,7 @@ func (repository VatInitRepository) MissingHeaders(startingBlockNumber, endingBl
) )
return result, err return result, err
} }
func (repository *VatInitRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -16,6 +16,7 @@ package vat_init_test
import ( import (
"database/sql" "database/sql"
"math/rand"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -32,7 +33,7 @@ import (
var _ = Describe("Vat init repository", func() { var _ = Describe("Vat init repository", func() {
var ( var (
db *postgres.DB db *postgres.DB
vatInitRepository vat_init.Repository vatInitRepository vat_init.VatInitRepository
headerRepository repositories.HeaderRepository headerRepository repositories.HeaderRepository
err error err error
) )
@ -40,7 +41,8 @@ var _ = Describe("Vat init repository", func() {
BeforeEach(func() { BeforeEach(func() {
db = test_config.NewTestDB(core.Node{}) db = test_config.NewTestDB(core.Node{})
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
vatInitRepository = vat_init.NewVatInitRepository(db) vatInitRepository = vat_init.VatInitRepository{}
vatInitRepository.SetDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
}) })
@ -51,13 +53,13 @@ var _ = Describe("Vat init repository", func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = vatInitRepository.Create(headerID, []vat_init.VatInitModel{test_data.VatInitModel}) err = vatInitRepository.Create(headerID, []interface{}{test_data.VatInitModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
It("adds a vat event", func() { It("adds a vat event", func() {
var dbVatInit vat_init.VatInitModel var dbVatInit vat_init.VatInitModel
err = db.Get(&dbVatInit, `SELECT ilk,tx_idx, raw_log FROM maker.vat_init WHERE header_id = $1`, headerID) err = db.Get(&dbVatInit, `SELECT ilk, tx_idx, raw_log FROM maker.vat_init WHERE header_id = $1`, headerID)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(dbVatInit.Ilk).To(Equal(test_data.VatInitModel.Ilk)) Expect(dbVatInit.Ilk).To(Equal(test_data.VatInitModel.Ilk))
Expect(dbVatInit.TransactionIndex).To(Equal(test_data.VatInitModel.TransactionIndex)) Expect(dbVatInit.TransactionIndex).To(Equal(test_data.VatInitModel.TransactionIndex))
@ -65,7 +67,7 @@ var _ = Describe("Vat init repository", func() {
}) })
It("does not duplicate vat events", func() { It("does not duplicate vat events", func() {
err = vatInitRepository.Create(headerID, []vat_init.VatInitModel{test_data.VatInitModel}) err = vatInitRepository.Create(headerID, []interface{}{test_data.VatInitModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
@ -87,6 +89,12 @@ var _ = Describe("Vat init repository", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(headerChecked).To(BeTrue()) Expect(headerChecked).To(BeTrue())
}) })
It("Returns an error if model is of wrong type", func() {
err = vatInitRepository.Create(headerID, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {
@ -95,7 +103,6 @@ var _ = Describe("Vat init repository", func() {
BeforeEach(func() { BeforeEach(func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
It("creates a row for a new headerID", func() { It("creates a row for a new headerID", func() {
@ -128,7 +135,7 @@ var _ = Describe("Vat init repository", func() {
) )
BeforeEach(func() { BeforeEach(func() {
startingBlock = GinkgoRandomSeed() startingBlock = rand.Int63()
vatInitBlock = startingBlock + 1 vatInitBlock = startingBlock + 1
endingBlock = startingBlock + 2 endingBlock = startingBlock + 2
@ -174,8 +181,10 @@ var _ = Describe("Vat init repository", func() {
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
vatInitRepositoryTwo := vat_init.NewVatInitRepository(dbTwo)
err := vatInitRepository.MarkHeaderChecked(headerIDs[0]) vatInitRepositoryTwo := vat_init.VatInitRepository{}
vatInitRepositoryTwo.SetDB(dbTwo)
err = vatInitRepository.MarkHeaderChecked(headerIDs[0])
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
nodeOneMissingHeaders, err := vatInitRepository.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1]) nodeOneMissingHeaders, err := vatInitRepository.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1])

View File

@ -1,78 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package vat_init
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type VatInitTransformerInitializer struct {
Config shared.TransformerConfig
}
func (initializer VatInitTransformerInitializer) NewVatInitTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := VatInitConverter{}
fetcher := shared.NewFetcher(blockChain)
repository := NewVatInitRepository(db)
return VatInitTransformer{
Config: initializer.Config,
Converter: converter,
Fetcher: fetcher,
Repository: repository,
}
}
type VatInitTransformer struct {
Config shared.TransformerConfig
Converter Converter
Fetcher shared.LogFetcher
Repository Repository
}
func (transformer VatInitTransformer) Execute() error {
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
return err
}
log.Printf("Fetching vat init event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
topics := [][]common.Hash{{common.HexToHash(shared.VatInitSignature)}}
matchingLogs, err := transformer.Fetcher.FetchLogs(VatInitConfig.ContractAddresses, topics, header.BlockNumber)
if err != nil {
return err
}
if len(matchingLogs) < 1 {
err = transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
}
models, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
return err
}
err = transformer.Repository.Create(header.Id, models)
if err != nil {
return err
}
}
return nil
}

View File

@ -19,6 +19,8 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/fakes"
@ -30,15 +32,36 @@ import (
) )
var _ = Describe("Vat init transformer", func() { var _ = Describe("Vat init transformer", func() {
It("gets missing headers for block numbers specified in config", func() { var (
repository := &vat_init_mocks.MockVatInitRepository{} config = vat_init.VatInitConfig
transformer := vat_init.VatInitTransformer{ converter vat_init_mocks.MockVatInitConverter
Config: vat_init.VatInitConfig, repository vat_init_mocks.MockVatInitRepository
Fetcher: &mocks.MockLogFetcher{}, fetcher mocks.MockLogFetcher
Converter: &vat_init_mocks.MockVatInitConverter{}, transformer shared.Transformer
Repository: repository, headerOne core.Header
} headerTwo core.Header
)
BeforeEach(func() {
converter = vat_init_mocks.MockVatInitConverter{}
repository = vat_init_mocks.MockVatInitRepository{}
fetcher = mocks.MockLogFetcher{}
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
headerTwo = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
transformer = factories.Transformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}.NewTransformer(nil, nil)
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
})
It("gets missing headers for block numbers specified in config", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -47,13 +70,7 @@ var _ = Describe("Vat init transformer", func() {
}) })
It("returns error if repository returns error for missing headers", func() { It("returns error if repository returns error for missing headers", func() {
repository := &vat_init_mocks.MockVatInitRepository{} repository.SetMissingHeadersError(fakes.FakeError)
repository.SetMissingHeadersErr(fakes.FakeError)
transformer := vat_init.VatInitTransformer{
Fetcher: &mocks.MockLogFetcher{},
Converter: &vat_init_mocks.MockVatInitConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -62,33 +79,20 @@ var _ = Describe("Vat init transformer", func() {
}) })
It("fetches logs for missing headers", func() { It("fetches logs for missing headers", func() {
fetcher := &mocks.MockLogFetcher{} repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
repository := &vat_init_mocks.MockVatInitRepository{}
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}, {BlockNumber: 2}})
transformer := vat_init.VatInitTransformer{
Fetcher: fetcher,
Converter: &vat_init_mocks.MockVatInitConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(Equal([]int64{1, 2})) Expect(fetcher.FetchedBlocks).To(Equal([]int64{headerOne.BlockNumber, headerTwo.BlockNumber}))
Expect(fetcher.FetchedContractAddresses).To(Equal([][]string{vat_init.VatInitConfig.ContractAddresses, vat_init.VatInitConfig.ContractAddresses})) Expect(fetcher.FetchedContractAddresses).To(Equal(
[][]string{config.ContractAddresses, config.ContractAddresses}))
Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.VatInitSignature)}})) Expect(fetcher.FetchedTopics).To(Equal([][]common.Hash{{common.HexToHash(shared.VatInitSignature)}}))
}) })
It("returns error if fetcher returns error", func() { It("returns error if fetcher returns error", func() {
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetcherError(fakes.FakeError) fetcher.SetFetcherError(fakes.FakeError)
repository := &vat_init_mocks.MockVatInitRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := vat_init.VatInitTransformer{
Fetcher: fetcher,
Converter: &vat_init_mocks.MockVatInitConverter{},
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -97,34 +101,17 @@ var _ = Describe("Vat init transformer", func() {
}) })
It("marks header checked if no logs returned", func() { It("marks header checked if no logs returned", func() {
mockConverter := &vat_init_mocks.MockVatInitConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &vat_init_mocks.MockVatInitRepository{}
headerID := int64(123)
mockRepository.SetMissingHeaders([]core.Header{{Id: headerID}})
mockFetcher := &mocks.MockLogFetcher{}
transformer := vat_init.VatInitTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
mockRepository.AssertMarkHeaderCheckedCalledWith(headerID) repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
}) })
It("returns error if marking header checked returns err", func() { It("returns error if marking header checked returns err", func() {
mockConverter := &vat_init_mocks.MockVatInitConverter{} repository.SetMissingHeaders([]core.Header{headerOne})
mockRepository := &vat_init_mocks.MockVatInitRepository{} repository.SetMarkHeaderCheckedError(fakes.FakeError)
mockRepository.SetMissingHeaders([]core.Header{{Id: int64(123)}})
mockRepository.SetMarkHeaderCheckedErr(fakes.FakeError)
mockFetcher := &mocks.MockLogFetcher{}
transformer := vat_init.VatInitTransformer{
Converter: mockConverter,
Fetcher: mockFetcher,
Repository: mockRepository,
}
err := transformer.Execute() err := transformer.Execute()
@ -133,16 +120,8 @@ var _ = Describe("Vat init transformer", func() {
}) })
It("converts matching logs", func() { It("converts matching logs", func() {
converter := &vat_init_mocks.MockVatInitConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthVatInitLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthVatInitLog})
repository := &vat_init_mocks.MockVatInitRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := vat_init.VatInitTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -151,17 +130,9 @@ var _ = Describe("Vat init transformer", func() {
}) })
It("returns error if converter returns error", func() { It("returns error if converter returns error", func() {
converter := &vat_init_mocks.MockVatInitConverter{}
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthVatInitLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthVatInitLog})
repository := &vat_init_mocks.MockVatInitRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}})
transformer := vat_init.VatInitTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -170,37 +141,20 @@ var _ = Describe("Vat init transformer", func() {
}) })
It("persists vat init model", func() { It("persists vat init model", func() {
converter := &vat_init_mocks.MockVatInitConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthVatInitLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthVatInitLog})
repository := &vat_init_mocks.MockVatInitRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
fakeHeader := core.Header{BlockNumber: 1, Id: 2}
repository.SetMissingHeaders([]core.Header{fakeHeader})
transformer := vat_init.VatInitTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(fakeHeader.Id)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]vat_init.VatInitModel{test_data.VatInitModel})) Expect(repository.PassedModels).To(Equal([]interface{}{test_data.VatInitModel}))
}) })
It("returns error if repository returns error for create", func() { It("returns error if repository returns error for create", func() {
converter := &vat_init_mocks.MockVatInitConverter{}
fetcher := &mocks.MockLogFetcher{}
fetcher.SetFetchedLogs([]types.Log{test_data.EthVatInitLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthVatInitLog})
repository := &vat_init_mocks.MockVatInitRepository{} repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetMissingHeaders([]core.Header{{BlockNumber: 1, Id: 2}})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
transformer := vat_init.VatInitTransformer{
Fetcher: fetcher,
Converter: converter,
Repository: repository,
}
err := transformer.Execute() err := transformer.Execute()

View File

@ -18,10 +18,11 @@ import (
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
) )
var VatMoveConfig = shared.TransformerConfig{ var VatMoveConfig = shared.SingleTransformerConfig{
TransformerName: shared.VatMoveLabel,
ContractAddresses: []string{shared.VatContractAddress}, ContractAddresses: []string{shared.VatContractAddress},
ContractAbi: shared.VatABI, ContractAbi: shared.VatABI,
Topics: []string{shared.VatMoveSignature}, Topic: shared.VatMoveSignature,
StartingBlockNumber: 0, StartingBlockNumber: 0,
EndingBlockNumber: 10000000, EndingBlockNumber: 10000000,
} }

View File

@ -21,18 +21,14 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
type Converter interface {
ToModels(ethLog []types.Log) ([]VatMoveModel, error)
}
type VatMoveConverter struct{} type VatMoveConverter struct{}
func (VatMoveConverter) ToModels(ethLogs []types.Log) ([]VatMoveModel, error) { func (VatMoveConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []VatMoveModel var models []interface{}
for _, ethLog := range ethLogs { for _, ethLog := range ethLogs {
err := verifyLog(ethLog) err := verifyLog(ethLog)
if err != nil { if err != nil {
return []VatMoveModel{}, err return []interface{}{}, err
} }
src := common.BytesToAddress(ethLog.Topics[1].Bytes()) src := common.BytesToAddress(ethLog.Topics[1].Bytes())
@ -40,7 +36,7 @@ func (VatMoveConverter) ToModels(ethLogs []types.Log) ([]VatMoveModel, error) {
rad := ethLog.Topics[3].Big() rad := ethLog.Topics[3].Big()
raw, err := json.Marshal(ethLog) raw, err := json.Marshal(ethLog)
if err != nil { if err != nil {
return []VatMoveModel{}, err return []interface{}{}, err
} }
models = append(models, VatMoveModel{ models = append(models, VatMoveModel{

View File

@ -24,18 +24,20 @@ import (
) )
var _ = Describe("Vat move converter", func() { var _ = Describe("Vat move converter", func() {
It("returns err if logs are missing topics", func() { var converter vat_move.VatMoveConverter
converter := vat_move.VatMoveConverter{}
badLog := types.Log{}
BeforeEach(func() {
converter = vat_move.VatMoveConverter{}
})
It("returns err if logs are missing topics", func() {
badLog := types.Log{}
_, err := converter.ToModels([]types.Log{badLog}) _, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
It("converts a log to a model", func() { It("converts a log to a model", func() {
converter := vat_move.VatMoveConverter{}
models, err := converter.ToModels([]types.Log{test_data.EthVatMoveLog}) models, err := converter.ToModels([]types.Log{test_data.EthVatMoveLog})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@ -15,33 +15,28 @@
package vat_move package vat_move
import ( import (
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
) )
type Repository interface {
Create(headerID int64, models []VatMoveModel) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
MarkHeaderChecked(headerID int64) error
}
type VatMoveRepository struct { type VatMoveRepository struct {
db *postgres.DB db *postgres.DB
} }
func NewVatMoveRepository(db *postgres.DB) VatMoveRepository { func (repository VatMoveRepository) Create(headerID int64, models []interface{}) error {
return VatMoveRepository{
db: db,
}
}
func (repository VatMoveRepository) Create(headerID int64, models []VatMoveModel) error {
tx, err := repository.db.Begin() tx, err := repository.db.Begin()
if err != nil { if err != nil {
return err return err
} }
for _, vatMove := range models { for _, model := range models {
vatMove, ok := model.(VatMoveModel)
if !ok {
tx.Rollback()
return fmt.Errorf("model of type %T, not %T", model, VatMoveModel{})
}
_, err = tx.Exec( _, err = tx.Exec(
`INSERT INTO maker.vat_move (header_id, src, dst, rad, tx_idx, raw_log) `INSERT INTO maker.vat_move (header_id, src, dst, rad, tx_idx, raw_log)
VALUES ($1, $2, $3, $4::NUMERIC, $5, $6)`, VALUES ($1, $2, $3, $4::NUMERIC, $5, $6)`,
@ -94,3 +89,7 @@ func (repository VatMoveRepository) MarkHeaderChecked(headerID int64) error {
UPDATE SET vat_move_checked = $2`, headerID, true) UPDATE SET vat_move_checked = $2`, headerID, true)
return err return err
} }
func (repository *VatMoveRepository) SetDB(db *postgres.DB) {
repository.db = db
}

View File

@ -16,9 +16,9 @@ package vat_move_test
import ( import (
"database/sql" "database/sql"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"math/rand"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
@ -38,7 +38,8 @@ var _ = Describe("Vat Move", func() {
db = test_config.NewTestDB(core.Node{}) db = test_config.NewTestDB(core.Node{})
test_config.CleanTestDB(db) test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db) headerRepository = repositories.NewHeaderRepository(db)
vatMoveRepository = vat_move.NewVatMoveRepository(db) vatMoveRepository = vat_move.VatMoveRepository{}
vatMoveRepository.SetDB(db)
}) })
Describe("Create", func() { Describe("Create", func() {
@ -48,7 +49,7 @@ var _ = Describe("Vat Move", func() {
BeforeEach(func() { BeforeEach(func() {
headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader) headerID, err = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
err = vatMoveRepository.Create(headerID, []vat_move.VatMoveModel{test_data.VatMoveModel}) err = vatMoveRepository.Create(headerID, []interface{}{test_data.VatMoveModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@ -71,7 +72,7 @@ var _ = Describe("Vat Move", func() {
}) })
It("returns an error if insertion fails", func() { It("returns an error if insertion fails", func() {
err = vatMoveRepository.Create(headerID, []vat_move.VatMoveModel{test_data.VatMoveModel}) err = vatMoveRepository.Create(headerID, []interface{}{test_data.VatMoveModel})
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
}) })
@ -85,10 +86,16 @@ var _ = Describe("Vat Move", func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(sql.ErrNoRows)) Expect(err).To(MatchError(sql.ErrNoRows))
}) })
It("Returns an error if model is of wrong type", func() {
err = vatMoveRepository.Create(headerID, []interface{}{test_data.WrongModel{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("model of type"))
})
}) })
Describe("MissingHeaders", func() { Describe("MissingHeaders", func() {
var eventBlockNumber = GinkgoRandomSeed() var eventBlockNumber = rand.Int63()
var startingBlockNumber = eventBlockNumber - 1 var startingBlockNumber = eventBlockNumber - 1
var endingBlockNumber = eventBlockNumber + 1 var endingBlockNumber = eventBlockNumber + 1
var outOfRangeBlockNumber = eventBlockNumber + 2 var outOfRangeBlockNumber = eventBlockNumber + 2
@ -145,8 +152,9 @@ var _ = Describe("Vat Move", func() {
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n)) _, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
vatMoveRepositoryTwo := vat_move.NewVatMoveRepository(dbTwo) vatMoveRepositoryTwo := vat_move.VatMoveRepository{}
err := vatMoveRepository.Create(headerIDs[0], []vat_move.VatMoveModel{test_data.VatMoveModel}) vatMoveRepositoryTwo.SetDB(dbTwo)
err := vatMoveRepository.Create(headerIDs[0], []interface{}{test_data.VatMoveModel})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
nodeOneMissingHeaders, err := vatMoveRepository.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1]) nodeOneMissingHeaders, err := vatMoveRepository.MissingHeaders(blockNumbers[0], blockNumbers[len(blockNumbers)-1])
@ -157,7 +165,6 @@ var _ = Describe("Vat Move", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(nodeTwoMissingHeaders)).To(Equal(len(blockNumbers))) Expect(len(nodeTwoMissingHeaders)).To(Equal(len(blockNumbers)))
}) })
}) })
Describe("MarkHeaderChecked", func() { Describe("MarkHeaderChecked", func() {

View File

@ -1,83 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package vat_move
import (
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type VatMoveTransformerInitializer struct {
Config shared.TransformerConfig
}
func (initializer VatMoveTransformerInitializer) NewVatMoveTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
converter := VatMoveConverter{}
fetcher := shared.NewFetcher(blockChain)
repository := NewVatMoveRepository(db)
return VatMoveTransformer{
Config: initializer.Config,
Converter: converter,
Fetcher: fetcher,
Repository: repository,
}
}
type VatMoveTransformer struct {
Config shared.TransformerConfig
Converter Converter
Fetcher shared.LogFetcher
Repository Repository
}
func (transformer VatMoveTransformer) Execute() error {
missingHeaders, err := transformer.Repository.MissingHeaders(transformer.Config.StartingBlockNumber, transformer.Config.EndingBlockNumber)
if err != nil {
return err
}
log.Printf("Fetching vat move event logs for %d headers \n", len(missingHeaders))
for _, header := range missingHeaders {
topics := [][]common.Hash{{common.HexToHash(shared.VatMoveSignature)}}
matchingLogs, err := transformer.Fetcher.FetchLogs(VatMoveConfig.ContractAddresses, topics, header.BlockNumber)
if err != nil {
return err
}
if len(matchingLogs) < 1 {
err := transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
return err
}
continue
}
models, err := transformer.Converter.ToModels(matchingLogs)
if err != nil {
return err
}
err = transformer.Repository.Create(header.Id, models)
if err != nil {
return err
}
}
return nil
}

View File

@ -21,18 +21,21 @@ import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks"
vat_move_mocks "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks/vat_move" vat_move_mocks "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks/vat_move"
"github.com/vulcanize/vulcanizedb/pkg/transformers/vat_move" "github.com/vulcanize/vulcanizedb/pkg/transformers/vat_move"
"math/rand"
) )
var _ = Describe("Vat move transformer", func() { var _ = Describe("Vat move transformer", func() {
var config = vat_move.VatMoveConfig
var fetcher mocks.MockLogFetcher var fetcher mocks.MockLogFetcher
var converter vat_move_mocks.MockVatMoveConverter var converter vat_move_mocks.MockVatMoveConverter
var repository vat_move_mocks.MockVatMoveRepository var repository vat_move_mocks.MockVatMoveRepository
var config = vat_move.VatMoveConfig var transformer shared.Transformer
var headerOne core.Header var headerOne core.Header
var headerTwo core.Header var headerTwo core.Header
@ -40,18 +43,22 @@ var _ = Describe("Vat move transformer", func() {
fetcher = mocks.MockLogFetcher{} fetcher = mocks.MockLogFetcher{}
converter = vat_move_mocks.MockVatMoveConverter{} converter = vat_move_mocks.MockVatMoveConverter{}
repository = vat_move_mocks.MockVatMoveRepository{} repository = vat_move_mocks.MockVatMoveRepository{}
headerOne = core.Header{Id: GinkgoRandomSeed(), BlockNumber: GinkgoRandomSeed()} headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
headerTwo = core.Header{Id: GinkgoRandomSeed(), BlockNumber: GinkgoRandomSeed()} headerTwo = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
}) transformer = factories.Transformer{
It("gets missing headers for block numbers specified in config", func() {
transformer := vat_move.VatMoveTransformer{
Config: config, Config: config,
Converter: &converter, Converter: &converter,
Fetcher: &fetcher, Fetcher: &fetcher,
Repository: &repository, Repository: &repository,
} }.NewTransformer(nil, nil)
})
It("sets the blockchain and database", func() {
Expect(fetcher.SetBcCalled).To(BeTrue())
Expect(repository.SetDbCalled).To(BeTrue())
})
It("gets missing headers for block numbers specified in config", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -61,12 +68,6 @@ var _ = Describe("Vat move transformer", func() {
It("returns error if repository returns error for missing headers", func() { It("returns error if repository returns error for missing headers", func() {
repository.SetMissingHeadersError(fakes.FakeError) repository.SetMissingHeadersError(fakes.FakeError)
transformer := vat_move.VatMoveTransformer{
Config: config,
Converter: &converter,
Fetcher: &fetcher,
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -76,12 +77,6 @@ var _ = Describe("Vat move transformer", func() {
It("fetches logs for missing headers", func() { It("fetches logs for missing headers", func() {
repository.SetMissingHeaders([]core.Header{headerOne, headerTwo}) repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
transformer := vat_move.VatMoveTransformer{
Config: config,
Fetcher: &fetcher,
Converter: &vat_move_mocks.MockVatMoveConverter{},
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -97,12 +92,6 @@ var _ = Describe("Vat move transformer", func() {
It("returns error if fetcher returns error", func() { It("returns error if fetcher returns error", func() {
fetcher.SetFetcherError(fakes.FakeError) fetcher.SetFetcherError(fakes.FakeError)
repository.SetMissingHeaders([]core.Header{headerOne}) repository.SetMissingHeaders([]core.Header{headerOne})
transformer := vat_move.VatMoveTransformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -113,12 +102,6 @@ var _ = Describe("Vat move transformer", func() {
It("converts matching logs", func() { It("converts matching logs", func() {
fetcher.SetFetchedLogs([]types.Log{test_data.EthVatMoveLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthVatMoveLog})
repository.SetMissingHeaders([]core.Header{headerOne}) repository.SetMissingHeaders([]core.Header{headerOne})
transformer := vat_move.VatMoveTransformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -130,12 +113,6 @@ var _ = Describe("Vat move transformer", func() {
converter.SetConverterError(fakes.FakeError) converter.SetConverterError(fakes.FakeError)
fetcher.SetFetchedLogs([]types.Log{test_data.EthVatMoveLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthVatMoveLog})
repository.SetMissingHeaders([]core.Header{headerOne}) repository.SetMissingHeaders([]core.Header{headerOne})
transformer := vat_move.VatMoveTransformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -146,12 +123,6 @@ var _ = Describe("Vat move transformer", func() {
It("marks header as checked even if no logs were returned", func() { It("marks header as checked even if no logs were returned", func() {
repository.SetMissingHeaders([]core.Header{headerOne, headerTwo}) repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
fetcher.SetFetchedLogs([]types.Log{}) fetcher.SetFetchedLogs([]types.Log{})
transformer := vat_move.VatMoveTransformer{
Config: config,
Converter: &converter,
Fetcher: &fetcher,
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -163,12 +134,6 @@ var _ = Describe("Vat move transformer", func() {
repository.SetMissingHeaders([]core.Header{headerOne, headerTwo}) repository.SetMissingHeaders([]core.Header{headerOne, headerTwo})
repository.SetCheckedHeaderError(fakes.FakeError) repository.SetCheckedHeaderError(fakes.FakeError)
fetcher.SetFetchedLogs([]types.Log{}) fetcher.SetFetchedLogs([]types.Log{})
transformer := vat_move.VatMoveTransformer{
Config: config,
Converter: &converter,
Fetcher: &fetcher,
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()
@ -179,30 +144,18 @@ var _ = Describe("Vat move transformer", func() {
It("persists vat move model", func() { It("persists vat move model", func() {
fetcher.SetFetchedLogs([]types.Log{test_data.EthVatMoveLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthVatMoveLog})
repository.SetMissingHeaders([]core.Header{headerOne}) repository.SetMissingHeaders([]core.Header{headerOne})
transformer := vat_move.VatMoveTransformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(headerOne.Id)) Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]vat_move.VatMoveModel{test_data.VatMoveModel})) Expect(repository.PassedModels).To(Equal([]interface{}{test_data.VatMoveModel}))
}) })
It("returns error if repository returns error for create", func() { It("returns error if repository returns error for create", func() {
fetcher.SetFetchedLogs([]types.Log{test_data.EthVatMoveLog}) fetcher.SetFetchedLogs([]types.Log{test_data.EthVatMoveLog})
repository.SetMissingHeaders([]core.Header{headerOne}) repository.SetMissingHeaders([]core.Header{headerOne})
repository.SetCreateError(fakes.FakeError) repository.SetCreateError(fakes.FakeError)
transformer := vat_move.VatMoveTransformer{
Config: config,
Fetcher: &fetcher,
Converter: &converter,
Repository: &repository,
}
err := transformer.Execute() err := transformer.Execute()