remove pkg/transformers; extract shared files needed to

libraries/shared; work on automated db migration management
This commit is contained in:
Ian Norden
2019-02-24 21:38:47 -06:00
parent 55fa9b8364
commit decc2a3caf
545 changed files with 431 additions and 15922 deletions
+3 -2
View File
@@ -26,11 +26,12 @@ import (
)
type Config struct {
Initializers map[string]string // Map of import aliases to transformer paths
Initializers map[string]string // Map of import aliases to transformer initializer paths
Dependencies map[string]string // Map of vendor dep names to their repositories
Migrations map[string]string // Map of migration names to their paths within the vendored deps
Migrations map[string]string // Map of vendor dep names to relative path from repository to db migrations
FilePath string
FileName string
Save bool
}
func (c *Config) GetPluginPaths() (string, string, error) {
+83 -104
View File
@@ -24,6 +24,7 @@ import (
"os/exec"
"path/filepath"
"strconv"
"strings"
. "github.com/dave/jennifer/jen"
@@ -50,14 +51,14 @@ func NewGenerator(gc Config, dbc config.Database) *generator {
}
func (g *generator) GenerateExporterPlugin() error {
if g.GenConfig == nil {
return errors.New("generator needs a config file")
}
if g.GenConfig.FilePath == "" {
return errors.New("generator is missing file path")
}
if len(g.GenConfig.Initializers) < 1 {
return errors.New("generator needs to be configured with imports")
return errors.New("generator needs to be configured with TransformerInitializer import paths")
}
if len(g.GenConfig.Dependencies) < 1 {
return errors.New("generator needs to be configured with root repository path(s)")
}
if len(g.GenConfig.Migrations) < 1 {
fmt.Fprintf(os.Stderr, "warning: no db migration paths have been provided\r\n")
}
// Get plugin file paths
@@ -66,14 +67,8 @@ func (g *generator) GenerateExporterPlugin() error {
return err
}
// Clear .go and .so files of the same name if they exist (overwrite)
err = utils.ClearFiles(goFile, soFile)
if err != nil {
return err
}
// Generate Exporter code
err = g.generateCode(goFile)
err = g.generateCode(goFile, soFile)
if err != nil {
return err
}
@@ -83,24 +78,32 @@ func (g *generator) GenerateExporterPlugin() error {
if err != nil {
return err
}
defer g.cleanUp() // Clear these up when we are done building our plugin
// Clear tmp files and directories when we exit
defer g.cleanUp(goFile)
// Build the .go file into a .so plugin
err = exec.Command("go", "build", "-buildmode=plugin", "-o", soFile, goFile).Run()
if err != nil {
return err
return errors.New(fmt.Sprintf("unable to build .so file: %s", err.Error()))
}
// Run migrations only after successfully building .so file
return g.runMigrations()
}
// Generates the plugin code
func (g *generator) generateCode(goFile string) error {
func (g *generator) generateCode(goFile, soFile string) error {
// Clear .go and .so files of the same name if they exist
err := utils.ClearFiles(goFile, soFile)
if err != nil {
return err
}
// Begin code generation
f := NewFile("main")
f.HeaderComment("This exporter is generated to export the configured transformer initializers")
// Import TransformerInitializers
// Import TransformerInitializers specified in config
f.ImportAlias("github.com/vulcanize/vulcanizedb/libraries/shared/transformer", "interface")
for alias, imp := range g.GenConfig.Initializers {
f.ImportAlias(imp, alias)
@@ -112,12 +115,10 @@ func (g *generator) generateCode(goFile string) error {
importedInitializers = append(importedInitializers, Qual(path, "TransformerInitializer"))
}
// Create Exporter variable with method to export a set of the configured TransformerInitializers
// Create Exporter variable with method to export the set of the imported TransformerInitializers
f.Type().Id("exporter").String()
f.Var().Id("Exporter").Id("exporter")
f.Func().Params(
Id("e").Id("exporter"),
).Id("Export").Params().Index().Qual(
f.Func().Params(Id("e").Id("exporter")).Id("Export").Params().Index().Qual(
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer",
"TransformerInitializer").Block(
Return(Index().Qual(
@@ -128,6 +129,49 @@ func (g *generator) generateCode(goFile string) error {
return f.Save(goFile)
}
// Sets up temporary vendor libs and migration directories
func (g *generator) setupTempDirs() error {
// TODO: Less hacky way of handling plugin build deps
dirPath, err := utils.CleanPath("$GOPATH/src/github.com/vulcanize/vulcanizedb/")
if err != nil {
return err
}
vendorPath := filepath.Join(dirPath, "vendor")
// Keep track of where we are writing transformer vendor libs, so that we can remove them afterwards
g.tmpVenDirs = make([]string, 0, len(g.GenConfig.Dependencies))
// Import transformer dependencies so that we build our plugin
for name, importPath := range g.GenConfig.Dependencies {
index := strings.Index(importPath, "/")
gitPath := importPath[:index] + ":" + importPath[index+1:]
importURL := "git@" + gitPath + ".git"
depPath := filepath.Join(vendorPath, importPath)
err = exec.Command("git", "clone", importURL, depPath).Run()
if err != nil {
return errors.New(fmt.Sprintf("unable to clone %s transformer dependency: %s", name, err.Error()))
}
err := os.RemoveAll(filepath.Join(depPath, "vendor/"))
if err != nil {
return err
}
g.tmpVenDirs = append(g.tmpVenDirs, depPath)
}
// Initialize temp directory for transformer migrations
g.tmpMigDir, err = utils.CleanPath("$GOPATH/src/github.com/vulcanize/vulcanizedb/db/plugin_migrations")
if err != nil {
return err
}
err = os.RemoveAll(g.tmpMigDir)
if err != nil {
return errors.New(fmt.Sprintf("unable to remove file found at %s where tmp directory needs to be written", g.tmpMigDir))
}
return os.Mkdir(g.tmpMigDir, os.FileMode(0777))
}
func (g *generator) runMigrations() error {
// Get paths to db migrations
paths, err := g.GenConfig.GetMigrationsPaths()
@@ -149,78 +193,8 @@ func (g *generator) runMigrations() error {
}
// Run the copied migrations
location := "file://" + g.tmpMigDir
pgStr := fmt.Sprintf("postgres://%s:%d/%s?sslmode=disable up", g.DBConfig.Hostname, g.DBConfig.Port, g.DBConfig.Name)
return exec.Command("migrate", "-source", location, pgStr).Run()
}
// Sets up temporary vendor libs and migration directories
func (g *generator) setupTempDirs() error {
// TODO: Less hacky way of handling plugin build deps
dirPath, err := utils.CleanPath("$GOPATH/src/github.com/vulcanize/vulcanizedb/")
if err != nil {
return err
}
vendorPath := filepath.Join(dirPath, "vendor/")
/*
// Keep track of where we are writing transformer vendor libs, so that we can remove them afterwards
g.tmpVenDirs = make([]string, 0, len(g.GenConfig.Dependencies))
// Import transformer dependencies so that we build our plugin
for _, importPath := range g.GenConfig.Dependencies {
importURL := "https://" + importPath + ".git"
depPath := filepath.Join(vendorPath, importPath)
err = exec.Command("git", "clone", importURL, depPath).Run()
if err != nil {
return err
}
err := os.RemoveAll(filepath.Join(depPath, "vendor/"))
if err != nil {
return err
}
g.tmpVenDirs = append(g.tmpVenDirs, depPath)
}
*/
// Keep track of where we are writing transformer vendor libs, so that we can remove them afterwards
g.tmpVenDirs = make([]string, 0, len(g.GenConfig.Dependencies))
for _, importPath := range g.GenConfig.Dependencies {
depPath := filepath.Join(vendorPath, importPath)
g.tmpVenDirs = append(g.tmpVenDirs, depPath)
}
// Dep ensure to make sure vendor pkgs are in place for building the plugin
err = exec.Command("dep", "ensure").Run()
if err != nil {
return errors.New("failed to vendor transformer packages required to build plugin")
}
// Git checkout our head-state vendor libraries
// This is necessary because we currently need to manual edit our vendored
// go-ethereum abi library to allow for unpacking in empty interfaces and maps
// This can be removed once the PRs against geth merged
err = exec.Command("git", "checkout", dirPath).Run()
if err != nil {
return errors.New("failed to checkout vendored go-ethereum lib")
}
// Initialize temp directory for transformer migrations
g.tmpMigDir, err = utils.CleanPath("$GOPATH/src/github.com/vulcanize/vulcanizedb/db/plugin_migrations")
if err != nil {
return err
}
stat, err := os.Stat(g.tmpMigDir)
if err == nil {
if !stat.IsDir() {
return errors.New(fmt.Sprintf("file %s found where directory is expected", stat.Name()))
}
} else if os.IsNotExist(err) {
os.Mkdir(g.tmpMigDir, os.FileMode(0777))
} else {
return err
}
return nil
pgStr := fmt.Sprintf("postgres://%s:%d/%s?sslmode=disable", g.DBConfig.Hostname, g.DBConfig.Port, g.DBConfig.Name)
return exec.Command("migrate", "-path", g.tmpMigDir, "-database", pgStr, "up").Run()
}
func (g *generator) createMigrationCopies(paths []string) error {
@@ -230,21 +204,19 @@ func (g *generator) createMigrationCopies(paths []string) error {
return err
}
for _, file := range dir {
if file.IsDir() || len(file.Name()) < 15 { // (10 digit unix time stamp + x + .sql) is bare minimum
if file.IsDir() || len(file.Name()) < 15 || filepath.Ext(file.Name()) != ".sql" { // (10 digit unix time stamp + x + .sql) is bare minimum
continue
}
_, err := strconv.Atoi(file.Name()[:10])
if err != nil {
fmt.Fprintf(os.Stderr, "migration file name %s does not posses 10 digit timestamp prefix", file.Name())
fmt.Fprintf(os.Stderr, "migration file name %s does not posses 10 digit timestamp prefix\r\n", file.Name())
continue
}
if filepath.Ext(file.Name()) == "sql" {
src := filepath.Join(path, file.Name())
dst := filepath.Join(g.tmpMigDir, "1"+file.Name())
err = utils.CopyFile(src, dst)
if err != nil {
return err
}
src := filepath.Join(path, file.Name())
dst := filepath.Join(g.tmpMigDir, "1"+file.Name())
err = utils.CopyFile(src, dst)
if err != nil {
return err
}
}
}
@@ -252,7 +224,14 @@ func (g *generator) createMigrationCopies(paths []string) error {
return nil
}
func (g *generator) cleanUp() error {
func (g *generator) cleanUp(goFile string) error {
if !g.GenConfig.Save {
err := utils.ClearFiles(goFile)
if err != nil {
return err
}
}
for _, venDir := range g.tmpVenDirs {
err := os.RemoveAll(venDir)
if err != nil {
+67 -141
View File
@@ -31,20 +31,10 @@ import (
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/bite"
"github.com/vulcanize/vulcanizedb/utils"
)
var localConfig = autogen.Config{
Initializers: map[string]string{
"bite": "github.com/vulcanize/vulcanizedb/pkg/autogen/test_helpers/bite",
"deal": "github.com/vulcanize/vulcanizedb/pkg/autogen/test_helpers/deal",
},
FileName: "localTestTransformerSet",
FilePath: "$GOPATH/src/github.com/vulcanize/vulcanizedb/pkg/autogen/test_helpers/test/",
}
var externalConfig = autogen.Config{
var genConfig = autogen.Config{
Initializers: map[string]string{
"bite": "github.com/vulcanize/mcd_transformers/transformers/bite",
"deal": "github.com/vulcanize/mcd_transformers/transformers/deal",
@@ -53,7 +43,8 @@ var externalConfig = autogen.Config{
"mcd_transformers": "github.com/vulcanize/mcd_transformers",
},
FileName: "externalTestTransformerSet",
FilePath: "$GOPATH/src/github.com/vulcanize/vulcanizedb/pkg/autogen/test_helpers/test/",
FilePath: "$GOPATH/src/github.com/vulcanize/vulcanizedb/pkg/autogen/test_helpers/test",
Save: false,
}
type Exporter interface {
@@ -71,147 +62,82 @@ var _ = Describe("Generator test", func() {
viper.SetConfigName("compose")
viper.AddConfigPath("$GOPATH/src/github.com/vulcanize/vulcanizedb/environments/")
Describe("Using local config", func() {
BeforeEach(func() {
goPath, soPath, err = localConfig.GetPluginPaths()
Expect(err).ToNot(HaveOccurred())
g = autogen.NewGenerator(localConfig, config.Database{})
err = g.GenerateExporterPlugin()
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
err := utils.ClearFiles(goPath, soPath)
Expect(err).ToNot(HaveOccurred())
})
Describe("GenerateTransformerPlugin", func() {
It("It bundles the specified transformer initializers into a Exporter object and creates .so", func() {
plug, err := plugin.Open(soPath)
Expect(err).ToNot(HaveOccurred())
symExporter, err := plug.Lookup("Exporter")
Expect(err).ToNot(HaveOccurred())
exporter, ok := symExporter.(Exporter)
Expect(ok).To(Equal(true))
initializers := exporter.Export()
Expect(len(initializers)).To(Equal(2))
})
It("Loads our generated Exporter and uses it to import an arbitrary set of TransformerInitializers that we can execute over", func() {
db, bc = test_helpers.SetupDBandBC()
defer test_helpers.TearDown(db)
hr = repositories.NewHeaderRepository(db)
header1, err := bc.GetHeaderByNumber(9377319)
Expect(err).ToNot(HaveOccurred())
headerID, err = hr.CreateOrUpdateHeader(header1)
Expect(err).ToNot(HaveOccurred())
plug, err := plugin.Open(soPath)
Expect(err).ToNot(HaveOccurred())
symExporter, err := plug.Lookup("Exporter")
Expect(err).ToNot(HaveOccurred())
exporter, ok := symExporter.(Exporter)
Expect(ok).To(Equal(true))
initializers := exporter.Export()
w := watcher.NewWatcher(db, bc)
w.AddTransformers(initializers)
err = w.Execute()
Expect(err).ToNot(HaveOccurred())
type model struct {
bite.BiteModel
Id int64 `db:"id"`
HeaderId int64 `db:"header_id"`
}
returned := model{}
err = db.Get(&returned, `SELECT * FROM maker.bite WHERE header_id = $1`, headerID)
Expect(err).ToNot(HaveOccurred())
Expect(returned.Ilk).To(Equal("ETH"))
Expect(returned.Urn).To(Equal("0x0000d8b4147eDa80Fec7122AE16DA2479Cbd7ffB"))
Expect(returned.Ink).To(Equal("80000000000000000000"))
Expect(returned.Art).To(Equal("11000000000000000000000"))
Expect(returned.IArt).To(Equal("12496609999999999999992"))
Expect(returned.Tab).To(Equal("11000000000000000000000"))
Expect(returned.NFlip).To(Equal("7"))
Expect(returned.TransactionIndex).To(Equal(uint(1)))
Expect(returned.LogIndex).To(Equal(uint(4)))
})
})
BeforeEach(func() {
goPath, soPath, err = genConfig.GetPluginPaths()
Expect(err).ToNot(HaveOccurred())
g = autogen.NewGenerator(genConfig, config.Database{})
err = g.GenerateExporterPlugin()
Expect(err).ToNot(HaveOccurred())
})
Describe("Using external config", func() {
BeforeEach(func() {
goPath, soPath, err = externalConfig.GetPluginPaths()
AfterEach(func() {
err := utils.ClearFiles(goPath, soPath)
Expect(err).ToNot(HaveOccurred())
})
Describe("GenerateTransformerPlugin", func() {
It("It bundles the specified transformer initializers into a Exporter object and creates .so", func() {
plug, err := plugin.Open(soPath)
Expect(err).ToNot(HaveOccurred())
g = autogen.NewGenerator(externalConfig, config.Database{})
err = g.GenerateExporterPlugin()
symExporter, err := plug.Lookup("Exporter")
Expect(err).ToNot(HaveOccurred())
exporter, ok := symExporter.(Exporter)
Expect(ok).To(Equal(true))
initializers := exporter.Export()
Expect(len(initializers)).To(Equal(2))
})
AfterEach(func() {
err := utils.ClearFiles(goPath, soPath)
It("Loads our generated Exporter and uses it to import an arbitrary set of TransformerInitializers that we can execute over", func() {
db, bc = test_helpers.SetupDBandBC()
defer test_helpers.TearDown(db)
hr = repositories.NewHeaderRepository(db)
header1, err := bc.GetHeaderByNumber(9377319)
Expect(err).ToNot(HaveOccurred())
headerID, err = hr.CreateOrUpdateHeader(header1)
Expect(err).ToNot(HaveOccurred())
})
Describe("GenerateTransformerPlugin", func() {
It("It bundles the specified transformer initializers into a Exporter object and creates .so", func() {
plug, err := plugin.Open(soPath)
Expect(err).ToNot(HaveOccurred())
symExporter, err := plug.Lookup("Exporter")
Expect(err).ToNot(HaveOccurred())
exporter, ok := symExporter.(Exporter)
Expect(ok).To(Equal(true))
initializers := exporter.Export()
Expect(len(initializers)).To(Equal(2))
})
plug, err := plugin.Open(soPath)
Expect(err).ToNot(HaveOccurred())
symExporter, err := plug.Lookup("Exporter")
Expect(err).ToNot(HaveOccurred())
exporter, ok := symExporter.(Exporter)
Expect(ok).To(Equal(true))
initializers := exporter.Export()
It("Loads our generated Exporter and uses it to import an arbitrary set of TransformerInitializers that we can execute over", func() {
db, bc = test_helpers.SetupDBandBC()
defer test_helpers.TearDown(db)
w := watcher.NewWatcher(db, bc)
w.AddTransformers(initializers)
err = w.Execute()
Expect(err).ToNot(HaveOccurred())
hr = repositories.NewHeaderRepository(db)
header1, err := bc.GetHeaderByNumber(9377319)
Expect(err).ToNot(HaveOccurred())
headerID, err = hr.CreateOrUpdateHeader(header1)
Expect(err).ToNot(HaveOccurred())
type model struct {
Ilk string
Urn string
Ink string
Art string
IArt string
Tab string
NFlip string
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
Id int64 `db:"id"`
HeaderId int64 `db:"header_id"`
}
plug, err := plugin.Open(soPath)
Expect(err).ToNot(HaveOccurred())
symExporter, err := plug.Lookup("Exporter")
Expect(err).ToNot(HaveOccurred())
exporter, ok := symExporter.(Exporter)
Expect(ok).To(Equal(true))
initializers := exporter.Export()
returned := model{}
w := watcher.NewWatcher(db, bc)
w.AddTransformers(initializers)
err = w.Execute()
Expect(err).ToNot(HaveOccurred())
type model struct {
bite.BiteModel
Id int64 `db:"id"`
HeaderId int64 `db:"header_id"`
}
returned := model{}
err = db.Get(&returned, `SELECT * FROM maker.bite WHERE header_id = $1`, headerID)
Expect(err).ToNot(HaveOccurred())
Expect(returned.Ilk).To(Equal("ETH"))
Expect(returned.Urn).To(Equal("0x0000d8b4147eDa80Fec7122AE16DA2479Cbd7ffB"))
Expect(returned.Ink).To(Equal("80000000000000000000"))
Expect(returned.Art).To(Equal("11000000000000000000000"))
Expect(returned.IArt).To(Equal("12496609999999999999992"))
Expect(returned.Tab).To(Equal("11000000000000000000000"))
Expect(returned.NFlip).To(Equal("7"))
Expect(returned.TransactionIndex).To(Equal(uint(1)))
Expect(returned.LogIndex).To(Equal(uint(4)))
})
err = db.Get(&returned, `SELECT * FROM maker.bite WHERE header_id = $1`, headerID)
Expect(err).ToNot(HaveOccurred())
Expect(returned.Ilk).To(Equal("ETH"))
Expect(returned.Urn).To(Equal("0x0000d8b4147eDa80Fec7122AE16DA2479Cbd7ffB"))
Expect(returned.Ink).To(Equal("80000000000000000000"))
Expect(returned.Art).To(Equal("11000000000000000000000"))
Expect(returned.IArt).To(Equal("12496609999999999999992"))
Expect(returned.Tab).To(Equal("11000000000000000000000"))
Expect(returned.NFlip).To(Equal("7"))
Expect(returned.TransactionIndex).To(Equal(uint(1)))
Expect(returned.LogIndex).To(Equal(uint(4)))
})
})
})
@@ -1,8 +0,0 @@
package bite
import (
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers"
)
var TransformerInitializer transformer.TransformerInitializer = transformers.GetBiteTransformer().NewTransformer
@@ -1,8 +0,0 @@
package deal
import (
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers"
)
var TransformerInitializer transformer.TransformerInitializer = transformers.GetDealTransformer().NewLogNoteTransformer
+1 -1
View File
@@ -1,3 +1,3 @@
### Test
This empty directory is for holding the output code generated, and then deleted, during the generator_tests
This empty directory is for holding the temporary .so and .go files generated during the generator_tests
+1 -1
View File
@@ -24,8 +24,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
var (
-129
View File
@@ -1,129 +0,0 @@
# Transformers
## Architecture
Transformers fetch logs from Ethereum, convert/decode them into usable data, and then persist them in postgres.
A transformer consists of:
- A fetcher -> Fetches raw logs from the blockchain and encodes them as go datatypes
- A converter -> Converts this raw data into a human friendly representation suitable for consumption in the API
- A repository -> Abstracts the database
For Maker, vulcanize will be run in `lightSync` mode, so it will store all headers, and then fetchers pull relevant logs by making RPC calls.
## Event Types
For Maker there are two main types of log events that we're tracking:
1. Custom events that are defined in the contract solidity code.
1. `LogNote` events which utilize the [DSNote library](https://github.com/dapphub/ds-note).
1. `Note` events in the `Vat`
The transformer process for each of these different log types is the same, except for the converting process, as denoted below.
## Creating a Transformer
1. Pull an example event (from kovan / ganache etc.)
1. Add event & method sig, contract address, `checked_headers` column name, and label to relevant files in [`constants`](./shared/constants)
1. Write a test for the event sig in [`event_signature_generator_test.go`](./shared/event_signature_generator_test.go)
1. Create DB table (using [`create_migration`](../../scripts/create_migration))
1. Create columns in `checked_headers` in the _same_ migration
1. Add a line to clean the new table `CleanTestDB` (in [`test_config.go`](../../test_config/test_config.go))
1. Define `model.go`
1. Create test event in [`test_data`](./test_data)
1. Write converter + converter tests
1. Write repository + repository tests
1. Create converter + repository mocks
1. Create an config object [`shared.TransformerConfig`](./shared/transformer.go) in `config.go`
1. Wire up transformer in [`transformers.go`](./transformers.go), remembering to add it to `TransformerInitializers()`
1. Wire up transformer in [`continuousLogSync.go`](../../cmd/continuousLogSync.go)
1. Manually trigger an event and check that it gets persisted to postgres
1. Create an integration test for the shiny new transformer in [`integration_tests`](./integration_tests)
**Fetching Logs**
1. Generate an example raw log event, by either:
- Pulling the log directly from the Kovan deployment ([address.go](https://github.com/8thlight/maker-vulcanizedb/blob/master/pkg/transformers/shared/constants/address.go)).
- Deploying the contract to a local chain and emiting the event manually.
1. Fetch the logs from the chain based on the example event's topic zero:
- The topic zero is based on the keccak-256 hash of the log event's method signature. These are located in [`pkg/transformers/shared/constants/signature.go`](./shared/constants/signature.go).
- Fetching is done in batch from the [`watcher`](../../libraries/shared/watcher.go).
- The logs are then chunked up by the [`chunker`](./shared/log_chunker.go) before being delegated to each transformer.
**Coverting logs**
- **Converting most custom events** (such as FlopKick)
1. Convert the raw log into a Go struct.
- We've been using [go-ethereum's abigen tool](https://github.com/ethereum/go-ethereum/tree/master/cmd/abigen) to get the contract's ABI, and a Go struct that represents the event log. We will unpack the raw logs into this struct.
- To use abigen: `abigen --sol flip.sol --pkg flip --out {/path/to/output_file}`
- sol: this is the path to the solidity contract
- pkg: a package name for the generated Go code
- out: the file path for the generated Go code (optional)
- the output for `flop.sol` will include the FlopperAbi and the FlopperKick struct:
```go
type FlopperKick struct {
Id *big.Int
Lot *big.Int
Bid *big.Int
Gal common.Address
End *big.Int
Raw types.Log
}
```
- Using go-ethereum's `contract.UnpackLog` method we can unpack the raw log into the FlopperKick struct (which we're referring to as the `entity`).
- See the `ToEntity` method in [`pkg/transformers/flop_kick/converter.go`](./flop_kick/converter.go).
1. Convert the entity into a database model. See the `ToModel` method in `pkg/transformers/flop_kick/converter`.
- **Converting Price Feed custom events**
- Price Feed contracts use the [LogNote event](https://github.com/makerdao/medianizer/blob/master/src/medianizer.sol#L23)
- The LogNote event takes in the value of the price feed as it's sole argument, and does not index it. This means that this value can be taken directly from the log's data, and then properly converted using the `price_feeds.Convert` method (located in the model.go file).
- Since this conversion from raw log to model includes less fields than some others, we've chosen to convert it directly to the database model, skipping the `ToEntity` step.
- **Converting LogNote events** (such as tend)
- Since LogNote events are a generic structure, they depend on the method signature of the method that is calling them. For example, the `tend` method is called on the [flip.sol contract](https://github.com/makerdao/dss/blob/master/src/flip.sol#L117), and it's method signature looks like this: `tend(uint,uint,uint)`.
- The first four bytes of the Keccak-256 hashed method signature will be located in `topic[0]` on the log.
- The message sender will be in `topic[1]`.
- The first parameter passed to `tend` becomes `topic[2]`.
- The second parameter passed to `tend` will be `topic[3]`.
- Any additional parameters will be in the log's data field.
- More detail is located in the [DSNote repo](https://github.com/dapphub/ds-note).
**Get all MissingHeaders**
- Headers are inserted into VulcanizeDB as part of the `lightSync` command. Then for each transformer we check each header for matching logs.
- The MissingHeaders method queries the `checked_headers` table to see if the header has been checked for the given log type.
**Persist the log record to VulcanizeDB**
- Each event log has it's own table in the database, as well as it's own column in the `checked_headers` table.
- The `checked_headers` table allows us to keep track of which headers have been checked for a given log type.
- To create a new migration file: `./scripts/create_migration create_flop_kick`
- See `db/migrations/1536942529_create_flop_kick.up.sql`.
- The specific log event tables are all created in the `maker` schema.
- There is a one-many association between `headers` and the log
event tables. This is so that if a header is removed due to a reorg, the associated log event records are also removed.
- To run the migrations: `make migrate HOST=local_host PORT=5432 NAME=vulcanize_private`
- When a new log record is inserted into VulcanizeDB, we also need to make sure to insert a record into the `checked_headers` table for the given log type.
- We have been using the repository pattern (i.e. wrapping all SQL/ORM invocations in isolated namespaces per table) to interact with the database, see the `Create` method in `pkg/transformers/flop_kick/repository.go`.
**MarkHeaderChecked**
- There is a chance that a header does not have a log for the given transformer's log type, and in this instance we also want to record that the header has been "checked" so that we don't continue to query that header over and over.
- In the transformer we'll make sure to insert a row for the header indicating that it has been checked for the log type that the transformer is responsible for.
**Wire each component up in the transformer**
- We use a [`TransformerInitializer`](./shared/transformer.go) struct for each transformer so that we can inject ethRPC and postgresDB connections as well as configuration data (including the contract address, block range, etc.) into the transformer.
- See any of `pkg/transformers/flop_kick/transformer.go`
- All of the transformers are then initialized in `pkg/transformers/transformers.go` with their configuration.
- The transformers can be executed by using the `continuousLogSync` command, which can be configured to run specific transformers or all transformers.
## Useful Documents
[Ethereum Event ABI Specification](https://solidity.readthedocs.io/en/develop/abi-spec.html#events)
-35
View File
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package bite_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
log "github.com/sirupsen/logrus"
"io/ioutil"
)
func TestBite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Bite Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-33
View File
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package bite
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetBiteConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.BiteLabel,
ContractAddresses: []string{constants.CatContractAddress()},
ContractAbi: constants.CatABI(),
Topic: constants.GetBiteSignature(),
StartingBlockNumber: constants.CatDeploymentBlock(),
EndingBlockNumber: -1,
}
}
-94
View File
@@ -1,94 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package bite
import (
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/geth"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type BiteConverter struct{}
func (BiteConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) {
var entities []interface{}
for _, ethLog := range ethLogs {
entity := &BiteEntity{}
address := ethLog.Address
abi, err := geth.ParseAbi(contractAbi)
if err != nil {
return nil, err
}
contract := bind.NewBoundContract(address, abi, nil, nil, nil)
err = contract.UnpackLog(entity, "Bite", ethLog)
if err != nil {
return nil, err
}
entity.Raw = ethLog
entity.LogIndex = ethLog.Index
entity.TransactionIndex = ethLog.TxIndex
entities = append(entities, *entity)
}
return entities, nil
}
func (converter BiteConverter) ToModels(entities []interface{}) ([]interface{}, error) {
var models []interface{}
for _, entity := range entities {
biteEntity, ok := entity.(BiteEntity)
if !ok {
return nil, fmt.Errorf("entity of type %T, not %T", entity, BiteEntity{})
}
ilk := shared.GetHexWithoutPrefix(biteEntity.Ilk[:])
urn := shared.GetHexWithoutPrefix(biteEntity.Urn[:])
ink := biteEntity.Ink
art := biteEntity.Art
iArt := biteEntity.IArt
tab := biteEntity.Tab
flip := biteEntity.Flip
logIdx := biteEntity.LogIndex
txIdx := biteEntity.TransactionIndex
rawLog, err := json.Marshal(biteEntity.Raw)
if err != nil {
return nil, err
}
model := BiteModel{
Ilk: ilk,
Urn: urn,
Ink: shared.BigIntToString(ink),
Art: shared.BigIntToString(art),
IArt: shared.BigIntToString(iArt),
Tab: shared.BigIntToString(tab),
NFlip: shared.BigIntToString(flip),
LogIndex: logIdx,
TransactionIndex: txIdx,
Raw: rawLog,
}
models = append(models, model)
}
return models, nil
}
-91
View File
@@ -1,91 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package bite_test
import (
"encoding/json"
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/bite"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Bite Converter", func() {
var converter = bite.BiteConverter{}
Describe("ToEntity", func() {
It("converts an eth log to a bite entity", func() {
entities, err := converter.ToEntities(test_data.KovanCatABI, []types.Log{test_data.EthBiteLog})
Expect(err).NotTo(HaveOccurred())
Expect(len(entities)).To(Equal(1))
entity := entities[0]
Expect(entity).To(Equal(test_data.BiteEntity))
})
It("returns an error if converting log to entity fails", func() {
_, err := converter.ToEntities("error abi", []types.Log{test_data.EthBiteLog})
Expect(err).To(HaveOccurred())
})
})
Describe("ToModel", func() {
var emptyEntity = bite.BiteEntity{}
It("converts an Entity to a Model", func() {
models, err := converter.ToModels([]interface{}{test_data.BiteEntity})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
model := models[0]
Expect(model).To(Equal(test_data.BiteModel))
})
It("returns an error if the entity type is wrong", func() {
_, err := converter.ToModels([]interface{}{test_data.WrongEntity{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("entity of type test_data.WrongEntity, not bite.BiteEntity"))
})
It("handles nil values", func() {
emptyLog, err := json.Marshal(types.Log{})
Expect(err).NotTo(HaveOccurred())
expectedModel := bite.BiteModel{
Ilk: "0000000000000000000000000000000000000000000000000000000000000000",
Urn: "0000000000000000000000000000000000000000000000000000000000000000",
Ink: "",
Art: "",
IArt: "",
Tab: "",
NFlip: "",
TransactionIndex: 0,
Raw: emptyLog,
}
models, err := converter.ToModels([]interface{}{emptyEntity})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
model := models[0]
Expect(model).To(Equal(expectedModel))
})
})
})
-35
View File
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package bite
import (
"github.com/ethereum/go-ethereum/core/types"
"math/big"
)
type BiteEntity struct {
Ilk [32]byte
Urn [32]byte
Ink *big.Int
Art *big.Int
Tab *big.Int
Flip *big.Int
IArt *big.Int
LogIndex uint
TransactionIndex uint
Raw types.Log
}
-30
View File
@@ -1,30 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package bite
type BiteModel struct {
Ilk string
Urn string
Ink string
Art string
IArt string
Tab string
NFlip string
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
}
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package chop_lump_test
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestChopLump(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "ChopLump Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package chop_lump
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetCatFileChopLumpConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.CatFileChopLumpLabel,
ContractAddresses: []string{constants.CatContractAddress()},
ContractAbi: constants.CatABI(),
Topic: constants.GetCatFileChopLumpSignature(),
StartingBlockNumber: constants.CatDeploymentBlock(),
EndingBlockNumber: -1,
}
}
@@ -1,84 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package chop_lump
import (
"bytes"
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"math/big"
)
var (
chop = "chop"
lump = "lump"
)
type CatFileChopLumpConverter struct{}
func (CatFileChopLumpConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var results []interface{}
for _, ethLog := range ethLogs {
err := verifyLog(ethLog)
if err != nil {
return nil, err
}
ilk := shared.GetHexWithoutPrefix(ethLog.Topics[2].Bytes())
what := string(bytes.Trim(ethLog.Topics[3].Bytes(), "\x00"))
dataBytes := ethLog.Data[len(ethLog.Data)-constants.DataItemLength:]
data := big.NewInt(0).SetBytes(dataBytes).String()
raw, err := json.Marshal(ethLog)
if err != nil {
return nil, err
}
result := CatFileChopLumpModel{
Ilk: ilk,
What: what,
Data: convertData(what, data),
TransactionIndex: ethLog.TxIndex,
LogIndex: ethLog.Index,
Raw: raw,
}
results = append(results, result)
}
return results, nil
}
func convertData(what, data string) string {
var convertedData string
if what == chop {
convertedData = shared.ConvertToRay(data)
} else if what == lump {
convertedData = shared.ConvertToWad(data)
}
return convertedData
}
func verifyLog(log types.Log) error {
if len(log.Topics) < 4 {
return errors.New("log missing topics")
}
if len(log.Data) < constants.DataItemLength {
return errors.New("log missing data")
}
return nil
}
@@ -1,71 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package chop_lump_test
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/cat_file/chop_lump"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Cat file chop lump converter", func() {
var converter chop_lump.CatFileChopLumpConverter
BeforeEach(func() {
converter = chop_lump.CatFileChopLumpConverter{}
})
Context("chop events", func() {
It("converts a chop log to a model", func() {
models, err := converter.ToModels([]types.Log{test_data.EthCatFileChopLog})
Expect(err).NotTo(HaveOccurred())
Expect(models).To(Equal([]interface{}{test_data.CatFileChopModel}))
})
})
Context("lump events", func() {
It("converts a lump log to a model", func() {
models, err := converter.ToModels([]types.Log{test_data.EthCatFileLumpLog})
Expect(err).NotTo(HaveOccurred())
Expect(models).To(Equal([]interface{}{test_data.CatFileLumpModel}))
})
})
It("returns err if log is missing topics", func() {
badLog := types.Log{
Data: []byte{1, 1, 1, 1, 1},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("returns err if log is missing data", func() {
badLog := types.Log{
Topics: []common.Hash{{}, {}, {}, {}},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
})
@@ -1,26 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package chop_lump
type CatFileChopLumpModel struct {
Ilk string
What string
Data string
TransactionIndex uint `db:"tx_idx"`
LogIndex uint `db:"log_idx"`
Raw []byte `db:"raw_log"`
}
-33
View File
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetCatFileFlipConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.CatFileFlipLabel,
ContractAddresses: []string{constants.CatContractAddress()},
ContractAbi: constants.CatABI(),
Topic: constants.GetCatFileFlipSignature(),
StartingBlockNumber: constants.CatDeploymentBlock(),
EndingBlockNumber: -1,
}
}
@@ -1,68 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip
import (
"bytes"
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type CatFileFlipConverter struct{}
func (CatFileFlipConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var results []interface{}
for _, ethLog := range ethLogs {
err := verifyLog(ethLog)
if err != nil {
return nil, err
}
ilk := shared.GetHexWithoutPrefix(ethLog.Topics[2].Bytes())
what := string(bytes.Trim(ethLog.Topics[3].Bytes(), "\x00"))
flipBytes := ethLog.Data[len(ethLog.Data)-constants.DataItemLength:]
flip := common.BytesToAddress(flipBytes).String()
raw, err := json.Marshal(ethLog)
if err != nil {
return nil, err
}
result := CatFileFlipModel{
Ilk: ilk,
What: what,
Flip: flip,
TransactionIndex: ethLog.TxIndex,
LogIndex: ethLog.Index,
Raw: raw,
}
results = append(results, result)
}
return results, nil
}
func verifyLog(log types.Log) error {
if len(log.Topics) < 4 {
return errors.New("log missing topics")
}
if len(log.Data) < constants.DataItemLength {
return errors.New("log missing data")
}
return nil
}
@@ -1,60 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_test
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/cat_file/flip"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Cat file flip converter", func() {
var converter flip.CatFileFlipConverter
BeforeEach(func() {
converter = flip.CatFileFlipConverter{}
})
It("returns err if log is missing topics", func() {
badLog := types.Log{
Data: []byte{1, 1, 1, 1, 1},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("returns err if log is missing data", func() {
badLog := types.Log{
Topics: []common.Hash{{}, {}, {}, {}},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("converts a log to an model", func() {
models, err := converter.ToModels([]types.Log{test_data.EthCatFileFlipLog})
Expect(err).NotTo(HaveOccurred())
Expect(models).To(Equal([]interface{}{test_data.CatFileFlipModel}))
})
})
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_test
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestFlip(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Flip Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-26
View File
@@ -1,26 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip
type CatFileFlipModel struct {
Ilk string
What string
Flip string
TransactionIndex uint `db:"tx_idx"`
LogIndex uint `db:"log_idx"`
Raw []byte `db:"raw_log"`
}
@@ -1,89 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type CatFileFlipRepository struct {
db *postgres.DB
}
func (repository CatFileFlipRepository) Create(headerID int64, models []interface{}) error {
tx, dBaseErr := repository.db.Begin()
if dBaseErr != nil {
return dBaseErr
}
for _, model := range models {
flip, ok := model.(CatFileFlipModel)
if !ok {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return fmt.Errorf("model of type %T, not %T", model, CatFileFlipModel{})
}
_, execErr := repository.db.Exec(
`INSERT into maker.cat_file_flip (header_id, ilk, what, flip, tx_idx, log_idx, raw_log)
VALUES($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (header_id, tx_idx, log_idx) DO UPDATE SET ilk = $2, what = $3, flip = $4, raw_log = $7;`,
headerID, flip.Ilk, flip.What, flip.Flip, flip.TransactionIndex, flip.LogIndex, flip.Raw,
)
if execErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return execErr
}
}
checkHeaderErr := shared.MarkHeaderCheckedInTransaction(headerID, tx, constants.CatFileFlipChecked)
if checkHeaderErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return checkHeaderErr
}
return tx.Commit()
}
func (repository CatFileFlipRepository) MarkHeaderChecked(headerID int64) error {
return shared.MarkHeaderChecked(headerID, repository.db, constants.CatFileFlipChecked)
}
func (repository CatFileFlipRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.CatFileFlipChecked)
}
func (repository CatFileFlipRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.CatFileFlipChecked)
}
func (repository *CatFileFlipRepository) SetDB(db *postgres.DB) {
repository.db = db
}
@@ -1,88 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/cat_file/flip"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/shared_behaviors"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("Cat file flip repository", func() {
var (
catFileFlipRepository flip.CatFileFlipRepository
db *postgres.DB
headerRepository datastore.HeaderRepository
)
BeforeEach(func() {
db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db)
catFileFlipRepository = flip.CatFileFlipRepository{}
catFileFlipRepository.SetDB(db)
})
Describe("Create", func() {
catFileFlipWithDifferentIdx := test_data.CatFileFlipModel
catFileFlipWithDifferentIdx.LogIndex++
inputs := shared_behaviors.CreateBehaviorInputs{
CheckedHeaderColumnName: constants.CatFileFlipChecked,
LogEventTableName: "maker.cat_file_flip",
TestModel: test_data.CatFileFlipModel,
ModelWithDifferentLogIdx: catFileFlipWithDifferentIdx,
Repository: &catFileFlipRepository,
}
shared_behaviors.SharedRepositoryCreateBehaviors(&inputs)
It("adds a cat file flip event", func() {
headerID, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred())
err = catFileFlipRepository.Create(headerID, []interface{}{test_data.CatFileFlipModel})
Expect(err).NotTo(HaveOccurred())
var dbResult flip.CatFileFlipModel
err = db.Get(&dbResult, `SELECT ilk, what, flip, tx_idx, log_idx, raw_log FROM maker.cat_file_flip WHERE header_id = $1`, headerID)
Expect(err).NotTo(HaveOccurred())
Expect(dbResult.Ilk).To(Equal(test_data.CatFileFlipModel.Ilk))
Expect(dbResult.What).To(Equal(test_data.CatFileFlipModel.What))
Expect(dbResult.Flip).To(Equal(test_data.CatFileFlipModel.Flip))
Expect(dbResult.TransactionIndex).To(Equal(test_data.CatFileFlipModel.TransactionIndex))
Expect(dbResult.LogIndex).To(Equal(test_data.CatFileFlipModel.LogIndex))
Expect(dbResult.Raw).To(MatchJSON(test_data.CatFileFlipModel.Raw))
})
})
Describe("MarkHeaderChecked", func() {
inputs := shared_behaviors.MarkedHeaderCheckedBehaviorInputs{
CheckedHeaderColumnName: constants.CatFileFlipChecked,
Repository: &catFileFlipRepository,
}
shared_behaviors.SharedRepositoryMarkHeaderCheckedBehaviors(&inputs)
})
})
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pit_vow
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetCatFilePitVowConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.CatFilePitVowLabel,
ContractAddresses: []string{constants.CatContractAddress()},
ContractAbi: constants.CatABI(),
Topic: constants.GetCatFilePitVowSignature(),
StartingBlockNumber: constants.CatDeploymentBlock(),
EndingBlockNumber: -1,
}
}
@@ -1,66 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pit_vow
import (
"bytes"
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type CatFilePitVowConverter struct{}
func (CatFilePitVowConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var results []interface{}
for _, ethLog := range ethLogs {
err := verifyLog(ethLog)
if err != nil {
return nil, err
}
what := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00"))
data := common.BytesToAddress(ethLog.Topics[3].Bytes()).String()
raw, err := json.Marshal(ethLog)
if err != nil {
return nil, err
}
result := CatFilePitVowModel{
What: what,
Data: data,
TransactionIndex: ethLog.TxIndex,
LogIndex: ethLog.Index,
Raw: raw,
}
results = append(results, result)
}
return results, nil
}
func verifyLog(log types.Log) error {
if len(log.Topics) < 4 {
return errors.New("log missing topics")
}
if len(log.Data) < constants.DataItemLength {
return errors.New("log missing data")
}
return nil
}
@@ -1,60 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pit_vow_test
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/cat_file/pit_vow"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Cat file pit vow converter", func() {
var converter pit_vow.CatFilePitVowConverter
BeforeEach(func() {
converter = pit_vow.CatFilePitVowConverter{}
})
It("returns err if log is missing topics", func() {
badLog := types.Log{
Data: []byte{1, 1, 1, 1, 1},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("returns err if log is missing data", func() {
badLog := types.Log{
Topics: []common.Hash{{}, {}, {}, {}},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("converts a log to an model", func() {
models, err := converter.ToModels([]types.Log{test_data.EthCatFilePitVowLog})
Expect(err).NotTo(HaveOccurred())
Expect(models).To(Equal([]interface{}{test_data.CatFilePitVowModel}))
})
})
@@ -1,25 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pit_vow
type CatFilePitVowModel struct {
What string
Data string
TransactionIndex uint `db:"tx_idx"`
LogIndex uint `db:"log_idx"`
Raw []byte `db:"raw_log"`
}
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pit_vow_test
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestPitVow(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "PitVow Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
@@ -1,89 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pit_vow
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type CatFilePitVowRepository struct {
db *postgres.DB
}
func (repository CatFilePitVowRepository) Create(headerID int64, models []interface{}) error {
tx, dBaseErr := repository.db.Begin()
if dBaseErr != nil {
return dBaseErr
}
for _, model := range models {
vow, ok := model.(CatFilePitVowModel)
if !ok {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return fmt.Errorf("model of type %T, not %T", model, CatFilePitVowModel{})
}
_, execErr := repository.db.Exec(
`INSERT into maker.cat_file_pit_vow (header_id, what, data, tx_idx, log_idx, raw_log)
VALUES($1, $2, $3, $4, $5, $6)
ON CONFLICT (header_id, tx_idx, log_idx) DO UPDATE SET what = $2, data = $3, raw_log = $6;`,
headerID, vow.What, vow.Data, vow.TransactionIndex, vow.LogIndex, vow.Raw,
)
if execErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return execErr
}
}
checkHeaderErr := shared.MarkHeaderCheckedInTransaction(headerID, tx, constants.CatFilePitVowChecked)
if checkHeaderErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return checkHeaderErr
}
return tx.Commit()
}
func (repository CatFilePitVowRepository) MarkHeaderChecked(headerID int64) error {
return shared.MarkHeaderChecked(headerID, repository.db, constants.CatFilePitVowChecked)
}
func (repository CatFilePitVowRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.CatFilePitVowChecked)
}
func (repository CatFilePitVowRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.CatFilePitVowChecked)
}
func (repository *CatFilePitVowRepository) SetDB(db *postgres.DB) {
repository.db = db
}
@@ -1,86 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package pit_vow_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/cat_file/pit_vow"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/shared_behaviors"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("Cat file pit vow repository", func() {
var (
catFilePitVowRepository pit_vow.CatFilePitVowRepository
db *postgres.DB
headerRepository datastore.HeaderRepository
)
BeforeEach(func() {
db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db)
catFilePitVowRepository = pit_vow.CatFilePitVowRepository{}
catFilePitVowRepository.SetDB(db)
})
Describe("Create", func() {
modelWithDifferentLogIdx := test_data.CatFilePitVowModel
modelWithDifferentLogIdx.LogIndex++
inputs := shared_behaviors.CreateBehaviorInputs{
CheckedHeaderColumnName: constants.CatFilePitVowChecked,
LogEventTableName: "maker.cat_file_pit_vow",
TestModel: test_data.CatFilePitVowModel,
ModelWithDifferentLogIdx: modelWithDifferentLogIdx,
Repository: &catFilePitVowRepository,
}
shared_behaviors.SharedRepositoryCreateBehaviors(&inputs)
It("adds a cat file pit vow event", func() {
headerID, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred())
err = catFilePitVowRepository.Create(headerID, []interface{}{test_data.CatFilePitVowModel})
Expect(err).NotTo(HaveOccurred())
var dbResult pit_vow.CatFilePitVowModel
err = db.Get(&dbResult, `SELECT what, data, tx_idx, log_idx, raw_log FROM maker.cat_file_pit_vow WHERE header_id = $1`, headerID)
Expect(err).NotTo(HaveOccurred())
Expect(dbResult.What).To(Equal(test_data.CatFilePitVowModel.What))
Expect(dbResult.Data).To(Equal(test_data.CatFilePitVowModel.Data))
Expect(dbResult.TransactionIndex).To(Equal(test_data.CatFilePitVowModel.TransactionIndex))
Expect(dbResult.LogIndex).To(Equal(test_data.CatFilePitVowModel.LogIndex))
Expect(dbResult.Raw).To(MatchJSON(test_data.CatFilePitVowModel.Raw))
})
})
Describe("MarkHeaderChecked", func() {
inputs := shared_behaviors.MarkedHeaderCheckedBehaviorInputs{
CheckedHeaderColumnName: constants.CatFilePitVowChecked,
Repository: &catFilePitVowRepository,
}
shared_behaviors.SharedRepositoryMarkHeaderCheckedBehaviors(&inputs)
})
})
-35
View File
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package deal
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetDealConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.DealLabel,
ContractAddresses: []string{constants.FlapperContractAddress(), constants.FlipperContractAddress(), constants.FlopperContractAddress()},
ContractAbi: constants.FlipperABI(),
Topic: constants.GetDealSignature(),
StartingBlockNumber: shared.MinInt64([]int64{
constants.FlapperDeploymentBlock(), constants.FlipperDeploymentBlock(), constants.FlopperDeploymentBlock()}),
EndingBlockNumber: -1,
}
}
-59
View File
@@ -1,59 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package deal
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/core/types"
)
type DealConverter struct{}
func (DealConverter) ToModels(ethLogs []types.Log) (result []interface{}, err error) {
for _, log := range ethLogs {
err := validateLog(log)
if err != nil {
return nil, err
}
bidId := log.Topics[2].Big()
raw, err := json.Marshal(log)
if err != nil {
return nil, err
}
model := DealModel{
BidId: bidId.String(),
ContractAddress: log.Address.Hex(),
LogIndex: log.Index,
TransactionIndex: log.TxIndex,
Raw: raw,
}
result = append(result, model)
}
return result, nil
}
func validateLog(ethLog types.Log) error {
if len(ethLog.Topics) < 3 {
return errors.New("deal log does not contain expected topics")
}
return nil
}
-50
View File
@@ -1,50 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package deal_test
import (
"github.com/ethereum/go-ethereum/common"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/deal"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Flip Deal Converter", func() {
It("converts logs to models", func() {
converter := deal.DealConverter{}
models, err := converter.ToModels([]types.Log{test_data.DealLogNote})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
Expect(models[0]).To(Equal(test_data.DealModel))
})
It("returns an error if the expected amount of topics aren't in the log", func() {
converter := deal.DealConverter{}
invalidLog := test_data.DealLogNote
invalidLog.Topics = []common.Hash{}
_, err := converter.ToModels([]types.Log{invalidLog})
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError("deal log does not contain expected topics"))
})
})
-19
View File
@@ -1,19 +0,0 @@
package deal_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
log "github.com/sirupsen/logrus"
"io/ioutil"
)
func TestFlipDeal(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Deal Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-25
View File
@@ -1,25 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package deal
type DealModel struct {
BidId string `db:"bid_id"`
ContractAddress string `db:"contract_address"`
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
}
-90
View File
@@ -1,90 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package deal
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type DealRepository struct {
db *postgres.DB
}
func (repository DealRepository) Create(headerID int64, models []interface{}) error {
tx, dBaseErr := repository.db.Begin()
if dBaseErr != nil {
return dBaseErr
}
for _, model := range models {
dealModel, ok := model.(DealModel)
if !ok {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return fmt.Errorf("model of type %T, not %T", model, DealModel{})
}
_, execErr := tx.Exec(
`INSERT into maker.deal (header_id, bid_id, contract_address, log_idx, tx_idx, raw_log)
VALUES($1, $2, $3, $4, $5, $6)
ON CONFLICT (header_id, tx_idx, log_idx) DO UPDATE SET bid_id = $2, contract_address = $3, raw_log = $6;`,
headerID, dealModel.BidId, dealModel.ContractAddress, dealModel.LogIndex, dealModel.TransactionIndex, dealModel.Raw,
)
if execErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return execErr
}
}
checkHeaderErr := shared.MarkHeaderCheckedInTransaction(headerID, tx, constants.DealChecked)
if checkHeaderErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return checkHeaderErr
}
return tx.Commit()
}
func (repository DealRepository) MarkHeaderChecked(headerID int64) error {
return shared.MarkHeaderChecked(headerID, repository.db, constants.DealChecked)
}
func (repository DealRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.DealChecked)
}
func (repository DealRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.DealChecked)
}
func (repository *DealRepository) SetDB(db *postgres.DB) {
repository.db = db
}
-89
View File
@@ -1,89 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package deal_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/deal"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/shared_behaviors"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("Deal Repository", func() {
var (
db *postgres.DB
dealRepository deal.DealRepository
headerRepository repositories.HeaderRepository
)
BeforeEach(func() {
db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db)
dealRepository = deal.DealRepository{}
dealRepository.SetDB(db)
headerRepository = repositories.NewHeaderRepository(db)
})
Describe("Create", func() {
modelWithDifferentLogIdx := test_data.DealModel
modelWithDifferentLogIdx.LogIndex = modelWithDifferentLogIdx.LogIndex + 1
inputs := shared_behaviors.CreateBehaviorInputs{
CheckedHeaderColumnName: constants.DealChecked,
LogEventTableName: "maker.deal",
TestModel: test_data.DealModel,
ModelWithDifferentLogIdx: modelWithDifferentLogIdx,
Repository: &dealRepository,
}
shared_behaviors.SharedRepositoryCreateBehaviors(&inputs)
It("persists a deal record", func() {
headerId, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred())
err = dealRepository.Create(headerId, []interface{}{test_data.DealModel})
Expect(err).NotTo(HaveOccurred())
var count int
db.QueryRow(`SELECT count(*) FROM maker.deal`).Scan(&count)
Expect(count).To(Equal(1))
var dbResult deal.DealModel
err = db.Get(&dbResult, `SELECT bid_id, contract_address, log_idx, tx_idx, raw_log FROM maker.deal WHERE header_id = $1`, headerId)
Expect(err).NotTo(HaveOccurred())
Expect(dbResult.BidId).To(Equal(test_data.DealModel.BidId))
Expect(dbResult.ContractAddress).To(Equal(test_data.DealModel.ContractAddress))
Expect(dbResult.LogIndex).To(Equal(test_data.DealModel.LogIndex))
Expect(dbResult.TransactionIndex).To(Equal(test_data.DealModel.TransactionIndex))
Expect(dbResult.Raw).To(MatchJSON(test_data.DealModel.Raw))
})
})
Describe("MarkHeaderChecked", func() {
inputs := shared_behaviors.MarkedHeaderCheckedBehaviorInputs{
CheckedHeaderColumnName: constants.DealChecked,
Repository: &dealRepository,
}
shared_behaviors.SharedRepositoryMarkHeaderCheckedBehaviors(&inputs)
})
})
-34
View File
@@ -1,34 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dent
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetDentConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.DentLabel,
ContractAddresses: []string{constants.FlipperContractAddress(), constants.FlopperContractAddress()},
ContractAbi: constants.FlipperABI(),
Topic: constants.GetDentFunctionSignature(),
StartingBlockNumber: shared.MinInt64([]int64{constants.FlipperDeploymentBlock(), constants.FlopperDeploymentBlock()}),
EndingBlockNumber: -1,
}
}
-88
View File
@@ -1,88 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dent
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type DentConverter struct{}
func NewDentConverter() DentConverter {
return DentConverter{}
}
func (c DentConverter) ToModels(ethLogs []types.Log) (result []interface{}, err error) {
for _, log := range ethLogs {
err := validateLog(log)
if err != nil {
return nil, err
}
bidId := log.Topics[2].Big()
lot := log.Topics[3].Big().String()
bidValue := getBidValue(log)
// TODO: verify guy is available on Topics[1] (looks like it may just be an int id)
guy := common.HexToAddress(log.Topics[1].Hex()).String()
logIndex := log.Index
transactionIndex := log.TxIndex
raw, err := json.Marshal(log)
if err != nil {
return nil, err
}
model := DentModel{
BidId: bidId.String(),
Lot: lot,
Bid: bidValue,
Guy: guy,
LogIndex: logIndex,
TransactionIndex: transactionIndex,
Raw: raw,
}
result = append(result, model)
}
return result, err
}
func validateLog(ethLog types.Log) error {
if len(ethLog.Data) <= 0 {
return errors.New("dent log data is empty")
}
if len(ethLog.Topics) < 4 {
return errors.New("dent log does not contain expected topics")
}
return nil
}
func getBidValue(ethLog types.Log) string {
itemByteLength := 32
lastDataItemStartIndex := len(ethLog.Data) - itemByteLength
lastItem := ethLog.Data[lastDataItemStartIndex:]
lastValue := big.NewInt(0).SetBytes(lastItem)
return lastValue.String()
}
-59
View File
@@ -1,59 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dent_test
import (
"github.com/ethereum/go-ethereum/common"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/dent"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Dent Converter", func() {
var converter dent.DentConverter
BeforeEach(func() {
converter = dent.NewDentConverter()
})
It("converts an eth log to a db model", func() {
models, err := converter.ToModels([]types.Log{test_data.DentLog})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
Expect(models[0].(dent.DentModel)).To(Equal(test_data.DentModel))
})
It("returns an error if the expected amount of topics aren't in the log", func() {
invalidLog := test_data.DentLog
invalidLog.Topics = []common.Hash{}
_, err := converter.ToModels([]types.Log{invalidLog})
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError("dent log does not contain expected topics"))
})
It("returns an error if the log data is empty", func() {
emptyDataLog := test_data.DentLog
emptyDataLog.Data = []byte{}
_, err := converter.ToModels([]types.Log{emptyDataLog})
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError("dent log data is empty"))
})
})
-19
View File
@@ -1,19 +0,0 @@
package dent_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
log "github.com/sirupsen/logrus"
"io/ioutil"
)
func TestDent(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Dent Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-27
View File
@@ -1,27 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dent
type DentModel struct {
BidId string `db:"bid_id"`
Lot string
Bid string
Guy string
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
}
-93
View File
@@ -1,93 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dent
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type DentRepository struct {
db *postgres.DB
}
func (repository DentRepository) Create(headerID int64, models []interface{}) error {
tx, dBaseErr := repository.db.Begin()
if dBaseErr != nil {
return dBaseErr
}
tic, getTicErr := shared.GetTicInTx(headerID, tx)
if getTicErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return getTicErr
}
for _, model := range models {
dent, ok := model.(DentModel)
if !ok {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return fmt.Errorf("model of type %T, not %T", model, DentModel{})
}
_, execErr := tx.Exec(
`INSERT into maker.dent (header_id, bid_id, lot, bid, guy, tic, log_idx, tx_idx, raw_log)
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9)
ON CONFLICT (header_id, tx_idx, log_idx) DO UPDATE SET bid_Id = $2, lot = $3, bid = $4, guy = $5, tic = $6, raw_log = $9;`,
headerID, dent.BidId, dent.Lot, dent.Bid, dent.Guy, tic, dent.LogIndex, dent.TransactionIndex, dent.Raw,
)
if execErr != nil {
tx.Rollback()
return execErr
}
}
err := shared.MarkHeaderCheckedInTransaction(headerID, tx, constants.DentChecked)
if err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
func (repository DentRepository) MarkHeaderChecked(headerId int64) error {
return shared.MarkHeaderChecked(headerId, repository.db, constants.DentChecked)
}
func (repository DentRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.DentChecked)
}
func (repository DentRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.DentChecked)
}
func (repository *DentRepository) SetDB(db *postgres.DB) {
repository.db = db
}
-97
View File
@@ -1,97 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dent_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/dent"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/shared_behaviors"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("Dent Repository", func() {
var (
db *postgres.DB
dentRepository dent.DentRepository
headerRepository repositories.HeaderRepository
)
BeforeEach(func() {
db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db)
dentRepository = dent.DentRepository{}
dentRepository.SetDB(db)
headerRepository = repositories.NewHeaderRepository(db)
})
Describe("Create", func() {
modelWithDifferentLogIdx := test_data.DentModel
modelWithDifferentLogIdx.LogIndex++
inputs := shared_behaviors.CreateBehaviorInputs{
CheckedHeaderColumnName: constants.DentChecked,
LogEventTableName: "maker.dent",
TestModel: test_data.DentModel,
ModelWithDifferentLogIdx: modelWithDifferentLogIdx,
Repository: &dentRepository,
}
shared_behaviors.SharedRepositoryCreateBehaviors(&inputs)
It("persists a dent record", func() {
headerID, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred())
err = dentRepository.Create(headerID, []interface{}{test_data.DentModel})
Expect(err).NotTo(HaveOccurred())
var count int
db.QueryRow(`SELECT count(*) FROM maker.dent`).Scan(&count)
Expect(count).To(Equal(1))
var dbResult dent.DentModel
err = db.Get(&dbResult, `SELECT bid_id, lot, bid, guy, log_idx, tx_idx, raw_log FROM maker.dent WHERE header_id = $1`, headerID)
Expect(err).NotTo(HaveOccurred())
Expect(dbResult.BidId).To(Equal(test_data.DentModel.BidId))
Expect(dbResult.Lot).To(Equal(test_data.DentModel.Lot))
Expect(dbResult.Bid).To(Equal(test_data.DentModel.Bid))
Expect(dbResult.Guy).To(Equal(test_data.DentModel.Guy))
Expect(dbResult.LogIndex).To(Equal(test_data.DentModel.LogIndex))
Expect(dbResult.TransactionIndex).To(Equal(test_data.DentModel.TransactionIndex))
Expect(dbResult.Raw).To(MatchJSON(test_data.DentModel.Raw))
var dbTic int64
err = db.Get(&dbTic, `SELECT tic FROM maker.dent WHERE header_id = $1`, headerID)
Expect(err).NotTo(HaveOccurred())
Expect(dbTic).To(Equal(fakes.FakeHeaderTic))
})
})
Describe("MarkHeaderChecked", func() {
inputs := shared_behaviors.MarkedHeaderCheckedBehaviorInputs{
CheckedHeaderColumnName: constants.DentChecked,
Repository: &dentRepository,
}
shared_behaviors.SharedRepositoryMarkHeaderCheckedBehaviors(&inputs)
})
})
-32
View File
@@ -1,32 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package drip_drip
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetDripDripConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
ContractAddresses: []string{constants.DripContractAddress()},
ContractAbi: constants.DripABI(),
Topic: constants.GetDripDripSignature(),
StartingBlockNumber: constants.DripDeploymentBlock(),
EndingBlockNumber: -1,
}
}
-56
View File
@@ -1,56 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package drip_drip
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type DripDripConverter struct{}
func (DripDripConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []interface{}
for _, ethLog := range ethLogs {
err := verifyLog(ethLog)
if err != nil {
return nil, err
}
ilk := shared.GetHexWithoutPrefix(ethLog.Topics[2].Bytes())
raw, err := json.Marshal(ethLog)
if err != nil {
return nil, err
}
model := DripDripModel{
Ilk: ilk,
LogIndex: ethLog.Index,
TransactionIndex: ethLog.TxIndex,
Raw: raw,
}
models = append(models, model)
}
return models, nil
}
func verifyLog(log types.Log) error {
if len(log.Topics) < 3 {
return errors.New("log missing topics")
}
return nil
}
@@ -1,46 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package drip_drip_test
import (
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_drip"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Drip drip converter", func() {
It("returns err if log is missing topics", func() {
converter := drip_drip.DripDripConverter{}
badLog := types.Log{}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("converts a log to an model", func() {
converter := drip_drip.DripDripConverter{}
model, err := converter.ToModels([]types.Log{test_data.EthDripDripLog})
Expect(err).NotTo(HaveOccurred())
Expect(model).To(Equal([]interface{}{test_data.DripDripModel}))
})
})
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package drip_drip_test
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestDripDrip(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "DripDrip Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-24
View File
@@ -1,24 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package drip_drip
type DripDripModel struct {
Ilk string
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
}
-33
View File
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ilk
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetDripFileIlkConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.DripFileIlkLabel,
ContractAddresses: []string{constants.DripContractAddress()},
ContractAbi: constants.DripABI(),
Topic: constants.GetDripFileIlkSignature(),
StartingBlockNumber: constants.DripDeploymentBlock(),
EndingBlockNumber: -1,
}
}
@@ -1,70 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ilk
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type DripFileIlkConverter struct{}
func (DripFileIlkConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []interface{}
for _, ethLog := range ethLogs {
err := verifyLog(ethLog)
if err != nil {
return nil, err
}
ilk := shared.GetHexWithoutPrefix(ethLog.Topics[2].Bytes())
vow := shared.GetHexWithoutPrefix(ethLog.Topics[3].Bytes())
taxBytes := ethLog.Data[len(ethLog.Data)-constants.DataItemLength:]
tax := shared.ConvertToRay(big.NewInt(0).SetBytes(taxBytes).String())
raw, err := json.Marshal(ethLog)
if err != nil {
return nil, err
}
model := DripFileIlkModel{
Ilk: ilk,
Vow: vow,
Tax: tax,
LogIndex: ethLog.Index,
TransactionIndex: ethLog.TxIndex,
Raw: raw,
}
models = append(models, model)
}
return models, nil
}
func verifyLog(log types.Log) error {
if len(log.Topics) < 4 {
return errors.New("log missing topics")
}
if len(log.Data) < constants.DataItemLength {
return errors.New("log missing data")
}
return nil
}
@@ -1,63 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ilk_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/ilk"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Drip file ilk converter", func() {
It("returns err if log missing topics", func() {
converter := ilk.DripFileIlkConverter{}
badLog := types.Log{
Topics: []common.Hash{{}},
Data: []byte{1, 1, 1, 1, 1},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("returns err if log missing data", func() {
converter := ilk.DripFileIlkConverter{}
badLog := types.Log{
Topics: []common.Hash{{}, {}, {}, {}},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("converts a log to a model", func() {
converter := ilk.DripFileIlkConverter{}
models, err := converter.ToModels([]types.Log{test_data.EthDripFileIlkLog})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
Expect(models[0].(ilk.DripFileIlkModel)).To(Equal(test_data.DripFileIlkModel))
})
})
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ilk_test
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestIlk(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Ilk Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-26
View File
@@ -1,26 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ilk
type DripFileIlkModel struct {
Ilk string
Vow string
Tax string
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
}
-33
View File
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repo
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetDripFileRepoConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.DripFileRepoLabel,
ContractAddresses: []string{constants.DripContractAddress()},
ContractAbi: constants.DripABI(),
Topic: constants.GetDripFileRepoSignature(),
StartingBlockNumber: constants.DripDeploymentBlock(),
EndingBlockNumber: -1,
}
}
@@ -1,61 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repo
import (
"bytes"
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/core/types"
"math/big"
)
type DripFileRepoConverter struct{}
func (DripFileRepoConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []interface{}
for _, ethLog := range ethLogs {
err := verifyLog(ethLog)
if err != nil {
return nil, err
}
what := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00"))
data := big.NewInt(0).SetBytes(ethLog.Topics[3].Bytes()).String()
raw, err := json.Marshal(ethLog)
if err != nil {
return nil, err
}
model := DripFileRepoModel{
What: what,
Data: data,
LogIndex: ethLog.Index,
TransactionIndex: ethLog.TxIndex,
Raw: raw,
}
models = append(models, model)
}
return models, nil
}
func verifyLog(log types.Log) error {
if len(log.Topics) < 4 {
return errors.New("log missing topics")
}
return nil
}
@@ -1,51 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repo_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/repo"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Drip file repo converter", func() {
It("returns err if log missing topics", func() {
converter := repo.DripFileRepoConverter{}
badLog := types.Log{
Topics: []common.Hash{{}},
Data: []byte{1, 1, 1, 1, 1},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("converts a log to a model", func() {
converter := repo.DripFileRepoConverter{}
models, err := converter.ToModels([]types.Log{test_data.EthDripFileRepoLog})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
Expect(models[0].(repo.DripFileRepoModel)).To(Equal(test_data.DripFileRepoModel))
})
})
-25
View File
@@ -1,25 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repo
type DripFileRepoModel struct {
What string
Data string
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
}
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repo_test
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestRepo(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Repo Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
@@ -1,91 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repo
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type DripFileRepoRepository struct {
db *postgres.DB
}
func (repository DripFileRepoRepository) Create(headerID int64, models []interface{}) error {
tx, dBaseErr := repository.db.Begin()
if dBaseErr != nil {
return dBaseErr
}
for _, model := range models {
repo, ok := model.(DripFileRepoModel)
if !ok {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return fmt.Errorf("model of type %T, not %T", model, DripFileRepoModel{})
}
_, execErr := tx.Exec(
`INSERT into maker.drip_file_repo (header_id, what, data, log_idx, tx_idx, raw_log)
VALUES($1, $2, $3::NUMERIC, $4, $5, $6)`,
headerID, repo.What, repo.Data, repo.LogIndex, repo.TransactionIndex, repo.Raw,
)
if execErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return execErr
}
}
checkHeaderErr := shared.MarkHeaderCheckedInTransaction(headerID, tx, constants.DripFileRepoChecked)
if checkHeaderErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return checkHeaderErr
}
return tx.Commit()
}
func (repository DripFileRepoRepository) MarkHeaderChecked(headerID int64) error {
return shared.MarkHeaderChecked(headerID, repository.db, constants.DripFileRepoChecked)
}
func (repository DripFileRepoRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.DripFileRepoChecked)
}
func (repository DripFileRepoRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.DripFileRepoChecked)
}
func (repository *DripFileRepoRepository) SetDB(db *postgres.DB) {
repository.db = db
}
@@ -1,87 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package repo_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/repo"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/shared_behaviors"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("Drip file repo repository", func() {
var (
db *postgres.DB
dripFileRepoRepository repo.DripFileRepoRepository
headerRepository datastore.HeaderRepository
)
BeforeEach(func() {
db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db)
dripFileRepoRepository = repo.DripFileRepoRepository{}
dripFileRepoRepository.SetDB(db)
})
Describe("Create", func() {
modelWithDifferentLogIdx := test_data.DripFileRepoModel
modelWithDifferentLogIdx.LogIndex++
inputs := shared_behaviors.CreateBehaviorInputs{
CheckedHeaderColumnName: constants.DripFileRepoChecked,
LogEventTableName: "maker.drip_file_repo",
TestModel: test_data.DripFileRepoModel,
ModelWithDifferentLogIdx: modelWithDifferentLogIdx,
Repository: &dripFileRepoRepository,
}
shared_behaviors.SharedRepositoryCreateBehaviors(&inputs)
It("adds a drip file repo event", func() {
headerID, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred())
err = dripFileRepoRepository.Create(headerID, []interface{}{test_data.DripFileRepoModel})
Expect(err).NotTo(HaveOccurred())
var dbDripFileRepo repo.DripFileRepoModel
err = db.Get(&dbDripFileRepo, `SELECT what, data, log_idx, tx_idx, raw_log FROM maker.drip_file_repo WHERE header_id = $1`, headerID)
Expect(err).NotTo(HaveOccurred())
Expect(dbDripFileRepo.What).To(Equal(test_data.DripFileRepoModel.What))
Expect(dbDripFileRepo.Data).To(Equal(test_data.DripFileRepoModel.Data))
Expect(dbDripFileRepo.LogIndex).To(Equal(test_data.DripFileRepoModel.LogIndex))
Expect(dbDripFileRepo.TransactionIndex).To(Equal(test_data.DripFileRepoModel.TransactionIndex))
Expect(dbDripFileRepo.Raw).To(MatchJSON(test_data.DripFileRepoModel.Raw))
})
})
Describe("MarkHeaderChecked", func() {
inputs := shared_behaviors.MarkedHeaderCheckedBehaviorInputs{
CheckedHeaderColumnName: constants.DripFileRepoChecked,
Repository: &dripFileRepoRepository,
}
shared_behaviors.SharedRepositoryMarkHeaderCheckedBehaviors(&inputs)
})
})
-33
View File
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package vow
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetDripFileVowConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.DripFileVowLabel,
ContractAddresses: []string{constants.DripContractAddress()},
ContractAbi: constants.DripABI(),
Topic: constants.GetDripFileVowSignature(),
StartingBlockNumber: constants.DripDeploymentBlock(),
EndingBlockNumber: -1,
}
}
@@ -1,61 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package vow
import (
"bytes"
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type DripFileVowConverter struct{}
func (DripFileVowConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
var models []interface{}
for _, ethLog := range ethLogs {
err := verifyLog(ethLog)
if err != nil {
return nil, err
}
what := string(bytes.Trim(ethLog.Topics[2].Bytes(), "\x00"))
data := common.BytesToAddress(ethLog.Topics[3].Bytes()).String()
raw, err := json.Marshal(ethLog)
if err != nil {
return nil, err
}
model := DripFileVowModel{
What: what,
Data: data,
LogIndex: ethLog.Index,
TransactionIndex: ethLog.TxIndex,
Raw: raw,
}
models = append(models, model)
}
return models, nil
}
func verifyLog(log types.Log) error {
if len(log.Topics) < 4 {
return errors.New("log missing topics")
}
return nil
}
@@ -1,51 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package vow_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("Drip file repo converter", func() {
It("returns err if log missing topics", func() {
converter := vow.DripFileVowConverter{}
badLog := types.Log{
Topics: []common.Hash{{}},
Data: []byte{1, 1, 1, 1, 1},
}
_, err := converter.ToModels([]types.Log{badLog})
Expect(err).To(HaveOccurred())
})
It("converts a log to a model", func() {
converter := vow.DripFileVowConverter{}
models, err := converter.ToModels([]types.Log{test_data.EthDripFileVowLog})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
Expect(models[0].(vow.DripFileVowModel)).To(Equal(test_data.DripFileVowModel))
})
})
-25
View File
@@ -1,25 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package vow
type DripFileVowModel struct {
What string
Data string
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
}
@@ -1,91 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package vow
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type DripFileVowRepository struct {
db *postgres.DB
}
func (repository DripFileVowRepository) Create(headerID int64, models []interface{}) error {
tx, dBaseErr := repository.db.Begin()
if dBaseErr != nil {
return dBaseErr
}
for _, model := range models {
vow, ok := model.(DripFileVowModel)
if !ok {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return fmt.Errorf("model of type %T, not %T", model, DripFileVowModel{})
}
_, execErr := tx.Exec(
`INSERT into maker.drip_file_vow (header_id, what, data, log_idx, tx_idx, raw_log)
VALUES($1, $2, $3, $4, $5, $6)
ON CONFLICT (header_id, tx_idx, log_idx) DO UPDATE SET what = $2, data = $3, raw_log = $6;`,
headerID, vow.What, vow.Data, vow.LogIndex, vow.TransactionIndex, vow.Raw,
)
if execErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return execErr
}
}
checkHeaderErr := shared.MarkHeaderCheckedInTransaction(headerID, tx, constants.DripFileVowChecked)
if checkHeaderErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return checkHeaderErr
}
return tx.Commit()
}
func (repository DripFileVowRepository) MarkHeaderChecked(headerID int64) error {
return shared.MarkHeaderChecked(headerID, repository.db, constants.DripFileVowChecked)
}
func (repository DripFileVowRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.DripFileVowChecked)
}
func (repository DripFileVowRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.DripFileVowChecked)
}
func (repository *DripFileVowRepository) SetDB(db *postgres.DB) {
repository.db = db
}
@@ -1,86 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package vow_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/drip_file/vow"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/shared_behaviors"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("Drip file vow repository", func() {
var (
db *postgres.DB
dripFileVowRepository vow.DripFileVowRepository
headerRepository datastore.HeaderRepository
)
BeforeEach(func() {
db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db)
headerRepository = repositories.NewHeaderRepository(db)
dripFileVowRepository = vow.DripFileVowRepository{}
dripFileVowRepository.SetDB(db)
})
Describe("Create", func() {
modelWithDifferentLogIdx := test_data.DripFileVowModel
modelWithDifferentLogIdx.LogIndex++
inputs := shared_behaviors.CreateBehaviorInputs{
CheckedHeaderColumnName: constants.DripFileVowChecked,
LogEventTableName: "maker.drip_file_vow",
TestModel: test_data.DripFileVowModel,
ModelWithDifferentLogIdx: modelWithDifferentLogIdx,
Repository: &dripFileVowRepository,
}
shared_behaviors.SharedRepositoryCreateBehaviors(&inputs)
It("adds a drip file vow event", func() {
headerID, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred())
err = dripFileVowRepository.Create(headerID, []interface{}{test_data.DripFileVowModel})
Expect(err).NotTo(HaveOccurred())
var dbDripFileVow vow.DripFileVowModel
err = db.Get(&dbDripFileVow, `SELECT what, data, log_idx, tx_idx, raw_log FROM maker.drip_file_vow WHERE header_id = $1`, headerID)
Expect(err).NotTo(HaveOccurred())
Expect(dbDripFileVow.What).To(Equal(test_data.DripFileVowModel.What))
Expect(dbDripFileVow.Data).To(Equal(test_data.DripFileVowModel.Data))
Expect(dbDripFileVow.LogIndex).To(Equal(test_data.DripFileVowModel.LogIndex))
Expect(dbDripFileVow.TransactionIndex).To(Equal(test_data.DripFileVowModel.TransactionIndex))
Expect(dbDripFileVow.Raw).To(MatchJSON(test_data.DripFileVowModel.Raw))
})
})
Describe("MarkHeaderChecked", func() {
inputs := shared_behaviors.MarkedHeaderCheckedBehaviorInputs{
CheckedHeaderColumnName: constants.DripFileVowChecked,
Repository: &dripFileVowRepository,
}
shared_behaviors.SharedRepositoryMarkHeaderCheckedBehaviors(&inputs)
})
})
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package vow_test
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestVow(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Vow Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-24
View File
@@ -1,24 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package factories
import "github.com/ethereum/go-ethereum/core/types"
type Converter interface {
ToEntities(contractAbi string, ethLog []types.Log) ([]interface{}, error)
ToModels([]interface{}) ([]interface{}, error)
}
@@ -1,19 +0,0 @@
package factories_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
log "github.com/sirupsen/logrus"
"io/ioutil"
)
func TestFactories(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Factories Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
@@ -1,23 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package factories
import "github.com/ethereum/go-ethereum/core/types"
type LogNoteConverter interface {
ToModels(ethLog []types.Log) ([]interface{}, error)
}
@@ -1,73 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package factories
import (
"github.com/ethereum/go-ethereum/core/types"
log "github.com/sirupsen/logrus"
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type LogNoteTransformer struct {
Config shared_t.TransformerConfig
Converter LogNoteConverter
Repository Repository
}
func (transformer LogNoteTransformer) NewLogNoteTransformer(db *postgres.DB) shared_t.Transformer {
transformer.Repository.SetDB(db)
return transformer
}
func (transformer LogNoteTransformer) Execute(logs []types.Log, header core.Header, recheckedHeader constants.TransformerExecution) error {
transformerName := transformer.Config.TransformerName
// No matching logs, mark the header as checked for this type of logs
if len(logs) < 1 {
err := transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
log.Printf("Error marking header as checked in %v: %v", transformerName, err)
return err
}
return nil
}
models, err := transformer.Converter.ToModels(logs)
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
}
func (transformer LogNoteTransformer) GetName() string {
return transformer.Config.TransformerName
}
func (transformer LogNoteTransformer) GetConfig() shared_t.TransformerConfig {
return transformer.Config
}
@@ -1,126 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package factories_test
import (
"math/rand"
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks"
)
var _ = Describe("LogNoteTransformer", func() {
var (
repository mocks.MockRepository
converter mocks.MockLogNoteConverter
headerOne core.Header
transformer shared_t.Transformer
model test_data.GenericModel
config = test_data.GenericTestConfig
logs = test_data.GenericTestLogs
)
BeforeEach(func() {
repository = mocks.MockRepository{}
converter = mocks.MockLogNoteConverter{}
transformer = factories.LogNoteTransformer{
Config: config,
Converter: &converter,
Repository: &repository,
}.NewLogNoteTransformer(nil)
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
})
It("sets the database", func() {
Expect(repository.SetDbCalled).To(BeTrue())
})
It("marks header checked if no logs are provided", func() {
err := transformer.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
})
It("doesn't attempt to convert or persist an empty collection when there are no logs", func() {
err := transformer.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
Expect(converter.ToModelsCalledCounter).To(Equal(0))
Expect(repository.CreateCalledCounter).To(Equal(0))
})
It("does not call repository.MarkCheckedHeader when there are logs", func() {
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
repository.AssertMarkHeaderCheckedNotCalled()
})
It("returns error if marking header checked returns err", func() {
repository.SetMarkHeaderCheckedError(fakes.FakeError)
err := transformer.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
It("converts matching logs to models", func() {
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
Expect(converter.PassedLogs).To(Equal(logs))
})
It("returns error if converter returns error", func() {
converter.SetConverterError(fakes.FakeError)
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
It("persists the model", func() {
converter.SetReturnModels([]interface{}{model})
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels).To(Equal([]interface{}{model}))
})
It("returns error if repository returns error for create", func() {
repository.SetCreateError(fakes.FakeError)
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
})
-30
View File
@@ -1,30 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package factories
import (
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
)
type Repository interface {
Create(headerID int64, models []interface{}) error
MarkHeaderChecked(headerID int64) error
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
RecheckHeaders(startingBlockNumber, endingBlockNUmber int64) ([]core.Header, error)
SetDB(db *postgres.DB)
}
@@ -1,29 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package storage_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestStorage(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Storage Suite")
}
@@ -1,53 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package storage
import (
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/storage"
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs"
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
)
type Transformer struct {
Address common.Address
Mappings storage_diffs.Mappings
Repository storage_diffs.Repository
}
func (transformer Transformer) NewTransformer(db *postgres.DB) storage.Transformer {
transformer.Mappings.SetDB(db)
transformer.Repository.SetDB(db)
return transformer
}
func (transformer Transformer) ContractAddress() common.Address {
return transformer.Address
}
func (transformer Transformer) Execute(row shared.StorageDiffRow) error {
metadata, lookupErr := transformer.Mappings.Lookup(row.StorageKey)
if lookupErr != nil {
return lookupErr
}
value, decodeErr := shared.Decode(row, metadata)
if decodeErr != nil {
return decodeErr
}
return transformer.Repository.Create(row.BlockHeight, row.BlockHash.Hex(), metadata, value)
}
@@ -1,102 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package storage_test
import (
"github.com/ethereum/go-ethereum/common"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories/storage"
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks"
)
var _ = Describe("Storage transformer", func() {
var (
mappings *mocks.MockMappings
repository *mocks.MockStorageRepository
transformer storage.Transformer
)
BeforeEach(func() {
mappings = &mocks.MockMappings{}
repository = &mocks.MockStorageRepository{}
transformer = storage.Transformer{
Address: common.Address{},
Mappings: mappings,
Repository: repository,
}
})
It("returns the contract address being watched", func() {
fakeAddress := common.HexToAddress("0x12345")
transformer.Address = fakeAddress
Expect(transformer.ContractAddress()).To(Equal(fakeAddress))
})
It("looks up metadata for storage key", func() {
transformer.Execute(shared.StorageDiffRow{})
Expect(mappings.LookupCalled).To(BeTrue())
})
It("returns error if lookup fails", func() {
mappings.LookupErr = fakes.FakeError
err := transformer.Execute(shared.StorageDiffRow{})
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
It("creates storage row with decoded data", func() {
fakeMetadata := shared.StorageValueMetadata{Type: shared.Address}
mappings.Metadata = fakeMetadata
rawValue := common.HexToAddress("0x12345")
fakeBlockNumber := 123
fakeBlockHash := "0x67890"
fakeRow := shared.StorageDiffRow{
Contract: common.Address{},
BlockHash: common.HexToHash(fakeBlockHash),
BlockHeight: fakeBlockNumber,
StorageKey: common.Hash{},
StorageValue: rawValue.Hash(),
}
err := transformer.Execute(fakeRow)
Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedBlockNumber).To(Equal(fakeBlockNumber))
Expect(repository.PassedBlockHash).To(Equal(common.HexToHash(fakeBlockHash).Hex()))
Expect(repository.PassedMetadata).To(Equal(fakeMetadata))
Expect(repository.PassedValue.(string)).To(Equal(rawValue.Hex()))
})
It("returns error if creating row fails", func() {
rawValue := common.HexToAddress("0x12345")
fakeMetadata := shared.StorageValueMetadata{Type: shared.Address}
mappings.Metadata = fakeMetadata
repository.CreateErr = fakes.FakeError
err := transformer.Execute(shared.StorageDiffRow{StorageValue: rawValue.Hash()})
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
})
-80
View File
@@ -1,80 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package factories
import (
"github.com/ethereum/go-ethereum/core/types"
log "github.com/sirupsen/logrus"
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type Transformer struct {
Config shared_t.TransformerConfig
Converter Converter
Repository Repository
}
func (transformer Transformer) NewTransformer(db *postgres.DB) shared_t.Transformer {
transformer.Repository.SetDB(db)
return transformer
}
func (transformer Transformer) Execute(logs []types.Log, header core.Header, recheckHeaders constants.TransformerExecution) error {
transformerName := transformer.Config.TransformerName
config := transformer.Config
if len(logs) < 1 {
err := transformer.Repository.MarkHeaderChecked(header.Id)
if err != nil {
log.Printf("Error marking header as checked in %v: %v", transformerName, err)
return err
}
return nil
}
entities, err := transformer.Converter.ToEntities(config.ContractAbi, logs)
if err != nil {
log.Printf("Error converting logs to entities in %v: %v", transformerName, err)
return err
}
models, err := transformer.Converter.ToModels(entities)
if err != nil {
log.Printf("Error converting entities to models 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
}
func (transformer Transformer) GetName() string {
return transformer.Config.TransformerName
}
func (transformer Transformer) GetConfig() shared_t.TransformerConfig {
return transformer.Config
}
@@ -1,147 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package factories_test
import (
"math/rand"
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/factories"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks"
)
var _ = Describe("Transformer", func() {
var (
repository mocks.MockRepository
converter mocks.MockConverter
transformer shared_t.Transformer
headerOne core.Header
config = test_data.GenericTestConfig
logs = test_data.GenericTestLogs
)
BeforeEach(func() {
repository = mocks.MockRepository{}
converter = mocks.MockConverter{}
transformer = factories.Transformer{
Repository: &repository,
Converter: &converter,
Config: config,
}.NewTransformer(nil)
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
})
It("sets the db", func() {
Expect(repository.SetDbCalled).To(BeTrue())
})
It("marks header checked if no logs returned", func() {
err := transformer.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
})
It("doesn't attempt to convert or persist an empty collection when there are no logs", func() {
err := transformer.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
Expect(converter.ToEntitiesCalledCounter).To(Equal(0))
Expect(converter.ToModelsCalledCounter).To(Equal(0))
Expect(repository.CreateCalledCounter).To(Equal(0))
})
It("does not call repository.MarkCheckedHeader when there are logs", func() {
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
repository.AssertMarkHeaderCheckedNotCalled()
})
It("returns error if marking header checked returns err", func() {
repository.SetMarkHeaderCheckedError(fakes.FakeError)
err := transformer.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
It("converts an eth log to an entity", func() {
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
Expect(converter.ContractAbi).To(Equal(config.ContractAbi))
Expect(converter.LogsToConvert).To(Equal(logs))
})
It("returns an error if converter fails", func() {
converter.ToEntitiesError = fakes.FakeError
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
It("converts an entity to a model", func() {
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
Expect(converter.EntitiesToConvert[0]).To(Equal(test_data.GenericEntity{}))
})
It("returns an error if converting to models fails", func() {
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
converter.ToModelsError = fakes.FakeError
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
It("persists the record", func() {
converter.ModelsToReturn = []interface{}{test_data.GenericModel{}}
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).NotTo(HaveOccurred())
Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
Expect(repository.PassedModels[0]).To(Equal(test_data.GenericModel{}))
})
It("returns error if persisting the record fails", func() {
repository.SetCreateError(fakes.FakeError)
err := transformer.Execute(logs, headerOne, constants.HeaderMissing)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(fakes.FakeError))
})
})
-33
View File
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flap_kick
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetFlapKickConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.FlapKickLabel,
ContractAddresses: []string{constants.FlapperContractAddress()},
ContractAbi: constants.FlapperABI(),
Topic: constants.GetFlapKickSignature(),
StartingBlockNumber: constants.FlapperDeploymentBlock(),
EndingBlockNumber: -1,
}
}
-91
View File
@@ -1,91 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flap_kick
import (
"encoding/json"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/vulcanizedb/pkg/geth"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"time"
)
type FlapKickConverter struct {
}
func (FlapKickConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) {
var entities []interface{}
for _, ethLog := range ethLogs {
entity := &FlapKickEntity{}
address := ethLog.Address
abi, err := geth.ParseAbi(contractAbi)
if err != nil {
return nil, err
}
contract := bind.NewBoundContract(address, abi, nil, nil, nil)
err = contract.UnpackLog(entity, "Kick", ethLog)
if err != nil {
return nil, err
}
entity.Raw = ethLog
entity.TransactionIndex = ethLog.TxIndex
entity.LogIndex = ethLog.Index
entities = append(entities, *entity)
}
return entities, nil
}
func (FlapKickConverter) ToModels(entities []interface{}) ([]interface{}, error) {
var models []interface{}
for _, entity := range entities {
flapKickEntity, ok := entity.(FlapKickEntity)
if !ok {
return nil, fmt.Errorf("entity of type %T, not %T", entity, FlapKickEntity{})
}
if flapKickEntity.Id == nil {
return nil, errors.New("FlapKick log ID cannot be nil.")
}
id := flapKickEntity.Id.String()
lot := shared.BigIntToString(flapKickEntity.Lot)
bid := shared.BigIntToString(flapKickEntity.Bid)
gal := flapKickEntity.Gal.String()
endValue := shared.BigIntToInt64(flapKickEntity.End)
end := time.Unix(endValue, 0)
rawLog, err := json.Marshal(flapKickEntity.Raw)
if err != nil {
return nil, err
}
model := FlapKickModel{
BidId: id,
Lot: lot,
Bid: bid,
Gal: gal,
End: end,
TransactionIndex: flapKickEntity.TransactionIndex,
LogIndex: flapKickEntity.LogIndex,
Raw: rawLog,
}
models = append(models, model)
}
return models, nil
}
@@ -1,97 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flap_kick_test
import (
"encoding/json"
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/flap_kick"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"math/big"
"time"
)
var _ = Describe("Flap kick converter", func() {
var converter = flap_kick.FlapKickConverter{}
Describe("ToEntity", func() {
It("converts an Eth Log to a FlapKickEntity", func() {
entities, err := converter.ToEntities(test_data.KovanFlapperABI, []types.Log{test_data.EthFlapKickLog})
Expect(err).NotTo(HaveOccurred())
Expect(len(entities)).To(Equal(1))
Expect(entities[0]).To(Equal(test_data.FlapKickEntity))
})
It("returns an error if converting log to entity fails", func() {
_, err := converter.ToEntities("error abi", []types.Log{test_data.EthFlapKickLog})
Expect(err).To(HaveOccurred())
})
})
Describe("ToModel", func() {
BeforeEach(func() {
})
It("converts an Entity to a Model", func() {
models, err := converter.ToModels([]interface{}{test_data.FlapKickEntity})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
Expect(models[0]).To(Equal(test_data.FlapKickModel))
})
It("handles nil values", func() {
emptyAddressHex := "0x0000000000000000000000000000000000000000"
emptyString := ""
emptyTime := time.Unix(0, 0)
emptyEntity := flap_kick.FlapKickEntity{}
emptyEntity.Id = big.NewInt(1)
emptyRawLogJson, err := json.Marshal(types.Log{})
Expect(err).NotTo(HaveOccurred())
models, err := converter.ToModels([]interface{}{emptyEntity})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
model := models[0].(flap_kick.FlapKickModel)
Expect(model.BidId).To(Equal("1"))
Expect(model.Lot).To(Equal(emptyString))
Expect(model.Bid).To(Equal(emptyString))
Expect(model.Gal).To(Equal(emptyAddressHex))
Expect(model.End).To(Equal(emptyTime))
Expect(model.Raw).To(Equal(emptyRawLogJson))
})
It("returns an error if the flap kick event id is nil", func() {
_, err := converter.ToModels([]interface{}{flap_kick.FlapKickEntity{}})
Expect(err).To(HaveOccurred())
})
It("returns an error if the wrong entity type is passed in", func() {
_, err := converter.ToModels([]interface{}{test_data.WrongEntity{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("entity of type"))
})
})
})
-35
View File
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flap_kick
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type FlapKickEntity struct {
Id *big.Int
Lot *big.Int
Bid *big.Int
Gal common.Address
End *big.Int
Raw types.Log
TransactionIndex uint
LogIndex uint
}
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flap_kick_test
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestFlapKick(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "FlapKick Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-30
View File
@@ -1,30 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flap_kick
import "time"
type FlapKickModel struct {
BidId string `db:"bid_id"`
Lot string
Bid string
Gal string
End time.Time
LogIndex uint `db:"log_idx"`
TransactionIndex uint `db:"tx_idx"`
Raw []byte `db:"raw_log"`
}
-85
View File
@@ -1,85 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flap_kick
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type FlapKickRepository struct {
db *postgres.DB
}
func (repository *FlapKickRepository) Create(headerID int64, models []interface{}) error {
tx, dBaseErr := repository.db.Begin()
if dBaseErr != nil {
return dBaseErr
}
for _, model := range models {
flapKickModel, ok := model.(FlapKickModel)
if !ok {
return fmt.Errorf("model of type %T, not %T", model, FlapKickModel{})
}
_, execErr := tx.Exec(
`INSERT into maker.flap_kick (header_id, bid_id, lot, bid, gal, "end", tx_idx, log_idx, raw_log)
VALUES($1, $2::NUMERIC, $3::NUMERIC, $4::NUMERIC, $5, $6, $7, $8, $9)
ON CONFLICT (header_id, tx_idx, log_idx) DO UPDATE SET bid_id = $2, lot = $3, bid = $4, gal = $5, "end" = $6, raw_log = $9;`,
headerID, flapKickModel.BidId, flapKickModel.Lot, flapKickModel.Bid, flapKickModel.Gal, flapKickModel.End, flapKickModel.TransactionIndex, flapKickModel.LogIndex, flapKickModel.Raw,
)
if execErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return execErr
}
}
checkHeaderErr := shared.MarkHeaderCheckedInTransaction(headerID, tx, constants.FlapKickChecked)
if checkHeaderErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return checkHeaderErr
}
return tx.Commit()
}
func (repository *FlapKickRepository) MarkHeaderChecked(headerID int64) error {
return shared.MarkHeaderChecked(headerID, repository.db, constants.FlapKickChecked)
}
func (repository FlapKickRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.FlapKickChecked)
}
func (repository FlapKickRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.FlapKickChecked)
}
func (repository *FlapKickRepository) SetDB(db *postgres.DB) {
repository.db = db
}
@@ -1,92 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flap_kick_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/flap_kick"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/shared_behaviors"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("Flap Kick Repository", func() {
var (
db *postgres.DB
flapKickRepository flap_kick.FlapKickRepository
headerRepository repositories.HeaderRepository
)
BeforeEach(func() {
db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db)
flapKickRepository = flap_kick.FlapKickRepository{}
flapKickRepository.SetDB(db)
headerRepository = repositories.NewHeaderRepository(db)
})
Describe("Create", func() {
modelWithDifferentLogIdx := test_data.FlapKickModel
modelWithDifferentLogIdx.LogIndex = modelWithDifferentLogIdx.LogIndex + 1
inputs := shared_behaviors.CreateBehaviorInputs{
CheckedHeaderColumnName: constants.FlapKickChecked,
LogEventTableName: "maker.flap_kick",
TestModel: test_data.FlapKickModel,
ModelWithDifferentLogIdx: modelWithDifferentLogIdx,
Repository: &flapKickRepository,
}
shared_behaviors.SharedRepositoryCreateBehaviors(&inputs)
It("persists a flap kick record", func() {
headerId, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred())
err = flapKickRepository.Create(headerId, []interface{}{test_data.FlapKickModel})
Expect(err).NotTo(HaveOccurred())
var count int
db.QueryRow(`SELECT count(*) FROM maker.flap_kick`).Scan(&count)
Expect(count).To(Equal(1))
var dbResult flap_kick.FlapKickModel
err = db.Get(&dbResult, `SELECT bid, bid_id, "end", gal, lot, log_idx, tx_idx, raw_log FROM maker.flap_kick WHERE header_id = $1`, headerId)
Expect(err).NotTo(HaveOccurred())
Expect(dbResult.Bid).To(Equal(test_data.FlapKickModel.Bid))
Expect(dbResult.BidId).To(Equal(test_data.FlapKickModel.BidId))
Expect(dbResult.End.Equal(test_data.FlapKickModel.End)).To(BeTrue())
Expect(dbResult.Gal).To(Equal(test_data.FlapKickModel.Gal))
Expect(dbResult.Lot).To(Equal(test_data.FlapKickModel.Lot))
Expect(dbResult.LogIndex).To(Equal(test_data.FlapKickModel.LogIndex))
Expect(dbResult.TransactionIndex).To(Equal(test_data.FlapKickModel.TransactionIndex))
Expect(dbResult.Raw).To(MatchJSON(test_data.FlapKickModel.Raw))
})
})
Describe("MarkHeaderChecked", func() {
inputs := shared_behaviors.MarkedHeaderCheckedBehaviorInputs{
CheckedHeaderColumnName: constants.FlapKickChecked,
Repository: &flapKickRepository,
}
shared_behaviors.SharedRepositoryMarkHeaderCheckedBehaviors(&inputs)
})
})
-33
View File
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_kick
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetFlipKickConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.FlipKickLabel,
ContractAddresses: []string{constants.FlipperContractAddress()},
ContractAbi: constants.FlipperABI(),
Topic: constants.GetFlipKickSignature(),
StartingBlockNumber: constants.FlipperDeploymentBlock(),
EndingBlockNumber: -1,
}
}
-100
View File
@@ -1,100 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_kick
import (
"encoding/json"
"errors"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/geth"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type FlipKickConverter struct{}
func (FlipKickConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) {
var entities []interface{}
for _, ethLog := range ethLogs {
entity := &FlipKickEntity{}
address := ethLog.Address
abi, err := geth.ParseAbi(contractAbi)
if err != nil {
return nil, err
}
contract := bind.NewBoundContract(address, abi, nil, nil, nil)
err = contract.UnpackLog(entity, "Kick", ethLog)
if err != nil {
return nil, err
}
entity.Raw = ethLog
entity.TransactionIndex = ethLog.TxIndex
entity.LogIndex = ethLog.Index
entities = append(entities, *entity)
}
return entities, nil
}
func (FlipKickConverter) ToModels(entities []interface{}) ([]interface{}, error) {
var models []interface{}
for _, entity := range entities {
flipKickEntity, ok := entity.(FlipKickEntity)
if !ok {
return nil, fmt.Errorf("entity of type %T, not %T", entity, FlipKickEntity{})
}
if flipKickEntity.Id == nil {
return nil, errors.New("FlipKick log ID cannot be nil.")
}
id := flipKickEntity.Id.String()
lot := shared.BigIntToString(flipKickEntity.Lot)
bid := shared.BigIntToString(flipKickEntity.Bid)
gal := flipKickEntity.Gal.String()
endValue := shared.BigIntToInt64(flipKickEntity.End)
end := time.Unix(endValue, 0)
urn := common.BytesToAddress(flipKickEntity.Urn[:common.AddressLength]).String()
tab := shared.BigIntToString(flipKickEntity.Tab)
rawLog, err := json.Marshal(flipKickEntity.Raw)
if err != nil {
return nil, err
}
model := FlipKickModel{
BidId: id,
Lot: lot,
Bid: bid,
Gal: gal,
End: end,
Urn: urn,
Tab: tab,
TransactionIndex: flipKickEntity.TransactionIndex,
LogIndex: flipKickEntity.LogIndex,
Raw: rawLog,
}
models = append(models, model)
}
return models, nil
}
@@ -1,104 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_kick_test
import (
"encoding/json"
"math/big"
"time"
"github.com/ethereum/go-ethereum/core/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/transformers/flip_kick"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
)
var _ = Describe("FlipKick Converter", func() {
var converter = flip_kick.FlipKickConverter{}
Describe("ToEntity", func() {
It("converts an Eth Log to a FlipKickEntity", func() {
entities, err := converter.ToEntities(test_data.KovanFlipperABI, []types.Log{test_data.EthFlipKickLog})
Expect(err).NotTo(HaveOccurred())
Expect(len(entities)).To(Equal(1))
entity := entities[0]
Expect(entity).To(Equal(test_data.FlipKickEntity))
})
It("returns an error if converting log to entity fails", func() {
_, err := converter.ToEntities("error abi", []types.Log{test_data.EthFlipKickLog})
Expect(err).To(HaveOccurred())
})
})
Describe("ToModel", func() {
var emptyAddressHex = "0x0000000000000000000000000000000000000000"
var emptyString = ""
var emptyTime = time.Unix(0, 0)
var emptyEntity = flip_kick.FlipKickEntity{}
var emptyRawLog []byte
var err error
BeforeEach(func() {
emptyEntity.Id = big.NewInt(1)
emptyRawLog, err = json.Marshal(types.Log{})
Expect(err).NotTo(HaveOccurred())
})
It("converts an Entity to a Model", func() {
models, err := converter.ToModels([]interface{}{test_data.FlipKickEntity})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
Expect(models[0]).To(Equal(test_data.FlipKickModel))
})
It("handles nil values", func() {
models, err := converter.ToModels([]interface{}{emptyEntity})
Expect(err).NotTo(HaveOccurred())
Expect(len(models)).To(Equal(1))
model := models[0].(flip_kick.FlipKickModel)
Expect(model.BidId).To(Equal("1"))
Expect(model.Lot).To(Equal(emptyString))
Expect(model.Bid).To(Equal(emptyString))
Expect(model.Gal).To(Equal(emptyAddressHex))
Expect(model.End).To(Equal(emptyTime))
Expect(model.Urn).To(Equal(emptyAddressHex))
Expect(model.Tab).To(Equal(emptyString))
Expect(model.Raw).To(Equal(emptyRawLog))
})
It("returns an error if the flip kick event id is nil", func() {
emptyEntity.Id = nil
_, err := converter.ToModels([]interface{}{emptyEntity})
Expect(err).To(HaveOccurred())
})
It("returns an error if the wrong entity type is passed in", func() {
_, err := converter.ToModels([]interface{}{test_data.WrongEntity{}})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("entity of type"))
})
})
})
-37
View File
@@ -1,37 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_kick
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type FlipKickEntity struct {
Id *big.Int
Lot *big.Int
Bid *big.Int
Gal common.Address
End *big.Int
Urn [32]byte
Tab *big.Int
TransactionIndex uint
LogIndex uint
Raw types.Log
}
@@ -1,35 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_kick
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestFlipKick(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "FlipKick Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})
-32
View File
@@ -1,32 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_kick
import "time"
type FlipKickModel struct {
BidId string `db:"bid_id"`
Lot string
Bid string
Gal string
End time.Time
Urn string
Tab string
TransactionIndex uint `db:"tx_idx"`
LogIndex uint `db:"log_idx"`
Raw []byte `db:"raw_log"`
}
-83
View File
@@ -1,83 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_kick
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
type FlipKickRepository struct {
db *postgres.DB
}
func (repository FlipKickRepository) Create(headerID int64, models []interface{}) error {
tx, dBaseErr := repository.db.Begin()
if dBaseErr != nil {
return dBaseErr
}
for _, model := range models {
flipKickModel, ok := model.(FlipKickModel)
if !ok {
return fmt.Errorf("model of type %T, not %T", model, FlipKickModel{})
}
_, execErr := tx.Exec(
`INSERT into maker.flip_kick (header_id, bid_id, lot, bid, gal, "end", urn, tab, tx_idx, log_idx, raw_log)
VALUES($1, $2::NUMERIC, $3::NUMERIC, $4::NUMERIC, $5, $6, $7, $8::NUMERIC, $9, $10, $11)
ON CONFLICT (header_id, tx_idx, log_idx) DO UPDATE SET bid_id = $2, lot = $3, bid = $4, gal = $5, "end" = $6, urn= $7, tab = $8, raw_log = $11;`,
headerID, flipKickModel.BidId, flipKickModel.Lot, flipKickModel.Bid, flipKickModel.Gal, flipKickModel.End, flipKickModel.Urn, flipKickModel.Tab, flipKickModel.TransactionIndex, flipKickModel.LogIndex, flipKickModel.Raw,
)
if execErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return execErr
}
}
checkHeaderErr := shared.MarkHeaderCheckedInTransaction(headerID, tx, constants.FlipKickChecked)
if checkHeaderErr != nil {
rollbackErr := tx.Rollback()
if rollbackErr != nil {
log.Error("failed to rollback ", rollbackErr)
}
return checkHeaderErr
}
return tx.Commit()
}
func (repository FlipKickRepository) MarkHeaderChecked(headerId int64) error {
return shared.MarkHeaderChecked(headerId, repository.db, constants.FlipKickChecked)
}
func (repository FlipKickRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.MissingHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.FlipKickChecked)
}
func (repository FlipKickRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
return shared.RecheckHeaders(startingBlockNumber, endingBlockNumber, repository.db, constants.FlipKickChecked)
}
func (repository *FlipKickRepository) SetDB(db *postgres.DB) {
repository.db = db
}
@@ -1,100 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flip_kick_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"github.com/vulcanize/vulcanizedb/pkg/transformers/flip_kick"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/shared_behaviors"
"github.com/vulcanize/vulcanizedb/test_config"
)
var _ = Describe("FlipKick Repository", func() {
var db *postgres.DB
var flipKickRepository flip_kick.FlipKickRepository
BeforeEach(func() {
db = test_config.NewTestDB(test_config.NewTestNode())
test_config.CleanTestDB(db)
flipKickRepository = flip_kick.FlipKickRepository{}
flipKickRepository.SetDB(db)
})
Describe("Create", func() {
modelWithDifferentLogIdx := test_data.FlipKickModel
modelWithDifferentLogIdx.LogIndex++
inputs := shared_behaviors.CreateBehaviorInputs{
CheckedHeaderColumnName: constants.FlipKickChecked,
LogEventTableName: "maker.flip_kick",
TestModel: test_data.FlipKickModel,
ModelWithDifferentLogIdx: modelWithDifferentLogIdx,
Repository: &flipKickRepository,
}
shared_behaviors.SharedRepositoryCreateBehaviors(&inputs)
It("persists flip_kick records", func() {
headerRepository := repositories.NewHeaderRepository(db)
headerId, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
Expect(err).NotTo(HaveOccurred())
err = flipKickRepository.Create(headerId, []interface{}{test_data.FlipKickModel})
Expect(err).NotTo(HaveOccurred())
assertDBRecordCount(db, "maker.flip_kick", 1)
dbResult := test_data.FlipKickDBRow{}
err = db.QueryRowx(`SELECT * FROM maker.flip_kick`).StructScan(&dbResult)
Expect(err).NotTo(HaveOccurred())
Expect(dbResult.HeaderId).To(Equal(headerId))
Expect(dbResult.BidId).To(Equal(test_data.FlipKickModel.BidId))
Expect(dbResult.Lot).To(Equal(test_data.FlipKickModel.Lot))
Expect(dbResult.Bid).To(Equal(test_data.FlipKickModel.Bid))
Expect(dbResult.Gal).To(Equal(test_data.FlipKickModel.Gal))
Expect(dbResult.End.Equal(test_data.FlipKickModel.End)).To(BeTrue())
Expect(dbResult.Urn).To(Equal(test_data.FlipKickModel.Urn))
Expect(dbResult.Tab).To(Equal(test_data.FlipKickModel.Tab))
Expect(dbResult.TransactionIndex).To(Equal(test_data.FlipKickModel.TransactionIndex))
Expect(dbResult.LogIndex).To(Equal(test_data.FlipKickModel.LogIndex))
Expect(dbResult.Raw).To(MatchJSON(test_data.FlipKickModel.Raw))
})
})
Describe("MarkHeaderChecked", func() {
inputs := shared_behaviors.MarkedHeaderCheckedBehaviorInputs{
CheckedHeaderColumnName: constants.FlipKickChecked,
Repository: &flipKickRepository,
}
shared_behaviors.SharedRepositoryMarkHeaderCheckedBehaviors(&inputs)
})
})
func assertDBRecordCount(db *postgres.DB, dbTable string, expectedCount int) {
var count int
query := `SELECT count(*) FROM ` + dbTable
err := db.QueryRow(query).Scan(&count)
Expect(err).NotTo(HaveOccurred())
Expect(count).To(Equal(expectedCount))
}
-33
View File
@@ -1,33 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flop_kick
import (
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared/constants"
)
func GetFlopKickConfig() shared_t.TransformerConfig {
return shared_t.TransformerConfig{
TransformerName: constants.FlopKickLabel,
ContractAddresses: []string{constants.FlopperContractAddress()},
ContractAbi: constants.FlopperABI(),
Topic: constants.GetFlopKickSignature(),
StartingBlockNumber: constants.FlopperDeploymentBlock(),
EndingBlockNumber: -1,
}
}
-85
View File
@@ -1,85 +0,0 @@
// VulcanizeDB
// Copyright © 2018 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package flop_kick
import (
"encoding/json"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"fmt"
"github.com/vulcanize/vulcanizedb/pkg/geth"
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
)
type FlopKickConverter struct{}
func (FlopKickConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) {
var results []interface{}
for _, ethLog := range ethLogs {
entity := Entity{}
address := ethLog.Address
abi, err := geth.ParseAbi(contractAbi)
if err != nil {
return nil, err
}
contract := bind.NewBoundContract(address, abi, nil, nil, nil)
err = contract.UnpackLog(&entity, "Kick", ethLog)
if err != nil {
return nil, err
}
entity.Raw = ethLog
entity.TransactionIndex = ethLog.TxIndex
entity.LogIndex = ethLog.Index
results = append(results, entity)
}
return results, nil
}
func (FlopKickConverter) ToModels(entities []interface{}) ([]interface{}, error) {
var results []interface{}
for _, entity := range entities {
flopKickEntity, ok := entity.(Entity)
if !ok {
return nil, fmt.Errorf("entity of type %T, not %T", entity, Entity{})
}
endValue := shared.BigIntToInt64(flopKickEntity.End)
rawLogJson, err := json.Marshal(flopKickEntity.Raw)
if err != nil {
return nil, err
}
model := Model{
BidId: shared.BigIntToString(flopKickEntity.Id),
Lot: shared.BigIntToString(flopKickEntity.Lot),
Bid: shared.BigIntToString(flopKickEntity.Bid),
Gal: flopKickEntity.Gal.String(),
End: time.Unix(endValue, 0),
TransactionIndex: flopKickEntity.TransactionIndex,
LogIndex: flopKickEntity.LogIndex,
Raw: rawLogJson,
}
results = append(results, model)
}
return results, nil
}

Some files were not shown because too many files have changed in this diff Show More