forked from cerc-io/ipld-eth-server
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6ab9382b2 | ||
|
|
031043130e | ||
|
|
4505382590 | ||
|
|
b4e16c4af5 | ||
|
|
f0d2741dea | ||
|
|
267de00f99 | ||
|
|
5c0e5592ab | ||
|
|
9c6182c356 | ||
|
|
6672ecf547 | ||
|
|
f315988507 | ||
|
|
6869330bd3 | ||
|
|
2931edc317 | ||
|
|
4166fb24dd | ||
|
|
e1de3afdfc | ||
|
|
2ff88de859 | ||
|
|
d06dddbfaa | ||
|
|
f574407bb6 | ||
|
|
8111f4ec5e | ||
|
|
3fb8e13979 | ||
|
|
deb0315a49 | ||
|
|
66d695d93b | ||
|
|
a8a8fe4ac2 | ||
|
|
9831badc2a | ||
|
|
8e166f2a56 | ||
|
|
639c561fdf | ||
|
|
9226e53e0b | ||
|
|
0cc90a1f80 | ||
|
|
18f47b7b6a | ||
|
|
045d78be25 | ||
|
|
87252f42b9 | ||
|
|
e637024cce | ||
|
|
7cd66b8775 | ||
|
|
7cbad1d89f | ||
|
|
963479fdc0 | ||
|
|
b09b8a8735 | ||
|
|
70fcc22a00 | ||
|
|
a577811e0a | ||
|
|
8c4a4d6587 | ||
|
|
ee244ac6f5 | ||
|
|
dc06991605 | ||
|
|
1b4a901892 | ||
|
|
9de631f3a7 | ||
|
|
34f8e16c11 | ||
|
|
36533f7c3f | ||
|
|
20ce0ab852 | ||
|
|
9bb2f27a69 | ||
|
|
ba4e79fc63 | ||
|
|
c21c069b69 | ||
|
|
eea0b0bdca | ||
|
|
a596966b7c | ||
|
|
37e2673a8d | ||
|
|
dc30099a7c | ||
|
|
3466a51b4d | ||
|
|
8bbd65eabd | ||
|
|
749db40b96 | ||
|
|
2b151c2ba3 | ||
|
|
3897b288af | ||
|
|
b96a1ee1c6 | ||
|
|
f83e996ab8 | ||
|
|
4fa19be90a | ||
|
|
2b798e00e0 | ||
|
|
3f9b034c4c | ||
|
|
13d503b851 | ||
|
|
c568fedd89 | ||
|
|
3d6c973f6e | ||
|
|
ce91b0d9e6 | ||
|
|
b9f3b9f946 | ||
|
|
5ac76eee74 | ||
|
|
222252f89a | ||
|
|
666ea1c325 | ||
|
|
d76be4962b | ||
|
|
1883a11ab1 | ||
|
|
63dabbb051 | ||
|
|
d496dad33c | ||
|
|
cb819fa9a6 | ||
|
|
66a4e20b20 | ||
|
|
3693ed905f | ||
|
|
b6a2a278ce | ||
|
|
edc0bdf668 | ||
|
|
1b3786338f | ||
|
|
58c23c6632 | ||
|
|
38f6847ff2 | ||
|
|
7e38764618 | ||
|
|
4e40e892d2 | ||
|
|
bcd6d14fcd | ||
|
|
258035833b | ||
|
|
4b61c87b55 | ||
|
|
1373fe83a1 | ||
|
|
b13eefbce7 | ||
|
|
3005a1ad50 | ||
|
|
750754caa7 | ||
|
|
e093ad351f | ||
|
|
33e7651096 |
+1
-1
@@ -84,7 +84,7 @@ func coldImport() {
|
|||||||
|
|
||||||
// init cold importer deps
|
// init cold importer deps
|
||||||
blockRepository := repositories.NewBlockRepository(&pgDB)
|
blockRepository := repositories.NewBlockRepository(&pgDB)
|
||||||
receiptRepository := repositories.ReceiptRepository{DB: &pgDB}
|
receiptRepository := repositories.FullSyncReceiptRepository{DB: &pgDB}
|
||||||
transactionConverter := cold_db.NewColdDbTransactionConverter()
|
transactionConverter := cold_db.NewColdDbTransactionConverter()
|
||||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||||
|
|
||||||
|
|||||||
+6
-5
@@ -1,17 +1,18 @@
|
|||||||
// Copyright © 2019 Vulcanize, Inc
|
// VulcanizeDB
|
||||||
//
|
// Copyright © 2019 Vulcanize
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// 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
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU Affero General Public License for more details.
|
// GNU Affero General Public License for more details.
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
|
|||||||
+34
-14
@@ -1,21 +1,26 @@
|
|||||||
// Copyright © 2019 Vulcanize, Inc
|
// VulcanizeDB
|
||||||
//
|
// Copyright © 2019 Vulcanize
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// 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
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU Affero General Public License for more details.
|
// GNU Affero General Public License for more details.
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/streamer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
||||||
"os"
|
"os"
|
||||||
"plugin"
|
"plugin"
|
||||||
syn "sync"
|
syn "sync"
|
||||||
@@ -24,9 +29,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/watcher"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/watcher"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
|
||||||
p2 "github.com/vulcanize/vulcanizedb/pkg/plugin"
|
p2 "github.com/vulcanize/vulcanizedb/pkg/plugin"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/plugin/helpers"
|
"github.com/vulcanize/vulcanizedb/pkg/plugin/helpers"
|
||||||
"github.com/vulcanize/vulcanizedb/utils"
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
@@ -169,18 +172,35 @@ func composeAndExecute() {
|
|||||||
var wg syn.WaitGroup
|
var wg syn.WaitGroup
|
||||||
if len(ethEventInitializers) > 0 {
|
if len(ethEventInitializers) > 0 {
|
||||||
ew := watcher.NewEventWatcher(&db, blockChain)
|
ew := watcher.NewEventWatcher(&db, blockChain)
|
||||||
ew.AddTransformers(ethEventInitializers)
|
err := ew.AddTransformers(ethEventInitializers)
|
||||||
|
if err != nil {
|
||||||
|
LogWithCommand.Fatalf("failed to add event transformer initializers to watcher: %s", err.Error())
|
||||||
|
}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go watchEthEvents(&ew, &wg)
|
go watchEthEvents(&ew, &wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ethStorageInitializers) > 0 {
|
if len(ethStorageInitializers) > 0 {
|
||||||
tailer := fs.FileTailer{Path: storageDiffsPath}
|
switch storageDiffsSource {
|
||||||
storageFetcher := fetcher.NewCsvTailStorageFetcher(tailer)
|
case "geth":
|
||||||
sw := watcher.NewStorageWatcher(storageFetcher, &db)
|
log.Debug("fetching storage diffs from geth pub sub")
|
||||||
sw.AddTransformers(ethStorageInitializers)
|
rpcClient, _ := getClients()
|
||||||
wg.Add(1)
|
stateDiffStreamer := streamer.NewStateDiffStreamer(rpcClient)
|
||||||
go watchEthStorage(&sw, &wg)
|
payloadChan := make(chan statediff.Payload)
|
||||||
|
storageFetcher := fetcher.NewGethRpcStorageFetcher(&stateDiffStreamer, payloadChan)
|
||||||
|
sw := watcher.NewStorageWatcher(storageFetcher, &db)
|
||||||
|
sw.AddTransformers(ethStorageInitializers)
|
||||||
|
wg.Add(1)
|
||||||
|
go watchEthStorage(&sw, &wg)
|
||||||
|
default:
|
||||||
|
log.Debug("fetching storage diffs from csv")
|
||||||
|
tailer := fs.FileTailer{Path: storageDiffsPath}
|
||||||
|
storageFetcher := fetcher.NewCsvTailStorageFetcher(tailer)
|
||||||
|
sw := watcher.NewStorageWatcher(storageFetcher, &db)
|
||||||
|
sw.AddTransformers(ethStorageInitializers)
|
||||||
|
wg.Add(1)
|
||||||
|
go watchEthStorage(&sw, &wg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ethContractInitializers) > 0 {
|
if len(ethContractInitializers) > 0 {
|
||||||
|
|||||||
+41
-22
@@ -1,22 +1,27 @@
|
|||||||
// Copyright © 2019 Vulcanize, Inc
|
// VulcanizeDB
|
||||||
//
|
// Copyright © 2019 Vulcanize
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// 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
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU Affero General Public License for more details.
|
// GNU Affero General Public License for more details.
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/streamer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
||||||
"plugin"
|
"plugin"
|
||||||
syn "sync"
|
syn "sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -25,11 +30,9 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
|
||||||
storageUtils "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
storageUtils "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/watcher"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/watcher"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
|
||||||
"github.com/vulcanize/vulcanizedb/utils"
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -113,18 +116,35 @@ func execute() {
|
|||||||
var wg syn.WaitGroup
|
var wg syn.WaitGroup
|
||||||
if len(ethEventInitializers) > 0 {
|
if len(ethEventInitializers) > 0 {
|
||||||
ew := watcher.NewEventWatcher(&db, blockChain)
|
ew := watcher.NewEventWatcher(&db, blockChain)
|
||||||
ew.AddTransformers(ethEventInitializers)
|
err = ew.AddTransformers(ethEventInitializers)
|
||||||
|
if err != nil {
|
||||||
|
LogWithCommand.Fatalf("failed to add event transformer initializers to watcher: %s", err.Error())
|
||||||
|
}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go watchEthEvents(&ew, &wg)
|
go watchEthEvents(&ew, &wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ethStorageInitializers) > 0 {
|
if len(ethStorageInitializers) > 0 {
|
||||||
tailer := fs.FileTailer{Path: storageDiffsPath}
|
switch storageDiffsSource {
|
||||||
storageFetcher := fetcher.NewCsvTailStorageFetcher(tailer)
|
case "geth":
|
||||||
sw := watcher.NewStorageWatcher(storageFetcher, &db)
|
log.Debug("fetching storage diffs from geth pub sub")
|
||||||
sw.AddTransformers(ethStorageInitializers)
|
rpcClient, _ := getClients()
|
||||||
wg.Add(1)
|
stateDiffStreamer := streamer.NewStateDiffStreamer(rpcClient)
|
||||||
go watchEthStorage(&sw, &wg)
|
payloadChan := make(chan statediff.Payload)
|
||||||
|
storageFetcher := fetcher.NewGethRpcStorageFetcher(&stateDiffStreamer, payloadChan)
|
||||||
|
sw := watcher.NewStorageWatcher(storageFetcher, &db)
|
||||||
|
sw.AddTransformers(ethStorageInitializers)
|
||||||
|
wg.Add(1)
|
||||||
|
go watchEthStorage(&sw, &wg)
|
||||||
|
default:
|
||||||
|
log.Debug("fetching storage diffs from csv")
|
||||||
|
tailer := fs.FileTailer{Path: storageDiffsPath}
|
||||||
|
storageFetcher := fetcher.NewCsvTailStorageFetcher(tailer)
|
||||||
|
sw := watcher.NewStorageWatcher(storageFetcher, &db)
|
||||||
|
sw.AddTransformers(ethStorageInitializers)
|
||||||
|
wg.Add(1)
|
||||||
|
go watchEthStorage(&sw, &wg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ethContractInitializers) > 0 {
|
if len(ethContractInitializers) > 0 {
|
||||||
@@ -154,16 +174,15 @@ func watchEthEvents(w *watcher.EventWatcher, wg *syn.WaitGroup) {
|
|||||||
if recheckHeadersArg {
|
if recheckHeadersArg {
|
||||||
recheck = constants.HeaderRecheck
|
recheck = constants.HeaderRecheck
|
||||||
} else {
|
} else {
|
||||||
recheck = constants.HeaderMissing
|
recheck = constants.HeaderUnchecked
|
||||||
}
|
}
|
||||||
ticker := time.NewTicker(pollingInterval)
|
err := w.Execute(recheck)
|
||||||
defer ticker.Stop()
|
if err != nil {
|
||||||
for range ticker.C {
|
LogWithCommand.Fatalf("error executing event watcher: %s", err.Error())
|
||||||
w.Execute(recheck)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func watchEthStorage(w *watcher.StorageWatcher, wg *syn.WaitGroup) {
|
func watchEthStorage(w watcher.IStorageWatcher, wg *syn.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
// Execute over the StorageTransformerInitializer set using the storage watcher
|
// Execute over the StorageTransformerInitializer set using the storage watcher
|
||||||
LogWithCommand.Info("executing storage transformers")
|
LogWithCommand.Info("executing storage transformers")
|
||||||
@@ -171,8 +190,8 @@ func watchEthStorage(w *watcher.StorageWatcher, wg *syn.WaitGroup) {
|
|||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
errs := make(chan error)
|
errs := make(chan error)
|
||||||
rows := make(chan storageUtils.StorageDiffRow)
|
diffs := make(chan storageUtils.StorageDiff)
|
||||||
w.Execute(rows, errs, queueRecheckInterval)
|
w.Execute(diffs, errs, queueRecheckInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-4
@@ -48,6 +48,7 @@ var (
|
|||||||
recheckHeadersArg bool
|
recheckHeadersArg bool
|
||||||
SubCommand string
|
SubCommand string
|
||||||
LogWithCommand log.Entry
|
LogWithCommand log.Entry
|
||||||
|
storageDiffsSource string
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -80,6 +81,7 @@ func setViperConfigs() {
|
|||||||
ipc = viper.GetString("client.ipcpath")
|
ipc = viper.GetString("client.ipcpath")
|
||||||
levelDbPath = viper.GetString("client.leveldbpath")
|
levelDbPath = viper.GetString("client.leveldbpath")
|
||||||
storageDiffsPath = viper.GetString("filesystem.storageDiffsPath")
|
storageDiffsPath = viper.GetString("filesystem.storageDiffsPath")
|
||||||
|
storageDiffsSource = viper.GetString("storageDiffs.source")
|
||||||
databaseConfig = config.Database{
|
databaseConfig = config.Database{
|
||||||
Name: viper.GetString("database.name"),
|
Name: viper.GetString("database.name"),
|
||||||
Hostname: viper.GetString("database.hostname"),
|
Hostname: viper.GetString("database.hostname"),
|
||||||
@@ -118,6 +120,7 @@ func init() {
|
|||||||
rootCmd.PersistentFlags().String("client-ipcPath", "", "location of geth.ipc file")
|
rootCmd.PersistentFlags().String("client-ipcPath", "", "location of geth.ipc file")
|
||||||
rootCmd.PersistentFlags().String("client-levelDbPath", "", "location of levelDb chaindata")
|
rootCmd.PersistentFlags().String("client-levelDbPath", "", "location of levelDb chaindata")
|
||||||
rootCmd.PersistentFlags().String("filesystem-storageDiffsPath", "", "location of storage diffs csv file")
|
rootCmd.PersistentFlags().String("filesystem-storageDiffsPath", "", "location of storage diffs csv file")
|
||||||
|
rootCmd.PersistentFlags().String("storageDiffs-source", "csv", "where to get the state diffs: csv or geth")
|
||||||
rootCmd.PersistentFlags().String("exporter-name", "exporter", "name of exporter plugin")
|
rootCmd.PersistentFlags().String("exporter-name", "exporter", "name of exporter plugin")
|
||||||
rootCmd.PersistentFlags().String("log-level", log.InfoLevel.String(), "Log level (trace, debug, info, warn, error, fatal, panic")
|
rootCmd.PersistentFlags().String("log-level", log.InfoLevel.String(), "Log level (trace, debug, info, warn, error, fatal, panic")
|
||||||
|
|
||||||
@@ -129,6 +132,7 @@ func init() {
|
|||||||
viper.BindPFlag("client.ipcPath", rootCmd.PersistentFlags().Lookup("client-ipcPath"))
|
viper.BindPFlag("client.ipcPath", rootCmd.PersistentFlags().Lookup("client-ipcPath"))
|
||||||
viper.BindPFlag("client.levelDbPath", rootCmd.PersistentFlags().Lookup("client-levelDbPath"))
|
viper.BindPFlag("client.levelDbPath", rootCmd.PersistentFlags().Lookup("client-levelDbPath"))
|
||||||
viper.BindPFlag("filesystem.storageDiffsPath", rootCmd.PersistentFlags().Lookup("filesystem-storageDiffsPath"))
|
viper.BindPFlag("filesystem.storageDiffsPath", rootCmd.PersistentFlags().Lookup("filesystem-storageDiffsPath"))
|
||||||
|
viper.BindPFlag("storageDiffs.source", rootCmd.PersistentFlags().Lookup("storageDiffs-source"))
|
||||||
viper.BindPFlag("exporter.fileName", rootCmd.PersistentFlags().Lookup("exporter-name"))
|
viper.BindPFlag("exporter.fileName", rootCmd.PersistentFlags().Lookup("exporter-name"))
|
||||||
viper.BindPFlag("log.level", rootCmd.PersistentFlags().Lookup("log-level"))
|
viper.BindPFlag("log.level", rootCmd.PersistentFlags().Lookup("log-level"))
|
||||||
}
|
}
|
||||||
@@ -152,6 +156,14 @@ func initConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getBlockChain() *geth.BlockChain {
|
func getBlockChain() *geth.BlockChain {
|
||||||
|
rpcClient, ethClient := getClients()
|
||||||
|
vdbEthClient := client.NewEthClient(ethClient)
|
||||||
|
vdbNode := node.MakeNode(rpcClient)
|
||||||
|
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
|
||||||
|
return geth.NewBlockChain(vdbEthClient, rpcClient, vdbNode, transactionConverter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClients() (client.RpcClient, *ethclient.Client) {
|
||||||
rawRpcClient, err := rpc.Dial(ipc)
|
rawRpcClient, err := rpc.Dial(ipc)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -159,8 +171,6 @@ func getBlockChain() *geth.BlockChain {
|
|||||||
}
|
}
|
||||||
rpcClient := client.NewRpcClient(rawRpcClient, ipc)
|
rpcClient := client.NewRpcClient(rawRpcClient, ipc)
|
||||||
ethClient := ethclient.NewClient(rawRpcClient)
|
ethClient := ethclient.NewClient(rawRpcClient)
|
||||||
vdbEthClient := client.NewEthClient(ethClient)
|
|
||||||
vdbNode := node.MakeNode(rpcClient)
|
return rpcClient, ethClient
|
||||||
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
|
|
||||||
return geth.NewBlockChain(vdbEthClient, rpcClient, vdbNode, transactionConverter)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE full_sync_logs
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
block_number BIGINT,
|
||||||
|
address VARCHAR(66),
|
||||||
|
tx_hash VARCHAR(66),
|
||||||
|
index BIGINT,
|
||||||
|
topic0 VARCHAR(66),
|
||||||
|
topic1 VARCHAR(66),
|
||||||
|
topic2 VARCHAR(66),
|
||||||
|
topic3 VARCHAR(66),
|
||||||
|
data TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE full_sync_logs;
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
CREATE TABLE logs (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
block_number BIGINT,
|
|
||||||
address VARCHAR(66),
|
|
||||||
tx_hash VARCHAR(66),
|
|
||||||
index BIGINT,
|
|
||||||
topic0 VARCHAR(66),
|
|
||||||
topic1 VARCHAR(66),
|
|
||||||
topic2 VARCHAR(66),
|
|
||||||
topic3 VARCHAR(66),
|
|
||||||
data TEXT,
|
|
||||||
CONSTRAINT log_uc UNIQUE (block_number, index)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP TABLE logs;
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE public.addresses
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
address character varying(42),
|
||||||
|
UNIQUE (address)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE public.addresses;
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
CREATE TABLE full_sync_receipts
|
|
||||||
(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
transaction_id INTEGER NOT NULL REFERENCES full_sync_transactions (id) ON DELETE CASCADE,
|
|
||||||
contract_address VARCHAR(42),
|
|
||||||
cumulative_gas_used NUMERIC,
|
|
||||||
gas_used NUMERIC,
|
|
||||||
state_root VARCHAR(66),
|
|
||||||
status INTEGER,
|
|
||||||
tx_hash VARCHAR(66)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP TABLE full_sync_receipts;
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE full_sync_receipts
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
transaction_id INTEGER NOT NULL REFERENCES full_sync_transactions (id) ON DELETE CASCADE,
|
||||||
|
contract_address_id INTEGER NOT NULL REFERENCES addresses (id) ON DELETE CASCADE,
|
||||||
|
cumulative_gas_used NUMERIC,
|
||||||
|
gas_used NUMERIC,
|
||||||
|
state_root VARCHAR(66),
|
||||||
|
status INTEGER,
|
||||||
|
tx_hash VARCHAR(66)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE full_sync_receipts;
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
ALTER TABLE logs
|
|
||||||
DROP CONSTRAINT log_uc;
|
|
||||||
|
|
||||||
ALTER TABLE logs
|
|
||||||
ADD COLUMN receipt_id INT;
|
|
||||||
|
|
||||||
ALTER TABLE logs
|
|
||||||
ADD CONSTRAINT receipts_fk
|
|
||||||
FOREIGN KEY (receipt_id)
|
|
||||||
REFERENCES full_sync_receipts (id)
|
|
||||||
ON DELETE CASCADE;
|
|
||||||
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
ALTER TABLE logs
|
|
||||||
DROP CONSTRAINT receipts_fk;
|
|
||||||
|
|
||||||
ALTER TABLE logs
|
|
||||||
DROP COLUMN receipt_id;
|
|
||||||
|
|
||||||
ALTER TABLE logs
|
|
||||||
ADD CONSTRAINT log_uc UNIQUE (block_number, index);
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- +goose Up
|
||||||
|
ALTER TABLE full_sync_logs
|
||||||
|
ADD COLUMN receipt_id INT;
|
||||||
|
|
||||||
|
ALTER TABLE full_sync_logs
|
||||||
|
ADD CONSTRAINT receipts_fk
|
||||||
|
FOREIGN KEY (receipt_id)
|
||||||
|
REFERENCES full_sync_receipts (id)
|
||||||
|
ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
ALTER TABLE full_sync_logs
|
||||||
|
DROP CONSTRAINT receipts_fk;
|
||||||
|
|
||||||
|
ALTER TABLE full_sync_logs
|
||||||
|
DROP COLUMN receipt_id;
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
CREATE VIEW block_stats AS
|
|
||||||
SELECT
|
|
||||||
max(block_number) AS max_block,
|
|
||||||
min(block_number) AS min_block
|
|
||||||
FROM logs;
|
|
||||||
|
|
||||||
CREATE VIEW watched_event_logs AS
|
|
||||||
SELECT
|
|
||||||
log_filters.name,
|
|
||||||
logs.id,
|
|
||||||
block_number,
|
|
||||||
logs.address,
|
|
||||||
tx_hash,
|
|
||||||
index,
|
|
||||||
logs.topic0,
|
|
||||||
logs.topic1,
|
|
||||||
logs.topic2,
|
|
||||||
logs.topic3,
|
|
||||||
data,
|
|
||||||
receipt_id
|
|
||||||
FROM log_filters
|
|
||||||
CROSS JOIN block_stats
|
|
||||||
JOIN logs ON logs.address = log_filters.address
|
|
||||||
AND logs.block_number >= coalesce(log_filters.from_block, block_stats.min_block)
|
|
||||||
AND logs.block_number <= coalesce(log_filters.to_block, block_stats.max_block)
|
|
||||||
WHERE (log_filters.topic0 = logs.topic0 OR log_filters.topic0 ISNULL)
|
|
||||||
AND (log_filters.topic1 = logs.topic1 OR log_filters.topic1 ISNULL)
|
|
||||||
AND (log_filters.topic2 = logs.topic2 OR log_filters.topic2 ISNULL)
|
|
||||||
AND (log_filters.topic3 = logs.topic3 OR log_filters.topic3 ISNULL);
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP VIEW watched_event_logs;
|
|
||||||
DROP VIEW block_stats;
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE VIEW block_stats AS
|
||||||
|
SELECT max(block_number) AS max_block,
|
||||||
|
min(block_number) AS min_block
|
||||||
|
FROM full_sync_logs;
|
||||||
|
|
||||||
|
CREATE VIEW watched_event_logs AS
|
||||||
|
SELECT log_filters.name,
|
||||||
|
full_sync_logs.id,
|
||||||
|
block_number,
|
||||||
|
full_sync_logs.address,
|
||||||
|
tx_hash,
|
||||||
|
index,
|
||||||
|
full_sync_logs.topic0,
|
||||||
|
full_sync_logs.topic1,
|
||||||
|
full_sync_logs.topic2,
|
||||||
|
full_sync_logs.topic3,
|
||||||
|
data,
|
||||||
|
receipt_id
|
||||||
|
FROM log_filters
|
||||||
|
CROSS JOIN block_stats
|
||||||
|
JOIN full_sync_logs ON full_sync_logs.address = log_filters.address
|
||||||
|
AND full_sync_logs.block_number >= coalesce(log_filters.from_block, block_stats.min_block)
|
||||||
|
AND full_sync_logs.block_number <= coalesce(log_filters.to_block, block_stats.max_block)
|
||||||
|
WHERE (log_filters.topic0 = full_sync_logs.topic0 OR log_filters.topic0 ISNULL)
|
||||||
|
AND (log_filters.topic1 = full_sync_logs.topic1 OR log_filters.topic1 ISNULL)
|
||||||
|
AND (log_filters.topic2 = full_sync_logs.topic2 OR log_filters.topic2 ISNULL)
|
||||||
|
AND (log_filters.topic3 = full_sync_logs.topic3 OR log_filters.topic3 ISNULL);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP VIEW watched_event_logs;
|
||||||
|
DROP VIEW block_stats;
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
CREATE TABLE public.headers (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
hash VARCHAR(66),
|
|
||||||
block_number BIGINT,
|
|
||||||
raw JSONB,
|
|
||||||
block_timestamp NUMERIC,
|
|
||||||
eth_node_id INTEGER NOT NULL REFERENCES eth_nodes (id) ON DELETE CASCADE,
|
|
||||||
eth_node_fingerprint VARCHAR(128)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Index is removed when table is
|
|
||||||
CREATE INDEX headers_block_number ON public.headers (block_number);
|
|
||||||
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP TABLE public.headers;
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE public.headers
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
hash VARCHAR(66),
|
||||||
|
block_number BIGINT,
|
||||||
|
raw JSONB,
|
||||||
|
block_timestamp NUMERIC,
|
||||||
|
check_count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
eth_node_id INTEGER NOT NULL REFERENCES eth_nodes (id) ON DELETE CASCADE,
|
||||||
|
eth_node_fingerprint VARCHAR(128)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Index is removed when table is
|
||||||
|
CREATE INDEX headers_block_number ON public.headers (block_number);
|
||||||
|
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE public.headers;
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
CREATE TABLE header_sync_receipts(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
transaction_id INTEGER NOT NULL REFERENCES header_sync_transactions(id) ON DELETE CASCADE,
|
|
||||||
header_id INTEGER NOT NULL REFERENCES headers(id) ON DELETE CASCADE,
|
|
||||||
contract_address VARCHAR(42),
|
|
||||||
cumulative_gas_used NUMERIC,
|
|
||||||
gas_used NUMERIC,
|
|
||||||
state_root VARCHAR(66),
|
|
||||||
status INTEGER,
|
|
||||||
tx_hash VARCHAR(66),
|
|
||||||
rlp BYTEA,
|
|
||||||
UNIQUE(header_id, transaction_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP TABLE header_sync_receipts;
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE header_sync_receipts
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
transaction_id INTEGER NOT NULL REFERENCES header_sync_transactions (id) ON DELETE CASCADE,
|
||||||
|
header_id INTEGER NOT NULL REFERENCES headers (id) ON DELETE CASCADE,
|
||||||
|
contract_address_id INTEGER NOT NULL REFERENCES addresses (id) ON DELETE CASCADE,
|
||||||
|
cumulative_gas_used NUMERIC,
|
||||||
|
gas_used NUMERIC,
|
||||||
|
state_root VARCHAR(66),
|
||||||
|
status INTEGER,
|
||||||
|
tx_hash VARCHAR(66),
|
||||||
|
rlp BYTEA,
|
||||||
|
UNIQUE (header_id, transaction_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE header_sync_receipts;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
-- +goose Up
|
||||||
|
-- SQL in this section is executed when the migration is applied.
|
||||||
|
CREATE TABLE header_sync_logs
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
header_id INTEGER NOT NULL REFERENCES headers (id) ON DELETE CASCADE,
|
||||||
|
address INTEGER NOT NULL REFERENCES addresses (id) ON DELETE CASCADE,
|
||||||
|
topics BYTEA[],
|
||||||
|
data BYTEA,
|
||||||
|
block_number BIGINT,
|
||||||
|
block_hash VARCHAR(66),
|
||||||
|
tx_hash VARCHAR(66),
|
||||||
|
tx_index INTEGER,
|
||||||
|
log_index INTEGER,
|
||||||
|
raw JSONB,
|
||||||
|
transformed BOOL NOT NULL DEFAULT FALSE,
|
||||||
|
UNIQUE (header_id, tx_index, log_index)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- SQL in this section is executed when the migration is rolled back.
|
||||||
|
DROP TABLE header_sync_logs;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
-- +goose Up
|
||||||
|
-- SQL in this section is executed when the migration is applied.
|
||||||
|
CREATE TABLE public.watched_logs
|
||||||
|
(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
contract_address VARCHAR(42),
|
||||||
|
topic_zero VARCHAR(66)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- SQL in this section is executed when the migration is rolled back.
|
||||||
|
DROP TABLE public.watched_logs;
|
||||||
+254
-59
@@ -2,8 +2,8 @@
|
|||||||
-- PostgreSQL database dump
|
-- PostgreSQL database dump
|
||||||
--
|
--
|
||||||
|
|
||||||
-- Dumped from database version 11.3
|
-- Dumped from database version 11.4
|
||||||
-- Dumped by pg_dump version 11.3
|
-- Dumped by pg_dump version 11.4
|
||||||
|
|
||||||
SET statement_timeout = 0;
|
SET statement_timeout = 0;
|
||||||
SET lock_timeout = 0;
|
SET lock_timeout = 0;
|
||||||
@@ -21,10 +21,40 @@ SET default_tablespace = '';
|
|||||||
SET default_with_oids = false;
|
SET default_with_oids = false;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: logs; Type: TABLE; Schema: public; Owner: -
|
-- Name: addresses; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|
||||||
CREATE TABLE public.logs (
|
CREATE TABLE public.addresses (
|
||||||
|
id integer NOT NULL,
|
||||||
|
address character varying(42)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: addresses_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.addresses_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: addresses_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.addresses_id_seq OWNED BY public.addresses.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: full_sync_logs; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.full_sync_logs (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
block_number bigint,
|
block_number bigint,
|
||||||
address character varying(66),
|
address character varying(66),
|
||||||
@@ -44,9 +74,9 @@ CREATE TABLE public.logs (
|
|||||||
--
|
--
|
||||||
|
|
||||||
CREATE VIEW public.block_stats AS
|
CREATE VIEW public.block_stats AS
|
||||||
SELECT max(logs.block_number) AS max_block,
|
SELECT max(full_sync_logs.block_number) AS max_block,
|
||||||
min(logs.block_number) AS min_block
|
min(full_sync_logs.block_number) AS min_block
|
||||||
FROM public.logs;
|
FROM public.full_sync_logs;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -138,13 +168,33 @@ CREATE TABLE public.eth_nodes (
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: full_sync_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.full_sync_logs_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: full_sync_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.full_sync_logs_id_seq OWNED BY public.full_sync_logs.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: full_sync_receipts; Type: TABLE; Schema: public; Owner: -
|
-- Name: full_sync_receipts; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|
||||||
CREATE TABLE public.full_sync_receipts (
|
CREATE TABLE public.full_sync_receipts (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
contract_address character varying(42),
|
contract_address_id integer NOT NULL,
|
||||||
cumulative_gas_used numeric,
|
cumulative_gas_used numeric,
|
||||||
gas_used numeric,
|
gas_used numeric,
|
||||||
state_root character varying(66),
|
state_root character varying(66),
|
||||||
@@ -246,6 +296,46 @@ CREATE SEQUENCE public.goose_db_version_id_seq
|
|||||||
ALTER SEQUENCE public.goose_db_version_id_seq OWNED BY public.goose_db_version.id;
|
ALTER SEQUENCE public.goose_db_version_id_seq OWNED BY public.goose_db_version.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_logs; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.header_sync_logs (
|
||||||
|
id integer NOT NULL,
|
||||||
|
header_id integer NOT NULL,
|
||||||
|
address integer NOT NULL,
|
||||||
|
topics bytea[],
|
||||||
|
data bytea,
|
||||||
|
block_number bigint,
|
||||||
|
block_hash character varying(66),
|
||||||
|
tx_hash character varying(66),
|
||||||
|
tx_index integer,
|
||||||
|
log_index integer,
|
||||||
|
raw jsonb,
|
||||||
|
transformed boolean DEFAULT false NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.header_sync_logs_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.header_sync_logs_id_seq OWNED BY public.header_sync_logs.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: header_sync_receipts; Type: TABLE; Schema: public; Owner: -
|
-- Name: header_sync_receipts; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -254,7 +344,7 @@ CREATE TABLE public.header_sync_receipts (
|
|||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
transaction_id integer NOT NULL,
|
transaction_id integer NOT NULL,
|
||||||
header_id integer NOT NULL,
|
header_id integer NOT NULL,
|
||||||
contract_address character varying(42),
|
contract_address_id integer NOT NULL,
|
||||||
cumulative_gas_used numeric,
|
cumulative_gas_used numeric,
|
||||||
gas_used numeric,
|
gas_used numeric,
|
||||||
state_root character varying(66),
|
state_root character varying(66),
|
||||||
@@ -334,6 +424,7 @@ CREATE TABLE public.headers (
|
|||||||
block_number bigint,
|
block_number bigint,
|
||||||
raw jsonb,
|
raw jsonb,
|
||||||
block_timestamp numeric,
|
block_timestamp numeric,
|
||||||
|
check_count integer DEFAULT 0 NOT NULL,
|
||||||
eth_node_id integer NOT NULL,
|
eth_node_id integer NOT NULL,
|
||||||
eth_node_fingerprint character varying(128)
|
eth_node_fingerprint character varying(128)
|
||||||
);
|
);
|
||||||
@@ -399,26 +490,6 @@ CREATE SEQUENCE public.log_filters_id_seq
|
|||||||
ALTER SEQUENCE public.log_filters_id_seq OWNED BY public.log_filters.id;
|
ALTER SEQUENCE public.log_filters_id_seq OWNED BY public.log_filters.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE SEQUENCE public.logs_id_seq
|
|
||||||
AS integer
|
|
||||||
START WITH 1
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MINVALUE
|
|
||||||
NO MAXVALUE
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER SEQUENCE public.logs_id_seq OWNED BY public.logs.id;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: nodes_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
-- Name: nodes_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -547,21 +618,59 @@ ALTER SEQUENCE public.watched_contracts_contract_id_seq OWNED BY public.watched_
|
|||||||
|
|
||||||
CREATE VIEW public.watched_event_logs AS
|
CREATE VIEW public.watched_event_logs AS
|
||||||
SELECT log_filters.name,
|
SELECT log_filters.name,
|
||||||
logs.id,
|
full_sync_logs.id,
|
||||||
logs.block_number,
|
full_sync_logs.block_number,
|
||||||
logs.address,
|
full_sync_logs.address,
|
||||||
logs.tx_hash,
|
full_sync_logs.tx_hash,
|
||||||
logs.index,
|
full_sync_logs.index,
|
||||||
logs.topic0,
|
full_sync_logs.topic0,
|
||||||
logs.topic1,
|
full_sync_logs.topic1,
|
||||||
logs.topic2,
|
full_sync_logs.topic2,
|
||||||
logs.topic3,
|
full_sync_logs.topic3,
|
||||||
logs.data,
|
full_sync_logs.data,
|
||||||
logs.receipt_id
|
full_sync_logs.receipt_id
|
||||||
FROM ((public.log_filters
|
FROM ((public.log_filters
|
||||||
CROSS JOIN public.block_stats)
|
CROSS JOIN public.block_stats)
|
||||||
JOIN public.logs ON ((((logs.address)::text = (log_filters.address)::text) AND (logs.block_number >= COALESCE(log_filters.from_block, block_stats.min_block)) AND (logs.block_number <= COALESCE(log_filters.to_block, block_stats.max_block)))))
|
JOIN public.full_sync_logs ON ((((full_sync_logs.address)::text = (log_filters.address)::text) AND (full_sync_logs.block_number >= COALESCE(log_filters.from_block, block_stats.min_block)) AND (full_sync_logs.block_number <= COALESCE(log_filters.to_block, block_stats.max_block)))))
|
||||||
WHERE ((((log_filters.topic0)::text = (logs.topic0)::text) OR (log_filters.topic0 IS NULL)) AND (((log_filters.topic1)::text = (logs.topic1)::text) OR (log_filters.topic1 IS NULL)) AND (((log_filters.topic2)::text = (logs.topic2)::text) OR (log_filters.topic2 IS NULL)) AND (((log_filters.topic3)::text = (logs.topic3)::text) OR (log_filters.topic3 IS NULL)));
|
WHERE ((((log_filters.topic0)::text = (full_sync_logs.topic0)::text) OR (log_filters.topic0 IS NULL)) AND (((log_filters.topic1)::text = (full_sync_logs.topic1)::text) OR (log_filters.topic1 IS NULL)) AND (((log_filters.topic2)::text = (full_sync_logs.topic2)::text) OR (log_filters.topic2 IS NULL)) AND (((log_filters.topic3)::text = (full_sync_logs.topic3)::text) OR (log_filters.topic3 IS NULL)));
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: watched_logs; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.watched_logs (
|
||||||
|
id integer NOT NULL,
|
||||||
|
contract_address character varying(42),
|
||||||
|
topic_zero character varying(66)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: watched_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.watched_logs_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: watched_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.watched_logs_id_seq OWNED BY public.watched_logs.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: addresses id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.addresses ALTER COLUMN id SET DEFAULT nextval('public.addresses_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -585,6 +694,13 @@ ALTER TABLE ONLY public.checked_headers ALTER COLUMN id SET DEFAULT nextval('pub
|
|||||||
ALTER TABLE ONLY public.eth_nodes ALTER COLUMN id SET DEFAULT nextval('public.nodes_id_seq'::regclass);
|
ALTER TABLE ONLY public.eth_nodes ALTER COLUMN id SET DEFAULT nextval('public.nodes_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: full_sync_logs id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.full_sync_logs ALTER COLUMN id SET DEFAULT nextval('public.full_sync_logs_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: full_sync_receipts id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: full_sync_receipts id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -606,6 +722,13 @@ ALTER TABLE ONLY public.full_sync_transactions ALTER COLUMN id SET DEFAULT nextv
|
|||||||
ALTER TABLE ONLY public.goose_db_version ALTER COLUMN id SET DEFAULT nextval('public.goose_db_version_id_seq'::regclass);
|
ALTER TABLE ONLY public.goose_db_version ALTER COLUMN id SET DEFAULT nextval('public.goose_db_version_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_logs id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.header_sync_logs ALTER COLUMN id SET DEFAULT nextval('public.header_sync_logs_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: header_sync_receipts id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: header_sync_receipts id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -634,13 +757,6 @@ ALTER TABLE ONLY public.headers ALTER COLUMN id SET DEFAULT nextval('public.head
|
|||||||
ALTER TABLE ONLY public.log_filters ALTER COLUMN id SET DEFAULT nextval('public.log_filters_id_seq'::regclass);
|
ALTER TABLE ONLY public.log_filters ALTER COLUMN id SET DEFAULT nextval('public.log_filters_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: logs id; Type: DEFAULT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.logs ALTER COLUMN id SET DEFAULT nextval('public.logs_id_seq'::regclass);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: queued_storage id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: queued_storage id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -662,6 +778,29 @@ ALTER TABLE ONLY public.uncles ALTER COLUMN id SET DEFAULT nextval('public.uncle
|
|||||||
ALTER TABLE ONLY public.watched_contracts ALTER COLUMN contract_id SET DEFAULT nextval('public.watched_contracts_contract_id_seq'::regclass);
|
ALTER TABLE ONLY public.watched_contracts ALTER COLUMN contract_id SET DEFAULT nextval('public.watched_contracts_contract_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: watched_logs id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.watched_logs ALTER COLUMN id SET DEFAULT nextval('public.watched_logs_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: addresses addresses_address_key; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.addresses
|
||||||
|
ADD CONSTRAINT addresses_address_key UNIQUE (address);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: addresses addresses_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.addresses
|
||||||
|
ADD CONSTRAINT addresses_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: blocks blocks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: blocks blocks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -702,6 +841,14 @@ ALTER TABLE ONLY public.eth_nodes
|
|||||||
ADD CONSTRAINT eth_node_uc UNIQUE (genesis_block, network_id, eth_node_id);
|
ADD CONSTRAINT eth_node_uc UNIQUE (genesis_block, network_id, eth_node_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: full_sync_logs full_sync_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.full_sync_logs
|
||||||
|
ADD CONSTRAINT full_sync_logs_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: full_sync_receipts full_sync_receipts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: full_sync_receipts full_sync_receipts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -726,6 +873,22 @@ ALTER TABLE ONLY public.goose_db_version
|
|||||||
ADD CONSTRAINT goose_db_version_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT goose_db_version_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_logs header_sync_logs_header_id_tx_index_log_index_key; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.header_sync_logs
|
||||||
|
ADD CONSTRAINT header_sync_logs_header_id_tx_index_log_index_key UNIQUE (header_id, tx_index, log_index);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_logs header_sync_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.header_sync_logs
|
||||||
|
ADD CONSTRAINT header_sync_logs_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: header_sync_receipts header_sync_receipts_header_id_transaction_id_key; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: header_sync_receipts header_sync_receipts_header_id_transaction_id_key; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -766,14 +929,6 @@ ALTER TABLE ONLY public.headers
|
|||||||
ADD CONSTRAINT headers_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT headers_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: logs logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.logs
|
|
||||||
ADD CONSTRAINT logs_pkey PRIMARY KEY (id);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: log_filters name_uc; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: log_filters name_uc; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -838,6 +993,14 @@ ALTER TABLE ONLY public.watched_contracts
|
|||||||
ADD CONSTRAINT watched_contracts_pkey PRIMARY KEY (contract_id);
|
ADD CONSTRAINT watched_contracts_pkey PRIMARY KEY (contract_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: watched_logs watched_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.watched_logs
|
||||||
|
ADD CONSTRAINT watched_logs_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: block_id_index; Type: INDEX; Schema: public; Owner: -
|
-- Name: block_id_index; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -896,6 +1059,14 @@ ALTER TABLE ONLY public.checked_headers
|
|||||||
ADD CONSTRAINT checked_headers_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
ADD CONSTRAINT checked_headers_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: full_sync_receipts full_sync_receipts_contract_address_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.full_sync_receipts
|
||||||
|
ADD CONSTRAINT full_sync_receipts_contract_address_id_fkey FOREIGN KEY (contract_address_id) REFERENCES public.addresses(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: full_sync_transactions full_sync_transactions_block_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: full_sync_transactions full_sync_transactions_block_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -904,6 +1075,30 @@ ALTER TABLE ONLY public.full_sync_transactions
|
|||||||
ADD CONSTRAINT full_sync_transactions_block_id_fkey FOREIGN KEY (block_id) REFERENCES public.blocks(id) ON DELETE CASCADE;
|
ADD CONSTRAINT full_sync_transactions_block_id_fkey FOREIGN KEY (block_id) REFERENCES public.blocks(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_logs header_sync_logs_address_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.header_sync_logs
|
||||||
|
ADD CONSTRAINT header_sync_logs_address_fkey FOREIGN KEY (address) REFERENCES public.addresses(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_logs header_sync_logs_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.header_sync_logs
|
||||||
|
ADD CONSTRAINT header_sync_logs_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: header_sync_receipts header_sync_receipts_contract_address_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.header_sync_receipts
|
||||||
|
ADD CONSTRAINT header_sync_receipts_contract_address_id_fkey FOREIGN KEY (contract_address_id) REFERENCES public.addresses(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: header_sync_receipts header_sync_receipts_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: header_sync_receipts header_sync_receipts_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -945,10 +1140,10 @@ ALTER TABLE ONLY public.blocks
|
|||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: logs receipts_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: full_sync_logs receipts_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|
||||||
ALTER TABLE ONLY public.logs
|
ALTER TABLE ONLY public.full_sync_logs
|
||||||
ADD CONSTRAINT receipts_fk FOREIGN KEY (receipt_id) REFERENCES public.full_sync_receipts(id) ON DELETE CASCADE;
|
ADD CONSTRAINT receipts_fk FOREIGN KEY (receipt_id) REFERENCES public.full_sync_receipts(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,63 +3,55 @@ module github.com/vulcanize/vulcanizedb
|
|||||||
go 1.12
|
go 1.12
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
github.com/allegro/bigcache v1.2.1 // indirect
|
||||||
github.com/allegro/bigcache v1.1.0 // indirect
|
github.com/aristanetworks/goarista v0.0.0-20190712234253-ed1100a1c015 // indirect
|
||||||
github.com/apilayer/freegeoip v3.5.0+incompatible // indirect
|
|
||||||
github.com/aristanetworks/goarista v0.0.0-20180907105523-ff33da284e76 // indirect
|
|
||||||
github.com/btcsuite/btcd v0.0.0-20180903232927-cff30e1d23fc // indirect
|
|
||||||
github.com/cespare/cp v1.1.1 // indirect
|
|
||||||
github.com/dave/jennifer v1.3.0
|
github.com/dave/jennifer v1.3.0
|
||||||
github.com/deckarep/golang-set v1.7.1 // indirect
|
github.com/deckarep/golang-set v1.7.1 // indirect
|
||||||
github.com/docker/docker v1.13.1 // indirect
|
|
||||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||||
github.com/elastic/gosigar v0.10.4 // indirect
|
github.com/elastic/gosigar v0.10.4 // indirect
|
||||||
github.com/ethereum/go-ethereum v1.9.0
|
github.com/ethereum/go-ethereum v1.9.5
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||||
github.com/go-sql-driver/mysql v1.4.1 // indirect
|
github.com/go-sql-driver/mysql v1.4.1 // indirect
|
||||||
github.com/golang/protobuf v1.3.2 // indirect
|
github.com/golang/protobuf v1.3.2 // indirect
|
||||||
github.com/google/uuid v1.0.0 // indirect
|
github.com/gorilla/websocket v1.4.1 // indirect
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20190610161739-8f92f34fc598 // indirect
|
github.com/hashicorp/golang-lru v0.5.3
|
||||||
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47
|
|
||||||
github.com/howeyc/fsnotify v0.9.0 // indirect
|
github.com/howeyc/fsnotify v0.9.0 // indirect
|
||||||
github.com/hpcloud/tail v1.0.0
|
github.com/hpcloud/tail v1.0.0
|
||||||
github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324 // indirect
|
github.com/huin/goupnp v1.0.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
|
||||||
github.com/influxdata/influxdb v1.7.7 // indirect
|
|
||||||
github.com/jackpal/go-nat-pmp v1.0.1 // indirect
|
github.com/jackpal/go-nat-pmp v1.0.1 // indirect
|
||||||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0
|
github.com/jmoiron/sqlx v0.0.0-20181024163419-82935fac6c1a
|
||||||
github.com/karalabe/usb v0.0.0-20190703133951-9be757f914c0 // indirect
|
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8 // indirect
|
||||||
github.com/lib/pq v1.0.0
|
github.com/lib/pq v1.0.0
|
||||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.9 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.11.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/go-homedir v1.0.0
|
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
|
||||||
github.com/olekukonko/tablewriter v0.0.1 // indirect
|
github.com/olekukonko/tablewriter v0.0.1 // indirect
|
||||||
github.com/onsi/ginkgo v1.6.0
|
github.com/onsi/ginkgo v1.7.0
|
||||||
github.com/onsi/gomega v1.4.2
|
github.com/onsi/gomega v1.4.3
|
||||||
github.com/oschwald/maxminddb-golang v1.3.1 // indirect
|
github.com/pborman/uuid v1.2.0 // indirect
|
||||||
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 // indirect
|
|
||||||
github.com/pkg/errors v0.8.1 // indirect
|
|
||||||
github.com/pressly/goose v2.6.0+incompatible
|
github.com/pressly/goose v2.6.0+incompatible
|
||||||
github.com/prometheus/tsdb v0.9.1 // indirect
|
github.com/prometheus/tsdb v0.10.0 // indirect
|
||||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
github.com/rjeczalik/notify v0.9.2 // indirect
|
||||||
github.com/rs/cors v1.5.0 // indirect
|
github.com/rs/cors v1.7.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.2.0
|
github.com/sirupsen/logrus v1.2.0
|
||||||
github.com/spf13/cobra v0.0.3
|
github.com/spf13/cobra v0.0.3
|
||||||
github.com/spf13/viper v1.2.0
|
github.com/spf13/viper v1.3.2
|
||||||
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 // indirect
|
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 // indirect
|
||||||
github.com/steakknife/bloomfilter v0.0.0-20180906043351-99ee86d9200f // indirect
|
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 // indirect
|
||||||
github.com/steakknife/hamming v0.0.0-20180906055317-003c143a81c2 // indirect
|
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
|
||||||
github.com/syndtr/goleveldb v0.0.0-20180815032940-ae2bd5eed72d // indirect
|
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||||
github.com/tyler-smith/go-bip39 v1.0.0 // indirect
|
github.com/tyler-smith/go-bip39 v1.0.2 // indirect
|
||||||
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 // indirect
|
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20190926114937-fa1a29108794 // indirect
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||||
google.golang.org/appengine v1.6.1 // indirect
|
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
|
||||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff // indirect
|
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
|
||||||
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
|
gopkg.in/urfave/cli.v1 v1.0.0-00010101000000-000000000000 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace github.com/ethereum/go-ethereum => github.com/vulcanize/go-ethereum v0.0.0-20190731183759-8e20673bd101
|
||||||
|
|
||||||
|
replace gopkg.in/urfave/cli.v1 => gopkg.in/urfave/cli.v1 v1.20.0
|
||||||
|
|||||||
@@ -1,23 +1,40 @@
|
|||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/allegro/bigcache v1.1.0 h1:MLuIKTjdxDc+qsG2rhjsYjsHQC5LUGjIWzutg7M+W68=
|
|
||||||
github.com/allegro/bigcache v1.1.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
github.com/allegro/bigcache v1.1.0/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||||
|
github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
|
||||||
|
github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||||
github.com/apilayer/freegeoip v3.5.0+incompatible h1:z1u2gv0/rsSi/HqMDB436AiUROXXim7st5DOg4Ikl4A=
|
github.com/apilayer/freegeoip v3.5.0+incompatible h1:z1u2gv0/rsSi/HqMDB436AiUROXXim7st5DOg4Ikl4A=
|
||||||
github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU=
|
github.com/apilayer/freegeoip v3.5.0+incompatible/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU=
|
||||||
github.com/aristanetworks/goarista v0.0.0-20180907105523-ff33da284e76 h1:64W/KrGykPTfDI9xTkZtnjZRYA5p2+c/IuGgjzeWCpI=
|
|
||||||
github.com/aristanetworks/goarista v0.0.0-20180907105523-ff33da284e76/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
|
github.com/aristanetworks/goarista v0.0.0-20180907105523-ff33da284e76/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
|
||||||
|
github.com/aristanetworks/goarista v0.0.0-20190121184617-8f049bdb8feb/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
|
||||||
|
github.com/aristanetworks/goarista v0.0.0-20190712234253-ed1100a1c015 h1:7ABPr1+uJdqESAdlVevnc/2FJGiC/K3uMg1JiELeF+0=
|
||||||
|
github.com/aristanetworks/goarista v0.0.0-20190712234253-ed1100a1c015/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/btcsuite/btcd v0.0.0-20180903232927-cff30e1d23fc h1:nLRj+ULuRYb0qTAOnuayFXRnLjYXBots5CSp5zH4RqU=
|
|
||||||
github.com/btcsuite/btcd v0.0.0-20180903232927-cff30e1d23fc/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
|
github.com/btcsuite/btcd v0.0.0-20180903232927-cff30e1d23fc/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
|
||||||
|
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d h1:xG8Pj6Y6J760xwETNmMzmlt38QSwz0BLp1cZ09g27uw=
|
||||||
|
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
|
||||||
|
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||||
|
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||||
|
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||||
|
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||||
|
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||||
|
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||||
|
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||||
github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=
|
github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU=
|
||||||
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/dave/jennifer v1.3.0 h1:p3tl41zjjCZTNBytMwrUuiAnherNUZktlhPTKoF/sEk=
|
github.com/dave/jennifer v1.3.0 h1:p3tl41zjjCZTNBytMwrUuiAnherNUZktlhPTKoF/sEk=
|
||||||
github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||||
|
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -30,8 +47,11 @@ github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
|
|||||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo=
|
github.com/elastic/gosigar v0.10.4 h1:6jfw75dsoflhBMRdO6QPzQUgLqUYTsQQQRkkcsHsuPo=
|
||||||
github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
|
github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
|
||||||
github.com/ethereum/go-ethereum v1.9.0 h1:9Kaf7UfDkV3aIUJlf14hI/GgEgRAUq60u4fBlb9dLWw=
|
|
||||||
github.com/ethereum/go-ethereum v1.9.0/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
|
github.com/ethereum/go-ethereum v1.9.0/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
|
||||||
|
github.com/ethereum/go-ethereum v1.9.1 h1:MrdTRvKIa3apdx6NW1azzSgl8BQB1eTBVSUmFhuztaU=
|
||||||
|
github.com/ethereum/go-ethereum v1.9.1/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
|
||||||
|
github.com/ethereum/go-ethereum v1.9.5 h1:4oxsF+/3N/sTgda9XTVG4r+wMVLsveziSMcK83hPbsk=
|
||||||
|
github.com/ethereum/go-ethereum v1.9.5/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
|
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
@@ -42,65 +62,96 @@ github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
|||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
|
github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||||
|
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
|
github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20190610161739-8f92f34fc598 h1:XLoCW/kXxbvPvp216Kq/c+TtwWYHy9sjeDidFcG45g0=
|
github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s=
|
||||||
|
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||||
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||||
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20190610161739-8f92f34fc598/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4=
|
github.com/graph-gophers/graphql-go v0.0.0-20190610161739-8f92f34fc598/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4=
|
||||||
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47 h1:UnszMmmmm5vLwWzDjTFVIkfhvWF1NdrmChl8L2NUDCw=
|
github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6 h1:9WiNlI9Cds5S5YITwRpRs8edNaq0nxTEymhDW20A1QE=
|
||||||
|
github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6/go.mod h1:Au3iQ8DvDis8hZ4q2OzRcaKYlAsPt+fYvib5q4nIqu4=
|
||||||
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/howeyc/fsnotify v0.9.0 h1:0gtV5JmOKH4A8SsFxG2BczSeXWWPvcMT0euZt5gDAxY=
|
github.com/howeyc/fsnotify v0.9.0 h1:0gtV5JmOKH4A8SsFxG2BczSeXWWPvcMT0euZt5gDAxY=
|
||||||
github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA=
|
github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324 h1:PV190X5/DzQ/tbFFG5YpT5mH6q+cHlfgqI5JuRnH9oE=
|
|
||||||
github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
|
github.com/huin/goupnp v0.0.0-20180415215157-1395d1447324/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
|
||||||
|
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
|
||||||
|
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
|
||||||
|
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/influxdata/influxdb v1.7.7 h1:UvNzAPfBrKMENVbQ4mr4ccA9sW+W1Ihl0Yh1s0BiVAg=
|
github.com/influxdata/influxdb v1.7.7 h1:UvNzAPfBrKMENVbQ4mr4ccA9sW+W1Ihl0Yh1s0BiVAg=
|
||||||
github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA=
|
github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0 h1:5B0uxl2lzNRVkJVg+uGHxWtRt4C0Wjc6kJKo5XYx8xE=
|
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
|
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
|
||||||
|
github.com/jmoiron/sqlx v0.0.0-20181024163419-82935fac6c1a h1:Jyg5PpIc1nLGrNDM5blVkiSySmRhaD/IiXkvaHzBYnw=
|
||||||
|
github.com/jmoiron/sqlx v0.0.0-20181024163419-82935fac6c1a/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||||
|
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
|
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/karalabe/usb v0.0.0-20190703133951-9be757f914c0 h1:S8kWZLXHpcOq3nGAvIs0oDgd4CXxkxE3hkDVRjTu7ro=
|
|
||||||
github.com/karalabe/usb v0.0.0-20190703133951-9be757f914c0/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
github.com/karalabe/usb v0.0.0-20190703133951-9be757f914c0/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||||
|
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8 h1:VhnqxaTIudc9IWKx8uXRLnpdSb9noCEj+vHacjmhp68=
|
||||||
|
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||||
|
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||||
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||||
|
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
||||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
|
||||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.0.0 h1:vVpGvMXJPqSDh2VYHF7gsfQj8Ncx+Xw5Y1KHeTRY+7I=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||||
@@ -111,16 +162,21 @@ github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8u
|
|||||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
|
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
|
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/oschwald/maxminddb-golang v1.3.1 h1:kPc5+ieL5CC/Zn0IaXJPxDFlUxKTQEU8QBTtmfQDAIo=
|
github.com/oschwald/maxminddb-golang v1.3.1 h1:kPc5+ieL5CC/Zn0IaXJPxDFlUxKTQEU8QBTtmfQDAIo=
|
||||||
github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY=
|
github.com/oschwald/maxminddb-golang v1.3.1/go.mod h1:3jhIUymTJ5VREKyIhWm66LJiQt04F0UCDdodShpjWsY=
|
||||||
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 h1:zNBQb37RGLmJybyMcs983HfUfpkw9OTFD9tbBfAViHE=
|
|
||||||
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
|
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
|
||||||
|
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
|
||||||
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@@ -135,49 +191,77 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
|
|||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/tsdb v0.9.1 h1:IWaAmWkYlgG7/S4iw4IpAQt5Y35QaZM6/GsZ7GsjAuk=
|
|
||||||
github.com/prometheus/tsdb v0.9.1/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
|
github.com/prometheus/tsdb v0.9.1/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
|
||||||
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
|
github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
|
||||||
|
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
|
||||||
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
|
||||||
github.com/rs/cors v1.5.0 h1:dgSHE6+ia18arGOTIYQKKGWLvEbGvmbNE6NfxhoNHUY=
|
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
|
||||||
|
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
|
||||||
github.com/rs/cors v1.5.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
github.com/rs/cors v1.5.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||||
|
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||||
|
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||||
|
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/cast v1.2.0 h1:HHl1DSRbEQN2i8tJmtS6ViPyHx35+p51amrdsiTCrkg=
|
github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M=
|
||||||
|
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||||
|
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
|
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
|
|
||||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/viper v1.2.0 h1:M4Rzxlu+RgU4pyBRKhKaVN1VeYOm8h2jgyXnAseDgCc=
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/viper v1.2.0/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
|
github.com/spf13/viper v1.2.0/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
|
||||||
|
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
|
||||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw=
|
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw=
|
||||||
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
||||||
github.com/steakknife/bloomfilter v0.0.0-20180906043351-99ee86d9200f h1:T7YHzO3/eqD/kv5m9+TLM4XuEAkN7NPj5pnZHqaOo/Q=
|
|
||||||
github.com/steakknife/bloomfilter v0.0.0-20180906043351-99ee86d9200f/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
|
github.com/steakknife/bloomfilter v0.0.0-20180906043351-99ee86d9200f/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
|
||||||
github.com/steakknife/hamming v0.0.0-20180906055317-003c143a81c2 h1:o6NMd68tuqfQ0ZFnz2d16xzFNLWxrCvqF40InOJJHSM=
|
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=
|
||||||
|
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
|
||||||
github.com/steakknife/hamming v0.0.0-20180906055317-003c143a81c2/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
|
github.com/steakknife/hamming v0.0.0-20180906055317-003c143a81c2/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
|
||||||
|
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
|
||||||
|
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/syndtr/goleveldb v0.0.0-20180815032940-ae2bd5eed72d h1:4J9HCZVpvDmj2tiKGSTUnb3Ok/9CEQb9oqu9LHKQQpc=
|
|
||||||
github.com/syndtr/goleveldb v0.0.0-20180815032940-ae2bd5eed72d/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
github.com/syndtr/goleveldb v0.0.0-20180815032940-ae2bd5eed72d/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||||
github.com/tyler-smith/go-bip39 v1.0.0 h1:FOHg9gaQLeBBRbHE/QrTLfEiBHy5pQ/yXzf9JG5pYFM=
|
github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2 h1:GnOzE5fEFN3b2zDhJJABEofdb51uMRNb8eqIVtdducs=
|
||||||
|
github.com/syndtr/goleveldb v0.0.0-20181128100959-b001fa50d6b2/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
github.com/tyler-smith/go-bip39 v1.0.0/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
github.com/tyler-smith/go-bip39 v1.0.0/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||||
|
github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8=
|
||||||
|
github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||||
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
|
github.com/vulcanize/go-ethereum v0.0.0-20190731183759-8e20673bd101 h1:fsHhBzscAwi4u7/F033SFJwTIz+46D8uDWMu2/ZdvzA=
|
||||||
|
github.com/vulcanize/go-ethereum v0.0.0-20190731183759-8e20673bd101 h1:fsHhBzscAwi4u7/F033SFJwTIz+46D8uDWMu2/ZdvzA=
|
||||||
|
github.com/vulcanize/go-ethereum v0.0.0-20190731183759-8e20673bd101/go.mod h1:9i0pGnKDUFFr8yC/n8xyrNBVfhYlpwE8J3Ge6ThKvug=
|
||||||
|
github.com/vulcanize/go-ethereum v0.0.0-20190731183759-8e20673bd101/go.mod h1:9i0pGnKDUFFr8yC/n8xyrNBVfhYlpwE8J3Ge6ThKvug=
|
||||||
|
github.com/vulcanize/vulcanizedb v0.0.5/go.mod h1:utXkheCL9VjTfmuivuvRiAAyHh54GSN9XRQNEbFCA8k=
|
||||||
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
|
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
|
||||||
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
||||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190926114937-fa1a29108794 h1:4Yo9XtTfxfBCecLiBW8TYsFIdN7TkDhjGLWetFo4JSo=
|
||||||
|
golang.org/x/crypto v0.0.0-20190926114937-fa1a29108794/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
@@ -193,14 +277,20 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5 h1:mzjBh+S5frKOsOBobWIMAbXavqjmgO17k/2puhcFR94=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5 h1:mzjBh+S5frKOsOBobWIMAbXavqjmgO17k/2puhcFR94=
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c h1:+EXw7AwNOKzPFXMZ1yNjO40aWCh3PIquJB2fYlv9wcs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c h1:+EXw7AwNOKzPFXMZ1yNjO40aWCh3PIquJB2fYlv9wcs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69 h1:rOhMmluY6kLMhdnrivzec6lLgaVbMHMn2ISQXJeJ5EM=
|
||||||
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
@@ -224,3 +314,5 @@ gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
|
|||||||
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
|
||||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
|
|
||||||
Describe("Getting a contract attribute", func() {
|
Describe("Getting a contract attribute", func() {
|
||||||
It("retrieves the event log for a specific block and contract", func() {
|
It("retrieves the event log for a specific block and contract", func() {
|
||||||
expectedLogZero := core.Log{
|
expectedLogZero := core.FullSyncLog{
|
||||||
BlockNumber: 4703824,
|
BlockNumber: 4703824,
|
||||||
TxHash: "0xf896bfd1eb539d881a1a31102b78de9f25cd591bf1fe1924b86148c0b205fd5d",
|
TxHash: "0xf896bfd1eb539d881a1a31102b78de9f25cd591bf1fe1924b86148c0b205fd5d",
|
||||||
Address: "0xd26114cd6ee289accf82350c8d8487fedb8a0c07",
|
Address: "0xd26114cd6ee289accf82350c8d8487fedb8a0c07",
|
||||||
@@ -59,7 +59,7 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
contract := testing.SampleContract()
|
contract := testing.SampleContract()
|
||||||
|
|
||||||
logs, err := blockChain.GetLogs(contract, big.NewInt(4703824), nil)
|
logs, err := blockChain.GetFullSyncLogs(contract, big.NewInt(4703824), nil)
|
||||||
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(len(logs)).To(Equal(3))
|
Expect(len(logs)).To(Equal(3))
|
||||||
@@ -76,7 +76,7 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
|
|
||||||
logs, err := blockChain.GetLogs(core.Contract{Hash: "0x123"}, big.NewInt(4703824), nil)
|
logs, err := blockChain.GetFullSyncLogs(core.Contract{Hash: "0x123"}, big.NewInt(4703824), nil)
|
||||||
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(len(logs)).To(Equal(0))
|
Expect(len(logs)).To(Equal(0))
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -17,17 +17,15 @@
|
|||||||
package chunker
|
package chunker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Chunker interface {
|
type Chunker interface {
|
||||||
AddConfigs(transformerConfigs []shared_t.EventTransformerConfig)
|
AddConfig(transformerConfig transformer.EventTransformerConfig)
|
||||||
ChunkLogs(logs []types.Log) map[string][]types.Log
|
ChunkLogs(logs []core.HeaderSyncLog) map[string][]core.HeaderSyncLog
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogChunker struct {
|
type LogChunker struct {
|
||||||
@@ -44,27 +42,25 @@ func NewLogChunker() *LogChunker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configures the chunker by adding more addreses and topics to consider.
|
// Configures the chunker by adding one config with more addresses and topics to consider.
|
||||||
func (chunker *LogChunker) AddConfigs(transformerConfigs []shared_t.EventTransformerConfig) {
|
func (chunker *LogChunker) AddConfig(transformerConfig transformer.EventTransformerConfig) {
|
||||||
for _, config := range transformerConfigs {
|
for _, address := range transformerConfig.ContractAddresses {
|
||||||
for _, address := range config.ContractAddresses {
|
var lowerCaseAddress = strings.ToLower(address)
|
||||||
var lowerCaseAddress = strings.ToLower(address)
|
chunker.AddressToNames[lowerCaseAddress] = append(chunker.AddressToNames[lowerCaseAddress], transformerConfig.TransformerName)
|
||||||
chunker.AddressToNames[lowerCaseAddress] = append(chunker.AddressToNames[lowerCaseAddress], config.TransformerName)
|
chunker.NameToTopic0[transformerConfig.TransformerName] = common.HexToHash(transformerConfig.Topic)
|
||||||
chunker.NameToTopic0[config.TransformerName] = common.HexToHash(config.Topic)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Goes through an array of logs, associating relevant logs (matching addresses and topic) with transformers
|
// Goes through a slice of logs, associating relevant logs (matching addresses and topic) with transformers
|
||||||
func (chunker *LogChunker) ChunkLogs(logs []types.Log) map[string][]types.Log {
|
func (chunker *LogChunker) ChunkLogs(logs []core.HeaderSyncLog) map[string][]core.HeaderSyncLog {
|
||||||
chunks := map[string][]types.Log{}
|
chunks := map[string][]core.HeaderSyncLog{}
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
// Topic0 is not unique to each transformer, also need to consider the contract address
|
// Topic0 is not unique to each transformer, also need to consider the contract address
|
||||||
relevantTransformers := chunker.AddressToNames[strings.ToLower(log.Address.String())]
|
relevantTransformers := chunker.AddressToNames[strings.ToLower(log.Log.Address.Hex())]
|
||||||
|
|
||||||
for _, transformer := range relevantTransformers {
|
for _, t := range relevantTransformers {
|
||||||
if chunker.NameToTopic0[transformer] == log.Topics[0] {
|
if chunker.NameToTopic0[t] == log.Log.Topics[0] {
|
||||||
chunks[transformer] = append(chunks[transformer], log)
|
chunks[t] = append(chunks[t], log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,38 +21,39 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
chunk "github.com/vulcanize/vulcanizedb/libraries/shared/chunker"
|
chunk "github.com/vulcanize/vulcanizedb/libraries/shared/chunker"
|
||||||
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Log chunker", func() {
|
var _ = Describe("Log chunker", func() {
|
||||||
var (
|
var (
|
||||||
configs []shared_t.EventTransformerConfig
|
|
||||||
chunker *chunk.LogChunker
|
chunker *chunk.LogChunker
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
configA := shared_t.EventTransformerConfig{
|
chunker = chunk.NewLogChunker()
|
||||||
|
|
||||||
|
configA := transformer.EventTransformerConfig{
|
||||||
TransformerName: "TransformerA",
|
TransformerName: "TransformerA",
|
||||||
ContractAddresses: []string{"0x00000000000000000000000000000000000000A1", "0x00000000000000000000000000000000000000A2"},
|
ContractAddresses: []string{"0x00000000000000000000000000000000000000A1", "0x00000000000000000000000000000000000000A2"},
|
||||||
Topic: "0xA",
|
Topic: "0xA",
|
||||||
}
|
}
|
||||||
configB := shared_t.EventTransformerConfig{
|
chunker.AddConfig(configA)
|
||||||
|
|
||||||
|
configB := transformer.EventTransformerConfig{
|
||||||
TransformerName: "TransformerB",
|
TransformerName: "TransformerB",
|
||||||
ContractAddresses: []string{"0x00000000000000000000000000000000000000B1"},
|
ContractAddresses: []string{"0x00000000000000000000000000000000000000B1"},
|
||||||
Topic: "0xB",
|
Topic: "0xB",
|
||||||
}
|
}
|
||||||
|
chunker.AddConfig(configB)
|
||||||
|
|
||||||
configC := shared_t.EventTransformerConfig{
|
configC := transformer.EventTransformerConfig{
|
||||||
TransformerName: "TransformerC",
|
TransformerName: "TransformerC",
|
||||||
ContractAddresses: []string{"0x00000000000000000000000000000000000000A2"},
|
ContractAddresses: []string{"0x00000000000000000000000000000000000000A2"},
|
||||||
Topic: "0xC",
|
Topic: "0xC",
|
||||||
}
|
}
|
||||||
|
chunker.AddConfig(configC)
|
||||||
configs = []shared_t.EventTransformerConfig{configA, configB, configC}
|
|
||||||
chunker = chunk.NewLogChunker()
|
|
||||||
chunker.AddConfigs(configs)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("initialisation", func() {
|
Describe("initialisation", func() {
|
||||||
@@ -71,26 +72,26 @@ var _ = Describe("Log chunker", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("AddConfigs", func() {
|
Describe("AddConfig", func() {
|
||||||
It("can add more configs later", func() {
|
It("can add more configs later", func() {
|
||||||
configD := shared_t.EventTransformerConfig{
|
configD := transformer.EventTransformerConfig{
|
||||||
TransformerName: "TransformerD",
|
TransformerName: "TransformerD",
|
||||||
ContractAddresses: []string{"0x000000000000000000000000000000000000000D"},
|
ContractAddresses: []string{"0x000000000000000000000000000000000000000D"},
|
||||||
Topic: "0xD",
|
Topic: "0xD",
|
||||||
}
|
}
|
||||||
chunker.AddConfigs([]shared_t.EventTransformerConfig{configD})
|
chunker.AddConfig(configD)
|
||||||
|
|
||||||
Expect(chunker.AddressToNames).To(ContainElement([]string{"TransformerD"}))
|
Expect(chunker.AddressToNames).To(ContainElement([]string{"TransformerD"}))
|
||||||
Expect(chunker.NameToTopic0).To(ContainElement(common.HexToHash("0xD")))
|
Expect(chunker.NameToTopic0).To(ContainElement(common.HexToHash("0xD")))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("lower cases address", func() {
|
It("lower cases address", func() {
|
||||||
configD := shared_t.EventTransformerConfig{
|
configD := transformer.EventTransformerConfig{
|
||||||
TransformerName: "TransformerD",
|
TransformerName: "TransformerD",
|
||||||
ContractAddresses: []string{"0x000000000000000000000000000000000000000D"},
|
ContractAddresses: []string{"0x000000000000000000000000000000000000000D"},
|
||||||
Topic: "0xD",
|
Topic: "0xD",
|
||||||
}
|
}
|
||||||
chunker.AddConfigs([]shared_t.EventTransformerConfig{configD})
|
chunker.AddConfig(configD)
|
||||||
|
|
||||||
Expect(chunker.AddressToNames["0x000000000000000000000000000000000000000d"]).To(Equal([]string{"TransformerD"}))
|
Expect(chunker.AddressToNames["0x000000000000000000000000000000000000000d"]).To(Equal([]string{"TransformerD"}))
|
||||||
})
|
})
|
||||||
@@ -98,7 +99,7 @@ var _ = Describe("Log chunker", func() {
|
|||||||
|
|
||||||
Describe("ChunkLogs", func() {
|
Describe("ChunkLogs", func() {
|
||||||
It("only associates logs with relevant topic0 and address to transformers", func() {
|
It("only associates logs with relevant topic0 and address to transformers", func() {
|
||||||
logs := []types.Log{log1, log2, log3, log4, log5}
|
logs := []core.HeaderSyncLog{log1, log2, log3, log4, log5}
|
||||||
chunks := chunker.ChunkLogs(logs)
|
chunks := chunker.ChunkLogs(logs)
|
||||||
|
|
||||||
Expect(chunks["TransformerA"]).To(And(ContainElement(log1), ContainElement(log4)))
|
Expect(chunks["TransformerA"]).To(And(ContainElement(log1), ContainElement(log4)))
|
||||||
@@ -110,43 +111,53 @@ var _ = Describe("Log chunker", func() {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// Match TransformerA
|
// Match TransformerA
|
||||||
log1 = types.Log{
|
log1 = core.HeaderSyncLog{
|
||||||
Address: common.HexToAddress("0xA1"),
|
Log: types.Log{
|
||||||
Topics: []common.Hash{
|
Address: common.HexToAddress("0xA1"),
|
||||||
common.HexToHash("0xA"),
|
Topics: []common.Hash{
|
||||||
common.HexToHash("0xLogTopic1"),
|
common.HexToHash("0xA"),
|
||||||
|
common.HexToHash("0xLogTopic1"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Match TransformerA address, but not topic0
|
// Match TransformerA address, but not topic0
|
||||||
log2 = types.Log{
|
log2 = core.HeaderSyncLog{
|
||||||
Address: common.HexToAddress("0xA1"),
|
Log: types.Log{
|
||||||
Topics: []common.Hash{
|
Address: common.HexToAddress("0xA1"),
|
||||||
common.HexToHash("0xB"),
|
Topics: []common.Hash{
|
||||||
common.HexToHash("0xLogTopic2"),
|
common.HexToHash("0xB"),
|
||||||
|
common.HexToHash("0xLogTopic2"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Match TransformerA topic, but TransformerB address
|
// Match TransformerA topic, but TransformerB address
|
||||||
log3 = types.Log{
|
log3 = core.HeaderSyncLog{
|
||||||
Address: common.HexToAddress("0xB1"),
|
Log: types.Log{
|
||||||
Topics: []common.Hash{
|
Address: common.HexToAddress("0xB1"),
|
||||||
common.HexToHash("0xA"),
|
Topics: []common.Hash{
|
||||||
common.HexToHash("0xLogTopic3"),
|
common.HexToHash("0xA"),
|
||||||
|
common.HexToHash("0xLogTopic3"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Match TransformerA, with the other address
|
// Match TransformerA, with the other address
|
||||||
log4 = types.Log{
|
log4 = core.HeaderSyncLog{
|
||||||
Address: common.HexToAddress("0xA2"),
|
Log: types.Log{
|
||||||
Topics: []common.Hash{
|
Address: common.HexToAddress("0xA2"),
|
||||||
common.HexToHash("0xA"),
|
Topics: []common.Hash{
|
||||||
common.HexToHash("0xLogTopic4"),
|
common.HexToHash("0xA"),
|
||||||
|
common.HexToHash("0xLogTopic4"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Match TransformerC, which shares address with TransformerA
|
// Match TransformerC, which shares address with TransformerA
|
||||||
log5 = types.Log{
|
log5 = core.HeaderSyncLog{
|
||||||
Address: common.HexToAddress("0xA2"),
|
Log: types.Log{
|
||||||
Topics: []common.Hash{
|
Address: common.HexToAddress("0xA2"),
|
||||||
common.HexToHash("0xC"),
|
Topics: []common.Hash{
|
||||||
common.HexToHash("0xLogTopic5"),
|
common.HexToHash("0xC"),
|
||||||
|
common.HexToHash("0xLogTopic5"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ type TransformerExecution bool
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
HeaderRecheck TransformerExecution = true
|
HeaderRecheck TransformerExecution = true
|
||||||
HeaderMissing TransformerExecution = false
|
HeaderUnchecked TransformerExecution = false
|
||||||
RecheckHeaderCap = "4"
|
RecheckHeaderCap = int64(5)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
package event
|
package event
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/core/types"
|
import "github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
|
||||||
type Converter interface {
|
type Converter interface {
|
||||||
ToEntities(contractAbi string, ethLog []types.Log) ([]interface{}, error)
|
ToEntities(contractAbi string, ethLog []core.HeaderSyncLog) ([]interface{}, error)
|
||||||
ToModels([]interface{}) ([]interface{}, error)
|
ToModels([]interface{}) ([]interface{}, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,9 @@
|
|||||||
|
|
||||||
package event
|
package event
|
||||||
|
|
||||||
import (
|
import "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
Create(headerID int64, models []interface{}) error
|
Create(models []interface{}) error
|
||||||
MarkHeaderChecked(headerID int64) error
|
|
||||||
SetDB(db *postgres.DB)
|
SetDB(db *postgres.DB)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,7 @@
|
|||||||
package event
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/sirupsen/logrus"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
@@ -36,34 +34,29 @@ func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.Event
|
|||||||
return transformer
|
return transformer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer Transformer) Execute(logs []types.Log, header core.Header) error {
|
func (transformer Transformer) Execute(logs []core.HeaderSyncLog) error {
|
||||||
transformerName := transformer.Config.TransformerName
|
transformerName := transformer.Config.TransformerName
|
||||||
config := transformer.Config
|
config := transformer.Config
|
||||||
|
|
||||||
if len(logs) < 1 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
entities, err := transformer.Converter.ToEntities(config.ContractAbi, logs)
|
entities, err := transformer.Converter.ToEntities(config.ContractAbi, logs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error converting logs to entities in %v: %v", transformerName, err)
|
logrus.Errorf("error converting logs to entities in %v: %v", transformerName, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
models, err := transformer.Converter.ToModels(entities)
|
models, err := transformer.Converter.ToModels(entities)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error converting entities to models in %v: %v", transformerName, err)
|
logrus.Errorf("error converting entities to models in %v: %v", transformerName, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = transformer.Repository.Create(header.Id, models)
|
err = transformer.Repository.Create(models)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error persisting %v record: %v", transformerName, err)
|
logrus.Errorf("error persisting %v record: %v", transformerName, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,32 +17,29 @@
|
|||||||
package event_test
|
package event_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/factories/event"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/factories/event"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/test_data"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/test_data"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Transformer", func() {
|
var _ = Describe("Transformer", func() {
|
||||||
var (
|
var (
|
||||||
repository mocks.MockRepository
|
repository mocks.MockEventRepository
|
||||||
converter mocks.MockConverter
|
converter mocks.MockConverter
|
||||||
t transformer.EventTransformer
|
t transformer.EventTransformer
|
||||||
headerOne core.Header
|
headerOne core.Header
|
||||||
config = test_data.GenericTestConfig
|
config = test_data.GenericTestConfig
|
||||||
logs = test_data.GenericTestLogs
|
logs []core.HeaderSyncLog
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
repository = mocks.MockRepository{}
|
repository = mocks.MockEventRepository{}
|
||||||
converter = mocks.MockConverter{}
|
converter = mocks.MockConverter{}
|
||||||
|
|
||||||
t = event.Transformer{
|
t = event.Transformer{
|
||||||
@@ -52,21 +49,21 @@ var _ = Describe("Transformer", func() {
|
|||||||
}.NewTransformer(nil)
|
}.NewTransformer(nil)
|
||||||
|
|
||||||
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
|
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
|
||||||
|
|
||||||
|
logs = []core.HeaderSyncLog{{
|
||||||
|
ID: 0,
|
||||||
|
HeaderID: headerOne.Id,
|
||||||
|
Log: test_data.GenericTestLog(),
|
||||||
|
Transformed: false,
|
||||||
|
}}
|
||||||
})
|
})
|
||||||
|
|
||||||
It("sets the db", func() {
|
It("sets the db", func() {
|
||||||
Expect(repository.SetDbCalled).To(BeTrue())
|
Expect(repository.SetDbCalled).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("marks header checked if no logs returned", func() {
|
|
||||||
err := t.Execute([]types.Log{}, headerOne)
|
|
||||||
|
|
||||||
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() {
|
It("doesn't attempt to convert or persist an empty collection when there are no logs", func() {
|
||||||
err := t.Execute([]types.Log{}, headerOne)
|
err := t.Execute([]core.HeaderSyncLog{})
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(converter.ToEntitiesCalledCounter).To(Equal(0))
|
Expect(converter.ToEntitiesCalledCounter).To(Equal(0))
|
||||||
@@ -74,24 +71,8 @@ var _ = Describe("Transformer", func() {
|
|||||||
Expect(repository.CreateCalledCounter).To(Equal(0))
|
Expect(repository.CreateCalledCounter).To(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("does not call repository.MarkCheckedHeader when there are logs", func() {
|
|
||||||
err := t.Execute(logs, headerOne)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
repository.AssertMarkHeaderCheckedNotCalled()
|
|
||||||
})
|
|
||||||
|
|
||||||
It("returns error if marking header checked returns err", func() {
|
|
||||||
repository.SetMarkHeaderCheckedError(fakes.FakeError)
|
|
||||||
|
|
||||||
err := t.Execute([]types.Log{}, headerOne)
|
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("converts an eth log to an entity", func() {
|
It("converts an eth log to an entity", func() {
|
||||||
err := t.Execute(logs, headerOne)
|
err := t.Execute(logs)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(converter.ContractAbi).To(Equal(config.ContractAbi))
|
Expect(converter.ContractAbi).To(Equal(config.ContractAbi))
|
||||||
@@ -101,7 +82,7 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("returns an error if converter fails", func() {
|
It("returns an error if converter fails", func() {
|
||||||
converter.ToEntitiesError = fakes.FakeError
|
converter.ToEntitiesError = fakes.FakeError
|
||||||
|
|
||||||
err := t.Execute(logs, headerOne)
|
err := t.Execute(logs)
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
@@ -110,7 +91,7 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("converts an entity to a model", func() {
|
It("converts an entity to a model", func() {
|
||||||
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
||||||
|
|
||||||
err := t.Execute(logs, headerOne)
|
err := t.Execute(logs)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(converter.EntitiesToConvert[0]).To(Equal(test_data.GenericEntity{}))
|
Expect(converter.EntitiesToConvert[0]).To(Equal(test_data.GenericEntity{}))
|
||||||
@@ -120,7 +101,7 @@ var _ = Describe("Transformer", func() {
|
|||||||
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
||||||
converter.ToModelsError = fakes.FakeError
|
converter.ToModelsError = fakes.FakeError
|
||||||
|
|
||||||
err := t.Execute(logs, headerOne)
|
err := t.Execute(logs)
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
@@ -129,16 +110,15 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("persists the record", func() {
|
It("persists the record", func() {
|
||||||
converter.ModelsToReturn = []interface{}{test_data.GenericModel{}}
|
converter.ModelsToReturn = []interface{}{test_data.GenericModel{}}
|
||||||
|
|
||||||
err := t.Execute(logs, headerOne)
|
err := t.Execute(logs)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
|
|
||||||
Expect(repository.PassedModels[0]).To(Equal(test_data.GenericModel{}))
|
Expect(repository.PassedModels[0]).To(Equal(test_data.GenericModel{}))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns error if persisting the record fails", func() {
|
It("returns error if persisting the record fails", func() {
|
||||||
repository.SetCreateError(fakes.FakeError)
|
repository.SetCreateError(fakes.FakeError)
|
||||||
err := t.Execute(logs, headerOne)
|
err := t.Execute(logs)
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
|||||||
+2
-2
@@ -14,14 +14,14 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package repository
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StorageRepository interface {
|
type Repository interface {
|
||||||
Create(blockNumber int, blockHash string, metadata utils.StorageValueMetadata, value interface{}) error
|
Create(blockNumber int, blockHash string, metadata utils.StorageValueMetadata, value interface{}) error
|
||||||
SetDB(db *postgres.DB)
|
SetDB(db *postgres.DB)
|
||||||
}
|
}
|
||||||
@@ -18,8 +18,6 @@ package storage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
@@ -27,9 +25,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Transformer struct {
|
type Transformer struct {
|
||||||
Address common.Address
|
HashedAddress common.Hash
|
||||||
Mappings storage.Mappings
|
Mappings storage.Mappings
|
||||||
Repository repository.StorageRepository
|
Repository Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.StorageTransformer {
|
func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.StorageTransformer {
|
||||||
@@ -38,18 +36,18 @@ func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.Stora
|
|||||||
return transformer
|
return transformer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer Transformer) ContractAddress() common.Address {
|
func (transformer Transformer) KeccakContractAddress() common.Hash {
|
||||||
return transformer.Address
|
return transformer.HashedAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer Transformer) Execute(row utils.StorageDiffRow) error {
|
func (transformer Transformer) Execute(diff utils.StorageDiff) error {
|
||||||
metadata, lookupErr := transformer.Mappings.Lookup(row.StorageKey)
|
metadata, lookupErr := transformer.Mappings.Lookup(diff.StorageKey)
|
||||||
if lookupErr != nil {
|
if lookupErr != nil {
|
||||||
return lookupErr
|
return lookupErr
|
||||||
}
|
}
|
||||||
value, decodeErr := utils.Decode(row, metadata)
|
value, decodeErr := utils.Decode(diff, metadata)
|
||||||
if decodeErr != nil {
|
if decodeErr != nil {
|
||||||
return decodeErr
|
return decodeErr
|
||||||
}
|
}
|
||||||
return transformer.Repository.Create(row.BlockHeight, row.BlockHash.Hex(), metadata, value)
|
return transformer.Repository.Create(diff.BlockHeight, diff.BlockHash.Hex(), metadata, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/factories/storage"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/factories/storage"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
@@ -38,21 +37,21 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
mappings = &mocks.MockMappings{}
|
mappings = &mocks.MockMappings{}
|
||||||
repository = &mocks.MockStorageRepository{}
|
repository = &mocks.MockStorageRepository{}
|
||||||
t = storage.Transformer{
|
t = storage.Transformer{
|
||||||
Address: common.Address{},
|
HashedAddress: common.Hash{},
|
||||||
Mappings: mappings,
|
Mappings: mappings,
|
||||||
Repository: repository,
|
Repository: repository,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns the contract address being watched", func() {
|
It("returns the contract address being watched", func() {
|
||||||
fakeAddress := common.HexToAddress("0x12345")
|
fakeAddress := utils.HexToKeccak256Hash("0x12345")
|
||||||
t.Address = fakeAddress
|
t.HashedAddress = fakeAddress
|
||||||
|
|
||||||
Expect(t.ContractAddress()).To(Equal(fakeAddress))
|
Expect(t.KeccakContractAddress()).To(Equal(fakeAddress))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("looks up metadata for storage key", func() {
|
It("looks up metadata for storage key", func() {
|
||||||
t.Execute(utils.StorageDiffRow{})
|
t.Execute(utils.StorageDiff{})
|
||||||
|
|
||||||
Expect(mappings.LookupCalled).To(BeTrue())
|
Expect(mappings.LookupCalled).To(BeTrue())
|
||||||
})
|
})
|
||||||
@@ -60,7 +59,7 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
It("returns error if lookup fails", func() {
|
It("returns error if lookup fails", func() {
|
||||||
mappings.LookupErr = fakes.FakeError
|
mappings.LookupErr = fakes.FakeError
|
||||||
|
|
||||||
err := t.Execute(utils.StorageDiffRow{})
|
err := t.Execute(utils.StorageDiff{})
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
@@ -72,12 +71,12 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
rawValue := common.HexToAddress("0x12345")
|
rawValue := common.HexToAddress("0x12345")
|
||||||
fakeBlockNumber := 123
|
fakeBlockNumber := 123
|
||||||
fakeBlockHash := "0x67890"
|
fakeBlockHash := "0x67890"
|
||||||
fakeRow := utils.StorageDiffRow{
|
fakeRow := utils.StorageDiff{
|
||||||
Contract: common.Address{},
|
HashedAddress: common.Hash{},
|
||||||
BlockHash: common.HexToHash(fakeBlockHash),
|
BlockHash: common.HexToHash(fakeBlockHash),
|
||||||
BlockHeight: fakeBlockNumber,
|
BlockHeight: fakeBlockNumber,
|
||||||
StorageKey: common.Hash{},
|
StorageKey: common.Hash{},
|
||||||
StorageValue: rawValue.Hash(),
|
StorageValue: rawValue.Hash(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := t.Execute(fakeRow)
|
err := t.Execute(fakeRow)
|
||||||
@@ -95,7 +94,7 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
mappings.Metadata = fakeMetadata
|
mappings.Metadata = fakeMetadata
|
||||||
repository.CreateErr = fakes.FakeError
|
repository.CreateErr = fakes.FakeError
|
||||||
|
|
||||||
err := t.Execute(utils.StorageDiffRow{StorageValue: rawValue.Hash()})
|
err := t.Execute(utils.StorageDiff{StorageValue: rawValue.Hash()})
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
@@ -120,12 +119,12 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
|
|
||||||
It("passes the decoded data items to the repository", func() {
|
It("passes the decoded data items to the repository", func() {
|
||||||
mappings.Metadata = fakeMetadata
|
mappings.Metadata = fakeMetadata
|
||||||
fakeRow := utils.StorageDiffRow{
|
fakeRow := utils.StorageDiff{
|
||||||
Contract: common.Address{},
|
HashedAddress: common.Hash{},
|
||||||
BlockHash: common.HexToHash(fakeBlockHash),
|
BlockHash: common.HexToHash(fakeBlockHash),
|
||||||
BlockHeight: fakeBlockNumber,
|
BlockHeight: fakeBlockNumber,
|
||||||
StorageKey: common.Hash{},
|
StorageKey: common.Hash{},
|
||||||
StorageValue: rawValue.Hash(),
|
StorageValue: rawValue.Hash(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := t.Execute(fakeRow)
|
err := t.Execute(fakeRow)
|
||||||
@@ -144,7 +143,7 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
mappings.Metadata = fakeMetadata
|
mappings.Metadata = fakeMetadata
|
||||||
repository.CreateErr = fakes.FakeError
|
repository.CreateErr = fakes.FakeError
|
||||||
|
|
||||||
err := t.Execute(utils.StorageDiffRow{StorageValue: rawValue.Hash()})
|
err := t.Execute(utils.StorageDiff{StorageValue: rawValue.Hash()})
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
|||||||
+6
-12
@@ -17,18 +17,12 @@
|
|||||||
package fetcher
|
package fetcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IStorageFetcher interface {
|
|
||||||
FetchStorageDiffs(chan<- utils.StorageDiffRow, chan<- error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type CsvTailStorageFetcher struct {
|
type CsvTailStorageFetcher struct {
|
||||||
tailer fs.Tailer
|
tailer fs.Tailer
|
||||||
}
|
}
|
||||||
@@ -37,18 +31,18 @@ func NewCsvTailStorageFetcher(tailer fs.Tailer) CsvTailStorageFetcher {
|
|||||||
return CsvTailStorageFetcher{tailer: tailer}
|
return CsvTailStorageFetcher{tailer: tailer}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storageFetcher CsvTailStorageFetcher) FetchStorageDiffs(out chan<- utils.StorageDiffRow, errs chan<- error) {
|
func (storageFetcher CsvTailStorageFetcher) FetchStorageDiffs(out chan<- utils.StorageDiff, errs chan<- error) {
|
||||||
t, tailErr := storageFetcher.tailer.Tail()
|
t, tailErr := storageFetcher.tailer.Tail()
|
||||||
if tailErr != nil {
|
if tailErr != nil {
|
||||||
errs <- tailErr
|
errs <- tailErr
|
||||||
}
|
}
|
||||||
log.Debug("fetching storage diffs...")
|
logrus.Debug("fetching storage diffs...")
|
||||||
for line := range t.Lines {
|
for line := range t.Lines {
|
||||||
row, parseErr := utils.FromStrings(strings.Split(line.Text, ","))
|
diff, parseErr := utils.FromParityCsvRow(strings.Split(line.Text, ","))
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
errs <- parseErr
|
errs <- parseErr
|
||||||
} else {
|
} else {
|
||||||
out <- row
|
out <- diff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+10
-12
@@ -18,30 +18,28 @@ package fetcher_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/hpcloud/tail"
|
"github.com/hpcloud/tail"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Csv Tail Storage Fetcher", func() {
|
var _ = Describe("Csv Tail Storage Fetcher", func() {
|
||||||
var (
|
var (
|
||||||
errorsChannel chan error
|
errorsChannel chan error
|
||||||
mockTailer *fakes.MockTailer
|
mockTailer *fakes.MockTailer
|
||||||
rowsChannel chan utils.StorageDiffRow
|
diffsChannel chan utils.StorageDiff
|
||||||
storageFetcher fetcher.CsvTailStorageFetcher
|
storageFetcher fetcher.CsvTailStorageFetcher
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
errorsChannel = make(chan error)
|
errorsChannel = make(chan error)
|
||||||
rowsChannel = make(chan utils.StorageDiffRow)
|
diffsChannel = make(chan utils.StorageDiff)
|
||||||
mockTailer = fakes.NewMockTailer()
|
mockTailer = fakes.NewMockTailer()
|
||||||
storageFetcher = fetcher.NewCsvTailStorageFetcher(mockTailer)
|
storageFetcher = fetcher.NewCsvTailStorageFetcher(mockTailer)
|
||||||
})
|
})
|
||||||
@@ -49,7 +47,7 @@ var _ = Describe("Csv Tail Storage Fetcher", func() {
|
|||||||
It("adds error to errors channel if tailing file fails", func(done Done) {
|
It("adds error to errors channel if tailing file fails", func(done Done) {
|
||||||
mockTailer.TailErr = fakes.FakeError
|
mockTailer.TailErr = fakes.FakeError
|
||||||
|
|
||||||
go storageFetcher.FetchStorageDiffs(rowsChannel, errorsChannel)
|
go storageFetcher.FetchStorageDiffs(diffsChannel, errorsChannel)
|
||||||
|
|
||||||
Expect(<-errorsChannel).To(MatchError(fakes.FakeError))
|
Expect(<-errorsChannel).To(MatchError(fakes.FakeError))
|
||||||
close(done)
|
close(done)
|
||||||
@@ -58,24 +56,24 @@ var _ = Describe("Csv Tail Storage Fetcher", func() {
|
|||||||
It("adds parsed csv row to rows channel for storage diff", func(done Done) {
|
It("adds parsed csv row to rows channel for storage diff", func(done Done) {
|
||||||
line := getFakeLine()
|
line := getFakeLine()
|
||||||
|
|
||||||
go storageFetcher.FetchStorageDiffs(rowsChannel, errorsChannel)
|
go storageFetcher.FetchStorageDiffs(diffsChannel, errorsChannel)
|
||||||
mockTailer.Lines <- line
|
mockTailer.Lines <- line
|
||||||
|
|
||||||
expectedRow, err := utils.FromStrings(strings.Split(line.Text, ","))
|
expectedRow, err := utils.FromParityCsvRow(strings.Split(line.Text, ","))
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(<-rowsChannel).To(Equal(expectedRow))
|
Expect(<-diffsChannel).To(Equal(expectedRow))
|
||||||
close(done)
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("adds error to errors channel if parsing csv fails", func(done Done) {
|
It("adds error to errors channel if parsing csv fails", func(done Done) {
|
||||||
line := &tail.Line{Text: "invalid"}
|
line := &tail.Line{Text: "invalid"}
|
||||||
|
|
||||||
go storageFetcher.FetchStorageDiffs(rowsChannel, errorsChannel)
|
go storageFetcher.FetchStorageDiffs(diffsChannel, errorsChannel)
|
||||||
mockTailer.Lines <- line
|
mockTailer.Lines <- line
|
||||||
|
|
||||||
Expect(<-errorsChannel).To(HaveOccurred())
|
Expect(<-errorsChannel).To(HaveOccurred())
|
||||||
select {
|
select {
|
||||||
case <-rowsChannel:
|
case <-diffsChannel:
|
||||||
Fail("value passed to rows channel on error")
|
Fail("value passed to rows channel on error")
|
||||||
default:
|
default:
|
||||||
Succeed()
|
Succeed()
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2019 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package fetcher
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/streamer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GethRpcStorageFetcher struct {
|
||||||
|
statediffPayloadChan chan statediff.Payload
|
||||||
|
streamer streamer.Streamer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGethRpcStorageFetcher(streamer streamer.Streamer, statediffPayloadChan chan statediff.Payload) GethRpcStorageFetcher {
|
||||||
|
return GethRpcStorageFetcher{
|
||||||
|
statediffPayloadChan: statediffPayloadChan,
|
||||||
|
streamer: streamer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fetcher GethRpcStorageFetcher) FetchStorageDiffs(out chan<- utils.StorageDiff, errs chan<- error) {
|
||||||
|
ethStatediffPayloadChan := fetcher.statediffPayloadChan
|
||||||
|
clientSubscription, clientSubErr := fetcher.streamer.Stream(ethStatediffPayloadChan)
|
||||||
|
if clientSubErr != nil {
|
||||||
|
errs <- clientSubErr
|
||||||
|
panic(fmt.Sprintf("Error creating a geth client subscription: %v", clientSubErr))
|
||||||
|
}
|
||||||
|
logrus.Info("Successfully created a geth client subscription: ", clientSubscription)
|
||||||
|
|
||||||
|
for {
|
||||||
|
diff := <-ethStatediffPayloadChan
|
||||||
|
logrus.Trace("received a statediff")
|
||||||
|
stateDiff := new(statediff.StateDiff)
|
||||||
|
decodeErr := rlp.DecodeBytes(diff.StateDiffRlp, stateDiff)
|
||||||
|
if decodeErr != nil {
|
||||||
|
logrus.Warn("Error decoding state diff into RLP: ", decodeErr)
|
||||||
|
errs <- decodeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
accounts := getAccountsFromDiff(*stateDiff)
|
||||||
|
logrus.Trace(fmt.Sprintf("iterating through %d accounts on stateDiff for block %d", len(accounts), stateDiff.BlockNumber))
|
||||||
|
for _, account := range accounts {
|
||||||
|
logrus.Trace(fmt.Sprintf("iterating through %d Storage values on account", len(account.Storage)))
|
||||||
|
for _, storage := range account.Storage {
|
||||||
|
diff, formatErr := utils.FromGethStateDiff(account, stateDiff, storage)
|
||||||
|
logrus.Trace("adding storage diff to out channel",
|
||||||
|
"keccak of address: ", diff.HashedAddress.Hex(),
|
||||||
|
"block height: ", diff.BlockHeight,
|
||||||
|
"storage key: ", diff.StorageKey.Hex(),
|
||||||
|
"storage value: ", diff.StorageValue.Hex())
|
||||||
|
if formatErr != nil {
|
||||||
|
errs <- formatErr
|
||||||
|
}
|
||||||
|
|
||||||
|
out <- diff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAccountsFromDiff(stateDiff statediff.StateDiff) []statediff.AccountDiff {
|
||||||
|
accounts := append(stateDiff.CreatedAccounts, stateDiff.UpdatedAccounts...)
|
||||||
|
return append(accounts, stateDiff.DeletedAccounts...)
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
// Copyright 2019 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package fetcher_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/test_data"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockStoragediffStreamer struct {
|
||||||
|
subscribeError error
|
||||||
|
PassedPayloadChan chan statediff.Payload
|
||||||
|
streamPayloads []statediff.Payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func (streamer *MockStoragediffStreamer) Stream(statediffPayloadChan chan statediff.Payload) (*rpc.ClientSubscription, error) {
|
||||||
|
clientSubscription := rpc.ClientSubscription{}
|
||||||
|
streamer.PassedPayloadChan = statediffPayloadChan
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for _, payload := range streamer.streamPayloads {
|
||||||
|
streamer.PassedPayloadChan <- payload
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return &clientSubscription, streamer.subscribeError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (streamer *MockStoragediffStreamer) SetSubscribeError(err error) {
|
||||||
|
streamer.subscribeError = err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (streamer *MockStoragediffStreamer) SetPayloads(payloads []statediff.Payload) {
|
||||||
|
streamer.streamPayloads = payloads
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = Describe("Geth RPC Storage Fetcher", func() {
|
||||||
|
var streamer MockStoragediffStreamer
|
||||||
|
var statediffPayloadChan chan statediff.Payload
|
||||||
|
var statediffFetcher fetcher.GethRpcStorageFetcher
|
||||||
|
var storagediffChan chan utils.StorageDiff
|
||||||
|
var errorChan chan error
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
streamer = MockStoragediffStreamer{}
|
||||||
|
statediffPayloadChan = make(chan statediff.Payload, 1)
|
||||||
|
statediffFetcher = fetcher.NewGethRpcStorageFetcher(&streamer, statediffPayloadChan)
|
||||||
|
storagediffChan = make(chan utils.StorageDiff)
|
||||||
|
errorChan = make(chan error)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("adds errors to error channel if the RPC subscription fails and panics", func(done Done) {
|
||||||
|
streamer.SetSubscribeError(fakes.FakeError)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
failedSub := func() {
|
||||||
|
statediffFetcher.FetchStorageDiffs(storagediffChan, errorChan)
|
||||||
|
}
|
||||||
|
Expect(failedSub).To(Panic())
|
||||||
|
}()
|
||||||
|
|
||||||
|
Expect(<-errorChan).To(MatchError(fakes.FakeError))
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("streams StatediffPayloads from a Geth RPC subscription", func(done Done) {
|
||||||
|
streamer.SetPayloads([]statediff.Payload{test_data.MockStatediffPayload})
|
||||||
|
|
||||||
|
go statediffFetcher.FetchStorageDiffs(storagediffChan, errorChan)
|
||||||
|
|
||||||
|
streamedPayload := <-statediffPayloadChan
|
||||||
|
Expect(streamedPayload).To(Equal(test_data.MockStatediffPayload))
|
||||||
|
Expect(streamer.PassedPayloadChan).To(Equal(statediffPayloadChan))
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("adds errors to error channel if decoding the state diff RLP fails", func(done Done) {
|
||||||
|
badStatediffPayload := statediff.Payload{}
|
||||||
|
streamer.SetPayloads([]statediff.Payload{badStatediffPayload})
|
||||||
|
|
||||||
|
go statediffFetcher.FetchStorageDiffs(storagediffChan, errorChan)
|
||||||
|
|
||||||
|
Expect(<-errorChan).To(MatchError("EOF"))
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("adds parsed statediff payloads to the rows channel", func(done Done) {
|
||||||
|
streamer.SetPayloads([]statediff.Payload{test_data.MockStatediffPayload})
|
||||||
|
|
||||||
|
go statediffFetcher.FetchStorageDiffs(storagediffChan, errorChan)
|
||||||
|
|
||||||
|
height := test_data.BlockNumber
|
||||||
|
intHeight := int(height.Int64())
|
||||||
|
createdExpectedStorageDiff := utils.StorageDiff{
|
||||||
|
HashedAddress: common.BytesToHash(test_data.ContractLeafKey[:]),
|
||||||
|
BlockHash: common.HexToHash("0xfa40fbe2d98d98b3363a778d52f2bcd29d6790b9b3f3cab2b167fd12d3550f73"),
|
||||||
|
BlockHeight: intHeight,
|
||||||
|
StorageKey: common.BytesToHash(test_data.StorageKey),
|
||||||
|
StorageValue: common.BytesToHash(test_data.SmallStorageValue),
|
||||||
|
}
|
||||||
|
updatedExpectedStorageDiff := utils.StorageDiff{
|
||||||
|
HashedAddress: common.BytesToHash(test_data.AnotherContractLeafKey[:]),
|
||||||
|
BlockHash: common.HexToHash("0xfa40fbe2d98d98b3363a778d52f2bcd29d6790b9b3f3cab2b167fd12d3550f73"),
|
||||||
|
BlockHeight: intHeight,
|
||||||
|
StorageKey: common.BytesToHash(test_data.StorageKey),
|
||||||
|
StorageValue: common.BytesToHash(test_data.LargeStorageValue),
|
||||||
|
}
|
||||||
|
deletedExpectedStorageDiff := utils.StorageDiff{
|
||||||
|
HashedAddress: common.BytesToHash(test_data.AnotherContractLeafKey[:]),
|
||||||
|
BlockHash: common.HexToHash("0xfa40fbe2d98d98b3363a778d52f2bcd29d6790b9b3f3cab2b167fd12d3550f73"),
|
||||||
|
BlockHeight: intHeight,
|
||||||
|
StorageKey: common.BytesToHash(test_data.StorageKey),
|
||||||
|
StorageValue: common.BytesToHash(test_data.SmallStorageValue),
|
||||||
|
}
|
||||||
|
|
||||||
|
createdStateDiff := <-storagediffChan
|
||||||
|
updatedStateDiff := <-storagediffChan
|
||||||
|
deletedStateDiff := <-storagediffChan
|
||||||
|
|
||||||
|
Expect(createdStateDiff).To(Equal(createdExpectedStorageDiff))
|
||||||
|
Expect(updatedStateDiff).To(Equal(updatedExpectedStorageDiff))
|
||||||
|
Expect(deletedStateDiff).To(Equal(deletedExpectedStorageDiff))
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("adds errors to error channel if formatting the diff as a StateDiff object fails", func(done Done) {
|
||||||
|
accountDiffs := test_data.CreatedAccountDiffs
|
||||||
|
accountDiffs[0].Storage = []statediff.StorageDiff{test_data.StorageWithBadValue}
|
||||||
|
|
||||||
|
stateDiff := statediff.StateDiff{
|
||||||
|
BlockNumber: test_data.BlockNumber,
|
||||||
|
BlockHash: common.HexToHash(test_data.BlockHash),
|
||||||
|
CreatedAccounts: accountDiffs,
|
||||||
|
}
|
||||||
|
|
||||||
|
stateDiffRlp, err := rlp.EncodeToBytes(stateDiff)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
badStatediffPayload := statediff.Payload{
|
||||||
|
StateDiffRlp: stateDiffRlp,
|
||||||
|
}
|
||||||
|
streamer.SetPayloads([]statediff.Payload{badStatediffPayload})
|
||||||
|
|
||||||
|
go statediffFetcher.FetchStorageDiffs(storagediffChan, errorChan)
|
||||||
|
|
||||||
|
Expect(<-errorChan).To(MatchError("rlp: input contains more than one value"))
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
type ILogFetcher interface {
|
type ILogFetcher interface {
|
||||||
FetchLogs(contractAddresses []common.Address, topics []common.Hash, missingHeader core.Header) ([]types.Log, error)
|
FetchLogs(contractAddresses []common.Address, topics []common.Hash, missingHeader core.Header) ([]types.Log, error)
|
||||||
|
// TODO Extend FetchLogs for doing several blocks at a time
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogFetcher struct {
|
type LogFetcher struct {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2018 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package fetcher
|
||||||
|
|
||||||
|
import "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
|
||||||
|
type IStorageFetcher interface {
|
||||||
|
FetchStorageDiffs(out chan<- utils.StorageDiff, errs chan<- error)
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/chunker"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoLogs = errors.New("no logs available for transforming")
|
||||||
|
ErrNoTransformers = errors.New("no event transformers configured in the log delegator")
|
||||||
|
)
|
||||||
|
|
||||||
|
type ILogDelegator interface {
|
||||||
|
AddTransformer(t transformer.EventTransformer)
|
||||||
|
DelegateLogs() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogDelegator struct {
|
||||||
|
Chunker chunker.Chunker
|
||||||
|
LogRepository datastore.HeaderSyncLogRepository
|
||||||
|
Transformers []transformer.EventTransformer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (delegator *LogDelegator) AddTransformer(t transformer.EventTransformer) {
|
||||||
|
delegator.Transformers = append(delegator.Transformers, t)
|
||||||
|
delegator.Chunker.AddConfig(t.GetConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (delegator *LogDelegator) DelegateLogs() error {
|
||||||
|
if len(delegator.Transformers) < 1 {
|
||||||
|
return ErrNoTransformers
|
||||||
|
}
|
||||||
|
|
||||||
|
persistedLogs, fetchErr := delegator.LogRepository.GetUntransformedHeaderSyncLogs()
|
||||||
|
if fetchErr != nil {
|
||||||
|
logrus.Errorf("error loading logs from db: %s", fetchErr.Error())
|
||||||
|
return fetchErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(persistedLogs) < 1 {
|
||||||
|
return ErrNoLogs
|
||||||
|
}
|
||||||
|
|
||||||
|
transformErr := delegator.delegateLogs(persistedLogs)
|
||||||
|
if transformErr != nil {
|
||||||
|
logrus.Errorf("error transforming logs: %s", transformErr)
|
||||||
|
return transformErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (delegator *LogDelegator) delegateLogs(logs []core.HeaderSyncLog) error {
|
||||||
|
chunkedLogs := delegator.Chunker.ChunkLogs(logs)
|
||||||
|
for _, t := range delegator.Transformers {
|
||||||
|
transformerName := t.GetConfig().TransformerName
|
||||||
|
logChunk := chunkedLogs[transformerName]
|
||||||
|
err := t.Execute(logChunk)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("%v transformer failed to execute in watcher: %v", transformerName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 logs_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/libraries/shared/chunker"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/logs"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Log delegator", func() {
|
||||||
|
Describe("AddTransformer", func() {
|
||||||
|
It("adds transformers to the delegator", func() {
|
||||||
|
fakeTransformer := &mocks.MockEventTransformer{}
|
||||||
|
delegator := logs.LogDelegator{Chunker: chunker.NewLogChunker()}
|
||||||
|
|
||||||
|
delegator.AddTransformer(fakeTransformer)
|
||||||
|
|
||||||
|
Expect(delegator.Transformers).To(Equal([]transformer.EventTransformer{fakeTransformer}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("passes transformers' configs to the chunker", func() {
|
||||||
|
fakeTransformer := &mocks.MockEventTransformer{}
|
||||||
|
fakeConfig := mocks.FakeTransformerConfig
|
||||||
|
fakeTransformer.SetTransformerConfig(fakeConfig)
|
||||||
|
chunker := chunker.NewLogChunker()
|
||||||
|
delegator := logs.LogDelegator{Chunker: chunker}
|
||||||
|
|
||||||
|
delegator.AddTransformer(fakeTransformer)
|
||||||
|
|
||||||
|
expectedName := fakeConfig.TransformerName
|
||||||
|
expectedTopic := common.HexToHash(fakeConfig.Topic)
|
||||||
|
Expect(chunker.NameToTopic0).To(Equal(map[string]common.Hash{expectedName: expectedTopic}))
|
||||||
|
expectedAddress := strings.ToLower(fakeConfig.ContractAddresses[0])
|
||||||
|
Expect(chunker.AddressToNames).To(Equal(map[string][]string{expectedAddress: {expectedName}}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("DelegateLogs", func() {
|
||||||
|
It("returns error if no transformers configured", func() {
|
||||||
|
delegator := newDelegator(&fakes.MockHeaderSyncLogRepository{})
|
||||||
|
|
||||||
|
err := delegator.DelegateLogs()
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(logs.ErrNoTransformers))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets untransformed logs", func() {
|
||||||
|
mockLogRepository := &fakes.MockHeaderSyncLogRepository{}
|
||||||
|
mockLogRepository.ReturnLogs = []core.HeaderSyncLog{{}}
|
||||||
|
delegator := newDelegator(mockLogRepository)
|
||||||
|
delegator.AddTransformer(&mocks.MockEventTransformer{})
|
||||||
|
|
||||||
|
err := delegator.DelegateLogs()
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(mockLogRepository.GetCalled).To(BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if getting untransformed logs fails", func() {
|
||||||
|
mockLogRepository := &fakes.MockHeaderSyncLogRepository{}
|
||||||
|
mockLogRepository.GetError = fakes.FakeError
|
||||||
|
delegator := newDelegator(mockLogRepository)
|
||||||
|
delegator.AddTransformer(&mocks.MockEventTransformer{})
|
||||||
|
|
||||||
|
err := delegator.DelegateLogs()
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error that no logs were found if no logs returned", func() {
|
||||||
|
delegator := newDelegator(&fakes.MockHeaderSyncLogRepository{})
|
||||||
|
delegator.AddTransformer(&mocks.MockEventTransformer{})
|
||||||
|
|
||||||
|
err := delegator.DelegateLogs()
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(logs.ErrNoLogs))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("delegates chunked logs to transformers", func() {
|
||||||
|
fakeTransformer := &mocks.MockEventTransformer{}
|
||||||
|
config := mocks.FakeTransformerConfig
|
||||||
|
fakeTransformer.SetTransformerConfig(config)
|
||||||
|
fakeGethLog := types.Log{
|
||||||
|
Address: common.HexToAddress(config.ContractAddresses[0]),
|
||||||
|
Topics: []common.Hash{common.HexToHash(config.Topic)},
|
||||||
|
}
|
||||||
|
fakeHeaderSyncLogs := []core.HeaderSyncLog{{Log: fakeGethLog}}
|
||||||
|
mockLogRepository := &fakes.MockHeaderSyncLogRepository{}
|
||||||
|
mockLogRepository.ReturnLogs = fakeHeaderSyncLogs
|
||||||
|
delegator := newDelegator(mockLogRepository)
|
||||||
|
delegator.AddTransformer(fakeTransformer)
|
||||||
|
|
||||||
|
err := delegator.DelegateLogs()
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(fakeTransformer.ExecuteWasCalled).To(BeTrue())
|
||||||
|
Expect(fakeTransformer.PassedLogs).To(Equal(fakeHeaderSyncLogs))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if transformer returns an error", func() {
|
||||||
|
mockLogRepository := &fakes.MockHeaderSyncLogRepository{}
|
||||||
|
mockLogRepository.ReturnLogs = []core.HeaderSyncLog{{}}
|
||||||
|
delegator := newDelegator(mockLogRepository)
|
||||||
|
fakeTransformer := &mocks.MockEventTransformer{ExecuteError: fakes.FakeError}
|
||||||
|
delegator.AddTransformer(fakeTransformer)
|
||||||
|
|
||||||
|
err := delegator.DelegateLogs()
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns nil for error when logs returned and delegated", func() {
|
||||||
|
fakeTransformer := &mocks.MockEventTransformer{}
|
||||||
|
config := mocks.FakeTransformerConfig
|
||||||
|
fakeTransformer.SetTransformerConfig(config)
|
||||||
|
fakeGethLog := types.Log{
|
||||||
|
Address: common.HexToAddress(config.ContractAddresses[0]),
|
||||||
|
Topics: []common.Hash{common.HexToHash(config.Topic)},
|
||||||
|
}
|
||||||
|
fakeHeaderSyncLogs := []core.HeaderSyncLog{{Log: fakeGethLog}}
|
||||||
|
mockLogRepository := &fakes.MockHeaderSyncLogRepository{}
|
||||||
|
mockLogRepository.ReturnLogs = fakeHeaderSyncLogs
|
||||||
|
delegator := newDelegator(mockLogRepository)
|
||||||
|
delegator.AddTransformer(fakeTransformer)
|
||||||
|
|
||||||
|
err := delegator.DelegateLogs()
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
func newDelegator(headerSyncLogRepository *fakes.MockHeaderSyncLogRepository) *logs.LogDelegator {
|
||||||
|
return &logs.LogDelegator{
|
||||||
|
Chunker: chunker.NewLogChunker(),
|
||||||
|
LogRepository: headerSyncLogRepository,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 logs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transactions"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoUncheckedHeaders = errors.New("no unchecked headers available for log fetching")
|
||||||
|
ErrNoWatchedAddresses = errors.New("no watched addresses configured in the log extractor")
|
||||||
|
)
|
||||||
|
|
||||||
|
type ILogExtractor interface {
|
||||||
|
AddTransformerConfig(config transformer.EventTransformerConfig) error
|
||||||
|
ExtractLogs(recheckHeaders constants.TransformerExecution) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogExtractor struct {
|
||||||
|
Addresses []common.Address
|
||||||
|
CheckedHeadersRepository datastore.CheckedHeadersRepository
|
||||||
|
CheckedLogsRepository datastore.CheckedLogsRepository
|
||||||
|
Fetcher fetcher.ILogFetcher
|
||||||
|
LogRepository datastore.HeaderSyncLogRepository
|
||||||
|
StartingBlock *int64
|
||||||
|
Syncer transactions.ITransactionsSyncer
|
||||||
|
Topics []common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add additional logs to extract
|
||||||
|
func (extractor *LogExtractor) AddTransformerConfig(config transformer.EventTransformerConfig) error {
|
||||||
|
checkedHeadersErr := extractor.updateCheckedHeaders(config)
|
||||||
|
if checkedHeadersErr != nil {
|
||||||
|
return checkedHeadersErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if extractor.StartingBlock == nil {
|
||||||
|
extractor.StartingBlock = &config.StartingBlockNumber
|
||||||
|
} else if earlierStartingBlockNumber(config.StartingBlockNumber, *extractor.StartingBlock) {
|
||||||
|
extractor.StartingBlock = &config.StartingBlockNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
addresses := transformer.HexStringsToAddresses(config.ContractAddresses)
|
||||||
|
extractor.Addresses = append(extractor.Addresses, addresses...)
|
||||||
|
extractor.Topics = append(extractor.Topics, common.HexToHash(config.Topic))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch and persist watched logs
|
||||||
|
func (extractor LogExtractor) ExtractLogs(recheckHeaders constants.TransformerExecution) error {
|
||||||
|
if len(extractor.Addresses) < 1 {
|
||||||
|
logrus.Errorf("error extracting logs: %s", ErrNoWatchedAddresses.Error())
|
||||||
|
return ErrNoWatchedAddresses
|
||||||
|
}
|
||||||
|
|
||||||
|
uncheckedHeaders, uncheckedHeadersErr := extractor.CheckedHeadersRepository.UncheckedHeaders(*extractor.StartingBlock, -1, getCheckCount(recheckHeaders))
|
||||||
|
if uncheckedHeadersErr != nil {
|
||||||
|
logrus.Errorf("error fetching missing headers: %s", uncheckedHeadersErr)
|
||||||
|
return uncheckedHeadersErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uncheckedHeaders) < 1 {
|
||||||
|
return ErrNoUncheckedHeaders
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, header := range uncheckedHeaders {
|
||||||
|
logs, fetchLogsErr := extractor.Fetcher.FetchLogs(extractor.Addresses, extractor.Topics, header)
|
||||||
|
if fetchLogsErr != nil {
|
||||||
|
logError("error fetching logs for header: %s", fetchLogsErr, header)
|
||||||
|
return fetchLogsErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(logs) > 0 {
|
||||||
|
transactionsSyncErr := extractor.Syncer.SyncTransactions(header.Id, logs)
|
||||||
|
if transactionsSyncErr != nil {
|
||||||
|
logError("error syncing transactions: %s", transactionsSyncErr, header)
|
||||||
|
return transactionsSyncErr
|
||||||
|
}
|
||||||
|
|
||||||
|
createLogsErr := extractor.LogRepository.CreateHeaderSyncLogs(header.Id, logs)
|
||||||
|
if createLogsErr != nil {
|
||||||
|
logError("error persisting logs: %s", createLogsErr, header)
|
||||||
|
return createLogsErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
markHeaderCheckedErr := extractor.CheckedHeadersRepository.MarkHeaderChecked(header.Id)
|
||||||
|
if markHeaderCheckedErr != nil {
|
||||||
|
logError("error marking header checked: %s", markHeaderCheckedErr, header)
|
||||||
|
return markHeaderCheckedErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func earlierStartingBlockNumber(transformerBlock, watcherBlock int64) bool {
|
||||||
|
return transformerBlock < watcherBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
func logError(description string, err error, header core.Header) {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"headerId": header.Id,
|
||||||
|
"headerHash": header.Hash,
|
||||||
|
"blockNumber": header.BlockNumber,
|
||||||
|
}).Errorf(description, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCheckCount(recheckHeaders constants.TransformerExecution) int64 {
|
||||||
|
if recheckHeaders == constants.HeaderUnchecked {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return constants.RecheckHeaderCap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (extractor *LogExtractor) updateCheckedHeaders(config transformer.EventTransformerConfig) error {
|
||||||
|
alreadyWatchingLog, watchingLogErr := extractor.CheckedLogsRepository.AlreadyWatchingLog(config.ContractAddresses, config.Topic)
|
||||||
|
if watchingLogErr != nil {
|
||||||
|
return watchingLogErr
|
||||||
|
}
|
||||||
|
if !alreadyWatchingLog {
|
||||||
|
uncheckHeadersErr := extractor.CheckedHeadersRepository.MarkHeadersUnchecked(config.StartingBlockNumber)
|
||||||
|
if uncheckHeadersErr != nil {
|
||||||
|
return uncheckHeadersErr
|
||||||
|
}
|
||||||
|
markLogWatchedErr := extractor.CheckedLogsRepository.MarkLogWatched(config.ContractAddresses, config.Topic)
|
||||||
|
if markLogWatchedErr != nil {
|
||||||
|
return markLogWatchedErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,414 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 logs_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/libraries/shared/constants"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/logs"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Log extractor", func() {
|
||||||
|
var (
|
||||||
|
checkedHeadersRepository *fakes.MockCheckedHeadersRepository
|
||||||
|
checkedLogsRepository *fakes.MockCheckedLogsRepository
|
||||||
|
extractor *logs.LogExtractor
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
checkedHeadersRepository = &fakes.MockCheckedHeadersRepository{}
|
||||||
|
checkedLogsRepository = &fakes.MockCheckedLogsRepository{}
|
||||||
|
extractor = &logs.LogExtractor{
|
||||||
|
CheckedHeadersRepository: checkedHeadersRepository,
|
||||||
|
CheckedLogsRepository: checkedLogsRepository,
|
||||||
|
Fetcher: &mocks.MockLogFetcher{},
|
||||||
|
LogRepository: &fakes.MockHeaderSyncLogRepository{},
|
||||||
|
Syncer: &fakes.MockTransactionSyncer{},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("AddTransformerConfig", func() {
|
||||||
|
It("updates extractor's starting block number to earliest available", func() {
|
||||||
|
earlierStartingBlockNumber := rand.Int63()
|
||||||
|
laterStartingBlockNumber := earlierStartingBlockNumber + 1
|
||||||
|
|
||||||
|
errOne := extractor.AddTransformerConfig(getTransformerConfig(laterStartingBlockNumber))
|
||||||
|
Expect(errOne).NotTo(HaveOccurred())
|
||||||
|
errTwo := extractor.AddTransformerConfig(getTransformerConfig(earlierStartingBlockNumber))
|
||||||
|
Expect(errTwo).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(*extractor.StartingBlock).To(Equal(earlierStartingBlockNumber))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("adds transformer's addresses to extractor's watched addresses", func() {
|
||||||
|
addresses := []string{"0xA", "0xB"}
|
||||||
|
configWithAddresses := transformer.EventTransformerConfig{
|
||||||
|
ContractAddresses: addresses,
|
||||||
|
StartingBlockNumber: rand.Int63(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := extractor.AddTransformerConfig(configWithAddresses)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
expectedAddresses := transformer.HexStringsToAddresses(addresses)
|
||||||
|
Expect(extractor.Addresses).To(Equal(expectedAddresses))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("adds transformer's topic to extractor's watched topics", func() {
|
||||||
|
topic := "0x1"
|
||||||
|
configWithTopic := transformer.EventTransformerConfig{
|
||||||
|
ContractAddresses: []string{fakes.FakeAddress.Hex()},
|
||||||
|
Topic: topic,
|
||||||
|
StartingBlockNumber: rand.Int63(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := extractor.AddTransformerConfig(configWithTopic)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(extractor.Topics).To(Equal([]common.Hash{common.HexToHash(topic)}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if checking whether log has been checked returns error", func() {
|
||||||
|
checkedLogsRepository.AlreadyWatchingLogError = fakes.FakeError
|
||||||
|
|
||||||
|
err := extractor.AddTransformerConfig(getTransformerConfig(rand.Int63()))
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when log has previously been checked", func() {
|
||||||
|
It("does not mark any headers unchecked", func() {
|
||||||
|
checkedLogsRepository.AlreadyWatchingLogReturn = true
|
||||||
|
|
||||||
|
err := extractor.AddTransformerConfig(getTransformerConfig(rand.Int63()))
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(checkedHeadersRepository.MarkHeadersUncheckedCalled).To(BeFalse())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when log has not previously been checked", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
checkedLogsRepository.AlreadyWatchingLogReturn = false
|
||||||
|
})
|
||||||
|
|
||||||
|
It("marks headers since transformer's starting block number as unchecked", func() {
|
||||||
|
blockNumber := rand.Int63()
|
||||||
|
|
||||||
|
err := extractor.AddTransformerConfig(getTransformerConfig(blockNumber))
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(checkedHeadersRepository.MarkHeadersUncheckedCalled).To(BeTrue())
|
||||||
|
Expect(checkedHeadersRepository.MarkHeadersUncheckedStartingBlockNumber).To(Equal(blockNumber))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if marking headers unchecked returns error", func() {
|
||||||
|
checkedHeadersRepository.MarkHeadersUncheckedReturnError = fakes.FakeError
|
||||||
|
|
||||||
|
err := extractor.AddTransformerConfig(getTransformerConfig(rand.Int63()))
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("persists that tranformer's log has been checked", func() {
|
||||||
|
config := getTransformerConfig(rand.Int63())
|
||||||
|
|
||||||
|
err := extractor.AddTransformerConfig(config)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(checkedLogsRepository.MarkLogWatchedAddresses).To(Equal(config.ContractAddresses))
|
||||||
|
Expect(checkedLogsRepository.MarkLogWatchedTopicZero).To(Equal(config.Topic))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if marking logs checked returns error", func() {
|
||||||
|
checkedLogsRepository.MarkLogWatchedError = fakes.FakeError
|
||||||
|
|
||||||
|
err := extractor.AddTransformerConfig(getTransformerConfig(rand.Int63()))
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("ExtractLogs", func() {
|
||||||
|
It("returns error if no watched addresses configured", func() {
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(logs.ErrNoWatchedAddresses))
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when checking unchecked headers", func() {
|
||||||
|
It("gets headers since configured starting block with check_count < 1", func() {
|
||||||
|
mockCheckedHeadersRepository := &fakes.MockCheckedHeadersRepository{}
|
||||||
|
mockCheckedHeadersRepository.UncheckedHeadersReturnHeaders = []core.Header{{}}
|
||||||
|
extractor.CheckedHeadersRepository = mockCheckedHeadersRepository
|
||||||
|
startingBlockNumber := rand.Int63()
|
||||||
|
extractor.AddTransformerConfig(getTransformerConfig(startingBlockNumber))
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(mockCheckedHeadersRepository.UncheckedHeadersStartingBlockNumber).To(Equal(startingBlockNumber))
|
||||||
|
Expect(mockCheckedHeadersRepository.UncheckedHeadersEndingBlockNumber).To(Equal(int64(-1)))
|
||||||
|
Expect(mockCheckedHeadersRepository.UncheckedHeadersCheckCount).To(Equal(int64(1)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when rechecking headers", func() {
|
||||||
|
It("gets headers since configured starting block with check_count < RecheckHeaderCap", func() {
|
||||||
|
mockCheckedHeadersRepository := &fakes.MockCheckedHeadersRepository{}
|
||||||
|
mockCheckedHeadersRepository.UncheckedHeadersReturnHeaders = []core.Header{{}}
|
||||||
|
extractor.CheckedHeadersRepository = mockCheckedHeadersRepository
|
||||||
|
startingBlockNumber := rand.Int63()
|
||||||
|
extractor.AddTransformerConfig(getTransformerConfig(startingBlockNumber))
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderRecheck)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(mockCheckedHeadersRepository.UncheckedHeadersStartingBlockNumber).To(Equal(startingBlockNumber))
|
||||||
|
Expect(mockCheckedHeadersRepository.UncheckedHeadersEndingBlockNumber).To(Equal(int64(-1)))
|
||||||
|
Expect(mockCheckedHeadersRepository.UncheckedHeadersCheckCount).To(Equal(constants.RecheckHeaderCap))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if getting unchecked headers fails", func() {
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockCheckedHeadersRepository := &fakes.MockCheckedHeadersRepository{}
|
||||||
|
mockCheckedHeadersRepository.UncheckedHeadersReturnError = fakes.FakeError
|
||||||
|
extractor.CheckedHeadersRepository = mockCheckedHeadersRepository
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when no unchecked headers", func() {
|
||||||
|
It("does not fetch logs", func() {
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockLogFetcher := &mocks.MockLogFetcher{}
|
||||||
|
extractor.Fetcher = mockLogFetcher
|
||||||
|
|
||||||
|
_ = extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(mockLogFetcher.FetchCalled).To(BeFalse())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error that no unchecked headers were found", func() {
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockLogFetcher := &mocks.MockLogFetcher{}
|
||||||
|
extractor.Fetcher = mockLogFetcher
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(MatchError(logs.ErrNoUncheckedHeaders))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when there are unchecked headers", func() {
|
||||||
|
It("fetches logs for unchecked headers", func() {
|
||||||
|
addUncheckedHeader(extractor)
|
||||||
|
config := transformer.EventTransformerConfig{
|
||||||
|
ContractAddresses: []string{fakes.FakeAddress.Hex()},
|
||||||
|
Topic: fakes.FakeHash.Hex(),
|
||||||
|
StartingBlockNumber: rand.Int63(),
|
||||||
|
}
|
||||||
|
addTransformerErr := extractor.AddTransformerConfig(config)
|
||||||
|
Expect(addTransformerErr).NotTo(HaveOccurred())
|
||||||
|
mockLogFetcher := &mocks.MockLogFetcher{}
|
||||||
|
extractor.Fetcher = mockLogFetcher
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(mockLogFetcher.FetchCalled).To(BeTrue())
|
||||||
|
expectedTopics := []common.Hash{common.HexToHash(config.Topic)}
|
||||||
|
Expect(mockLogFetcher.Topics).To(Equal(expectedTopics))
|
||||||
|
expectedAddresses := transformer.HexStringsToAddresses(config.ContractAddresses)
|
||||||
|
Expect(mockLogFetcher.ContractAddresses).To(Equal(expectedAddresses))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if fetching logs fails", func() {
|
||||||
|
addUncheckedHeader(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockLogFetcher := &mocks.MockLogFetcher{}
|
||||||
|
mockLogFetcher.ReturnError = fakes.FakeError
|
||||||
|
extractor.Fetcher = mockLogFetcher
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when no fetched logs", func() {
|
||||||
|
It("does not sync transactions", func() {
|
||||||
|
addUncheckedHeader(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockTransactionSyncer := &fakes.MockTransactionSyncer{}
|
||||||
|
extractor.Syncer = mockTransactionSyncer
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(mockTransactionSyncer.SyncTransactionsCalled).To(BeFalse())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when there are fetched logs", func() {
|
||||||
|
It("syncs transactions", func() {
|
||||||
|
addUncheckedHeader(extractor)
|
||||||
|
addFetchedLog(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockTransactionSyncer := &fakes.MockTransactionSyncer{}
|
||||||
|
extractor.Syncer = mockTransactionSyncer
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(mockTransactionSyncer.SyncTransactionsCalled).To(BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if syncing transactions fails", func() {
|
||||||
|
addUncheckedHeader(extractor)
|
||||||
|
addFetchedLog(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockTransactionSyncer := &fakes.MockTransactionSyncer{}
|
||||||
|
mockTransactionSyncer.SyncTransactionsError = fakes.FakeError
|
||||||
|
extractor.Syncer = mockTransactionSyncer
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("persists fetched logs", func() {
|
||||||
|
addUncheckedHeader(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
fakeLogs := []types.Log{{
|
||||||
|
Address: common.HexToAddress("0xA"),
|
||||||
|
Topics: []common.Hash{common.HexToHash("0xA")},
|
||||||
|
Data: []byte{},
|
||||||
|
Index: 0,
|
||||||
|
}}
|
||||||
|
mockLogFetcher := &mocks.MockLogFetcher{ReturnLogs: fakeLogs}
|
||||||
|
extractor.Fetcher = mockLogFetcher
|
||||||
|
mockLogRepository := &fakes.MockHeaderSyncLogRepository{}
|
||||||
|
extractor.LogRepository = mockLogRepository
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(mockLogRepository.PassedLogs).To(Equal(fakeLogs))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if persisting logs fails", func() {
|
||||||
|
addUncheckedHeader(extractor)
|
||||||
|
addFetchedLog(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockLogRepository := &fakes.MockHeaderSyncLogRepository{}
|
||||||
|
mockLogRepository.CreateError = fakes.FakeError
|
||||||
|
extractor.LogRepository = mockLogRepository
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
It("marks header checked", func() {
|
||||||
|
addFetchedLog(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockCheckedHeadersRepository := &fakes.MockCheckedHeadersRepository{}
|
||||||
|
headerID := rand.Int63()
|
||||||
|
mockCheckedHeadersRepository.UncheckedHeadersReturnHeaders = []core.Header{{Id: headerID}}
|
||||||
|
extractor.CheckedHeadersRepository = mockCheckedHeadersRepository
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(mockCheckedHeadersRepository.MarkHeaderCheckedHeaderID).To(Equal(headerID))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if marking header checked fails", func() {
|
||||||
|
addFetchedLog(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
mockCheckedHeadersRepository := &fakes.MockCheckedHeadersRepository{}
|
||||||
|
mockCheckedHeadersRepository.UncheckedHeadersReturnHeaders = []core.Header{{Id: rand.Int63()}}
|
||||||
|
mockCheckedHeadersRepository.MarkHeaderCheckedReturnError = fakes.FakeError
|
||||||
|
extractor.CheckedHeadersRepository = mockCheckedHeadersRepository
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns nil for error if everything succeeds", func() {
|
||||||
|
addUncheckedHeader(extractor)
|
||||||
|
addTransformerConfig(extractor)
|
||||||
|
|
||||||
|
err := extractor.ExtractLogs(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
func addTransformerConfig(extractor *logs.LogExtractor) {
|
||||||
|
fakeConfig := transformer.EventTransformerConfig{
|
||||||
|
ContractAddresses: []string{fakes.FakeAddress.Hex()},
|
||||||
|
Topic: fakes.FakeHash.Hex(),
|
||||||
|
StartingBlockNumber: rand.Int63(),
|
||||||
|
}
|
||||||
|
extractor.AddTransformerConfig(fakeConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addUncheckedHeader(extractor *logs.LogExtractor) {
|
||||||
|
mockCheckedHeadersRepository := &fakes.MockCheckedHeadersRepository{}
|
||||||
|
mockCheckedHeadersRepository.UncheckedHeadersReturnHeaders = []core.Header{{}}
|
||||||
|
extractor.CheckedHeadersRepository = mockCheckedHeadersRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFetchedLog(extractor *logs.LogExtractor) {
|
||||||
|
mockLogFetcher := &mocks.MockLogFetcher{}
|
||||||
|
mockLogFetcher.ReturnLogs = []types.Log{{}}
|
||||||
|
extractor.Fetcher = mockLogFetcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTransformerConfig(startingBlockNumber int64) transformer.EventTransformerConfig {
|
||||||
|
return transformer.EventTransformerConfig{
|
||||||
|
ContractAddresses: []string{fakes.FakeAddress.Hex()},
|
||||||
|
Topic: fakes.FakeHash.Hex(),
|
||||||
|
StartingBlockNumber: startingBlockNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 logs_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLogs(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "Logs Suite")
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func() {
|
||||||
|
logrus.SetOutput(ioutil.Discard)
|
||||||
|
})
|
||||||
@@ -16,9 +16,7 @@
|
|||||||
|
|
||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import (
|
import "github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockConverter struct {
|
type MockConverter struct {
|
||||||
ToEntitiesError error
|
ToEntitiesError error
|
||||||
@@ -27,7 +25,7 @@ type MockConverter struct {
|
|||||||
entityConverterError error
|
entityConverterError error
|
||||||
modelConverterError error
|
modelConverterError error
|
||||||
ContractAbi string
|
ContractAbi string
|
||||||
LogsToConvert []types.Log
|
LogsToConvert []core.HeaderSyncLog
|
||||||
EntitiesToConvert []interface{}
|
EntitiesToConvert []interface{}
|
||||||
EntitiesToReturn []interface{}
|
EntitiesToReturn []interface{}
|
||||||
ModelsToReturn []interface{}
|
ModelsToReturn []interface{}
|
||||||
@@ -35,9 +33,9 @@ type MockConverter struct {
|
|||||||
ToModelsCalledCounter int
|
ToModelsCalledCounter int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (converter *MockConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) {
|
func (converter *MockConverter) ToEntities(contractAbi string, ethLogs []core.HeaderSyncLog) ([]interface{}, error) {
|
||||||
for _, log := range ethLogs {
|
for _, log := range ethLogs {
|
||||||
converter.PassedContractAddresses = append(converter.PassedContractAddresses, log.Address.Hex())
|
converter.PassedContractAddresses = append(converter.PassedContractAddresses, log.Log.Address.Hex())
|
||||||
}
|
}
|
||||||
converter.ContractAbi = contractAbi
|
converter.ContractAbi = contractAbi
|
||||||
converter.LogsToConvert = ethLogs
|
converter.LogsToConvert = ethLogs
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockEventRepository struct {
|
||||||
|
createError error
|
||||||
|
PassedModels []interface{}
|
||||||
|
SetDbCalled bool
|
||||||
|
CreateCalledCounter int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repository *MockEventRepository) Create(models []interface{}) error {
|
||||||
|
repository.PassedModels = models
|
||||||
|
repository.CreateCalledCounter++
|
||||||
|
|
||||||
|
return repository.createError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repository *MockEventRepository) SetDB(db *postgres.DB) {
|
||||||
|
repository.SetDbCalled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repository *MockEventRepository) SetCreateError(e error) {
|
||||||
|
repository.createError = e
|
||||||
|
}
|
||||||
+19
-22
@@ -17,45 +17,42 @@
|
|||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
|
||||||
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MockTransformer struct {
|
type MockEventTransformer struct {
|
||||||
ExecuteWasCalled bool
|
ExecuteWasCalled bool
|
||||||
ExecuteError error
|
ExecuteError error
|
||||||
PassedLogs []types.Log
|
PassedLogs []core.HeaderSyncLog
|
||||||
PassedHeader core.Header
|
config transformer.EventTransformerConfig
|
||||||
config shared_t.EventTransformerConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mh *MockTransformer) Execute(logs []types.Log, header core.Header) error {
|
func (t *MockEventTransformer) Execute(logs []core.HeaderSyncLog) error {
|
||||||
if mh.ExecuteError != nil {
|
if t.ExecuteError != nil {
|
||||||
return mh.ExecuteError
|
return t.ExecuteError
|
||||||
}
|
}
|
||||||
mh.ExecuteWasCalled = true
|
t.ExecuteWasCalled = true
|
||||||
mh.PassedLogs = logs
|
t.PassedLogs = logs
|
||||||
mh.PassedHeader = header
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mh *MockTransformer) GetConfig() shared_t.EventTransformerConfig {
|
func (t *MockEventTransformer) GetConfig() transformer.EventTransformerConfig {
|
||||||
return mh.config
|
return t.config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mh *MockTransformer) SetTransformerConfig(config shared_t.EventTransformerConfig) {
|
func (t *MockEventTransformer) SetTransformerConfig(config transformer.EventTransformerConfig) {
|
||||||
mh.config = config
|
t.config = config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mh *MockTransformer) FakeTransformerInitializer(db *postgres.DB) shared_t.EventTransformer {
|
func (t *MockEventTransformer) FakeTransformerInitializer(db *postgres.DB) transformer.EventTransformer {
|
||||||
return mh
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
var FakeTransformerConfig = shared_t.EventTransformerConfig{
|
var FakeTransformerConfig = transformer.EventTransformerConfig{
|
||||||
TransformerName: "FakeTransformer",
|
TransformerName: "FakeTransformer",
|
||||||
ContractAddresses: []string{"FakeAddress"},
|
ContractAddresses: []string{fakes.FakeAddress.Hex()},
|
||||||
Topic: "FakeTopic",
|
Topic: fakes.FakeHash.Hex(),
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockLogDelegator struct {
|
||||||
|
AddedTransformers []transformer.EventTransformer
|
||||||
|
DelegateCallCount int
|
||||||
|
DelegateErrors []error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (delegator *MockLogDelegator) AddTransformer(t transformer.EventTransformer) {
|
||||||
|
delegator.AddedTransformers = append(delegator.AddedTransformers, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (delegator *MockLogDelegator) DelegateLogs() error {
|
||||||
|
delegator.DelegateCallCount++
|
||||||
|
if len(delegator.DelegateErrors) > 1 {
|
||||||
|
var delegateErrorThisRun error
|
||||||
|
delegateErrorThisRun, delegator.DelegateErrors = delegator.DelegateErrors[0], delegator.DelegateErrors[1:]
|
||||||
|
return delegateErrorThisRun
|
||||||
|
} else if len(delegator.DelegateErrors) == 1 {
|
||||||
|
thisErr := delegator.DelegateErrors[0]
|
||||||
|
delegator.DelegateErrors = []error{}
|
||||||
|
return thisErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockLogExtractor struct {
|
||||||
|
AddedConfigs []transformer.EventTransformerConfig
|
||||||
|
AddTransformerConfigError error
|
||||||
|
ExtractLogsCount int
|
||||||
|
ExtractLogsErrors []error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (extractor *MockLogExtractor) AddTransformerConfig(config transformer.EventTransformerConfig) error {
|
||||||
|
extractor.AddedConfigs = append(extractor.AddedConfigs, config)
|
||||||
|
return extractor.AddTransformerConfigError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (extractor *MockLogExtractor) ExtractLogs(recheckHeaders constants.TransformerExecution) error {
|
||||||
|
extractor.ExtractLogsCount++
|
||||||
|
if len(extractor.ExtractLogsErrors) > 1 {
|
||||||
|
var errorThisRun error
|
||||||
|
errorThisRun, extractor.ExtractLogsErrors = extractor.ExtractLogsErrors[0], extractor.ExtractLogsErrors[1:]
|
||||||
|
return errorThisRun
|
||||||
|
} else if len(extractor.ExtractLogsErrors) == 1 {
|
||||||
|
thisErr := extractor.ExtractLogsErrors[0]
|
||||||
|
extractor.ExtractLogsErrors = []error{}
|
||||||
|
return thisErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+15
-17
@@ -17,26 +17,24 @@
|
|||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MockLogNoteConverter struct {
|
type MockLogFetcher struct {
|
||||||
err error
|
ContractAddresses []common.Address
|
||||||
returnModels []interface{}
|
FetchCalled bool
|
||||||
PassedLogs []types.Log
|
MissingHeader core.Header
|
||||||
ToModelsCalledCounter int
|
ReturnError error
|
||||||
|
ReturnLogs []types.Log
|
||||||
|
Topics []common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (converter *MockLogNoteConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
|
func (fetcher *MockLogFetcher) FetchLogs(contractAddresses []common.Address, topics []common.Hash, missingHeader core.Header) ([]types.Log, error) {
|
||||||
converter.PassedLogs = ethLogs
|
fetcher.FetchCalled = true
|
||||||
converter.ToModelsCalledCounter++
|
fetcher.ContractAddresses = contractAddresses
|
||||||
return converter.returnModels, converter.err
|
fetcher.Topics = topics
|
||||||
}
|
fetcher.MissingHeader = missingHeader
|
||||||
|
return fetcher.ReturnLogs, fetcher.ReturnError
|
||||||
func (converter *MockLogNoteConverter) SetConverterError(e error) {
|
|
||||||
converter.err = e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (converter *MockLogNoteConverter) SetReturnModels(models []interface{}) {
|
|
||||||
converter.returnModels = models
|
|
||||||
}
|
}
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
// VulcanizeDB
|
|
||||||
// Copyright © 2019 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 mocks
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/onsi/gomega"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockRepository struct {
|
|
||||||
createError error
|
|
||||||
markHeaderCheckedError error
|
|
||||||
MarkHeaderCheckedPassedHeaderIDs []int64
|
|
||||||
CreatedHeaderIds []int64
|
|
||||||
missingHeaders []core.Header
|
|
||||||
allHeaders []core.Header
|
|
||||||
missingHeadersError error
|
|
||||||
PassedStartingBlockNumber int64
|
|
||||||
PassedEndingBlockNumber int64
|
|
||||||
PassedHeaderID int64
|
|
||||||
PassedModels []interface{}
|
|
||||||
SetDbCalled bool
|
|
||||||
CreateCalledCounter int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) Create(headerID int64, models []interface{}) error {
|
|
||||||
repository.PassedHeaderID = headerID
|
|
||||||
repository.PassedModels = models
|
|
||||||
repository.CreatedHeaderIds = append(repository.CreatedHeaderIds, headerID)
|
|
||||||
repository.CreateCalledCounter++
|
|
||||||
|
|
||||||
return repository.createError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) MarkHeaderChecked(headerID int64) error {
|
|
||||||
repository.MarkHeaderCheckedPassedHeaderIDs = append(repository.MarkHeaderCheckedPassedHeaderIDs, headerID)
|
|
||||||
return repository.markHeaderCheckedError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
|
|
||||||
repository.PassedStartingBlockNumber = startingBlockNumber
|
|
||||||
repository.PassedEndingBlockNumber = endingBlockNumber
|
|
||||||
return repository.missingHeaders, repository.missingHeadersError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) RecheckHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
|
|
||||||
repository.PassedStartingBlockNumber = startingBlockNumber
|
|
||||||
repository.PassedEndingBlockNumber = endingBlockNumber
|
|
||||||
return repository.allHeaders, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) SetDB(db *postgres.DB) {
|
|
||||||
repository.SetDbCalled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) SetMissingHeadersError(e error) {
|
|
||||||
repository.missingHeadersError = e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) SetAllHeaders(headers []core.Header) {
|
|
||||||
repository.allHeaders = headers
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) SetMissingHeaders(headers []core.Header) {
|
|
||||||
repository.missingHeaders = headers
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) SetMarkHeaderCheckedError(e error) {
|
|
||||||
repository.markHeaderCheckedError = e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) SetCreateError(e error) {
|
|
||||||
repository.createError = e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) AssertMarkHeaderCheckedCalledWith(i int64) {
|
|
||||||
Expect(repository.MarkHeaderCheckedPassedHeaderIDs).To(ContainElement(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockRepository) AssertMarkHeaderCheckedNotCalled() {
|
|
||||||
Expect(len(repository.MarkHeaderCheckedPassedHeaderIDs)).To(Equal(0))
|
|
||||||
}
|
|
||||||
@@ -19,21 +19,21 @@ package mocks
|
|||||||
import "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
import "github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
|
||||||
type MockStorageFetcher struct {
|
type MockStorageFetcher struct {
|
||||||
RowsToReturn []utils.StorageDiffRow
|
DiffsToReturn []utils.StorageDiff
|
||||||
ErrsToReturn []error
|
ErrsToReturn []error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMockStorageFetcher() *MockStorageFetcher {
|
func NewMockStorageFetcher() *MockStorageFetcher {
|
||||||
return &MockStorageFetcher{}
|
return &MockStorageFetcher{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fetcher *MockStorageFetcher) FetchStorageDiffs(out chan<- utils.StorageDiffRow, errs chan<- error) {
|
func (fetcher *MockStorageFetcher) FetchStorageDiffs(out chan<- utils.StorageDiff, errs chan<- error) {
|
||||||
defer close(out)
|
defer close(out)
|
||||||
defer close(errs)
|
defer close(errs)
|
||||||
for _, err := range fetcher.ErrsToReturn {
|
for _, err := range fetcher.ErrsToReturn {
|
||||||
errs <- err
|
errs <- err
|
||||||
}
|
}
|
||||||
for _, row := range fetcher.RowsToReturn {
|
for _, diff := range fetcher.DiffsToReturn {
|
||||||
out <- row
|
out <- diff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,16 +23,16 @@ import (
|
|||||||
type MockStorageQueue struct {
|
type MockStorageQueue struct {
|
||||||
AddCalled bool
|
AddCalled bool
|
||||||
AddError error
|
AddError error
|
||||||
AddPassedRow utils.StorageDiffRow
|
AddPassedDiff utils.StorageDiff
|
||||||
DeleteErr error
|
DeleteErr error
|
||||||
DeletePassedId int
|
DeletePassedId int
|
||||||
GetAllErr error
|
GetAllErr error
|
||||||
RowsToReturn []utils.StorageDiffRow
|
DiffsToReturn []utils.StorageDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
func (queue *MockStorageQueue) Add(row utils.StorageDiffRow) error {
|
func (queue *MockStorageQueue) Add(diff utils.StorageDiff) error {
|
||||||
queue.AddCalled = true
|
queue.AddCalled = true
|
||||||
queue.AddPassedRow = row
|
queue.AddPassedDiff = diff
|
||||||
return queue.AddError
|
return queue.AddError
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +41,6 @@ func (queue *MockStorageQueue) Delete(id int) error {
|
|||||||
return queue.DeleteErr
|
return queue.DeleteErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (queue *MockStorageQueue) GetAll() ([]utils.StorageDiffRow, error) {
|
func (queue *MockStorageQueue) GetAll() ([]utils.StorageDiff, error) {
|
||||||
return queue.RowsToReturn, queue.GetAllErr
|
return queue.DiffsToReturn, queue.GetAllErr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,25 +18,24 @@ package mocks
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MockStorageTransformer struct {
|
type MockStorageTransformer struct {
|
||||||
Address common.Address
|
KeccakOfAddress common.Hash
|
||||||
ExecuteErr error
|
ExecuteErr error
|
||||||
PassedRow utils.StorageDiffRow
|
PassedDiff utils.StorageDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer *MockStorageTransformer) Execute(row utils.StorageDiffRow) error {
|
func (transformer *MockStorageTransformer) Execute(diff utils.StorageDiff) error {
|
||||||
transformer.PassedRow = row
|
transformer.PassedDiff = diff
|
||||||
return transformer.ExecuteErr
|
return transformer.ExecuteErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer *MockStorageTransformer) ContractAddress() common.Address {
|
func (transformer *MockStorageTransformer) KeccakContractAddress() common.Hash {
|
||||||
return transformer.Address
|
return transformer.KeccakOfAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer *MockStorageTransformer) FakeTransformerInitializer(db *postgres.DB) transformer.StorageTransformer {
|
func (transformer *MockStorageTransformer) FakeTransformerInitializer(db *postgres.DB) transformer.StorageTransformer {
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
// VulcanizeDB
|
|
||||||
// Copyright © 2019 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 mocks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockWatcherRepository struct {
|
|
||||||
ReturnCheckedColumnNames []string
|
|
||||||
GetCheckedColumnNamesError error
|
|
||||||
GetCheckedColumnNamesCalled bool
|
|
||||||
|
|
||||||
ReturnNotCheckedSQL string
|
|
||||||
CreateNotCheckedSQLCalled bool
|
|
||||||
|
|
||||||
ReturnMissingHeaders []core.Header
|
|
||||||
MissingHeadersError error
|
|
||||||
MissingHeadersCalled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockWatcherRepository) GetCheckedColumnNames(db *postgres.DB) ([]string, error) {
|
|
||||||
repository.GetCheckedColumnNamesCalled = true
|
|
||||||
if repository.GetCheckedColumnNamesError != nil {
|
|
||||||
return []string{}, repository.GetCheckedColumnNamesError
|
|
||||||
}
|
|
||||||
|
|
||||||
return repository.ReturnCheckedColumnNames, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockWatcherRepository) SetCheckedColumnNames(checkedColumnNames []string) {
|
|
||||||
repository.ReturnCheckedColumnNames = checkedColumnNames
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockWatcherRepository) CreateNotCheckedSQL(boolColumns []string) string {
|
|
||||||
repository.CreateNotCheckedSQLCalled = true
|
|
||||||
return repository.ReturnNotCheckedSQL
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockWatcherRepository) SetNotCheckedSQL(notCheckedSql string) {
|
|
||||||
repository.ReturnNotCheckedSQL = notCheckedSql
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockWatcherRepository) MissingHeaders(startingBlockNumber int64, endingBlockNumber int64, db *postgres.DB, notCheckedSQL string) ([]core.Header, error) {
|
|
||||||
if repository.MissingHeadersError != nil {
|
|
||||||
return []core.Header{}, repository.MissingHeadersError
|
|
||||||
}
|
|
||||||
repository.MissingHeadersCalled = true
|
|
||||||
return repository.ReturnMissingHeaders, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockWatcherRepository) SetMissingHeaders(headers []core.Header) {
|
|
||||||
repository.ReturnMissingHeaders = headers
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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/>.
|
||||||
|
|
||||||
|
// 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 repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
const getOrCreateAddressQuery = `WITH addressId AS (
|
||||||
|
INSERT INTO addresses (address) VALUES ($1) ON CONFLICT DO NOTHING RETURNING id
|
||||||
|
)
|
||||||
|
SELECT id FROM addresses WHERE address = $1
|
||||||
|
UNION
|
||||||
|
SELECT id FROM addressId`
|
||||||
|
|
||||||
|
func GetOrCreateAddress(db *postgres.DB, address string) (int64, error) {
|
||||||
|
checksumAddress := getChecksumAddress(address)
|
||||||
|
|
||||||
|
var addressId int64
|
||||||
|
getOrCreateErr := db.Get(&addressId, getOrCreateAddressQuery, checksumAddress)
|
||||||
|
|
||||||
|
return addressId, getOrCreateErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOrCreateAddressInTransaction(tx *sqlx.Tx, address string) (int64, error) {
|
||||||
|
checksumAddress := getChecksumAddress(address)
|
||||||
|
|
||||||
|
var addressId int64
|
||||||
|
getOrCreateErr := tx.Get(&addressId, getOrCreateAddressQuery, checksumAddress)
|
||||||
|
|
||||||
|
return addressId, getOrCreateErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAddressById(db *postgres.DB, id int64) (string, error) {
|
||||||
|
var address string
|
||||||
|
getErr := db.Get(&address, `SELECT address FROM public.addresses WHERE id = $1`, id)
|
||||||
|
return address, getErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChecksumAddress(address string) string {
|
||||||
|
stringAddressToCommonAddress := common.HexToAddress(address)
|
||||||
|
return stringAddressToCommonAddress.Hex()
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 repository_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("address lookup", func() {
|
||||||
|
var (
|
||||||
|
db *postgres.DB
|
||||||
|
address = fakes.FakeAddress.Hex()
|
||||||
|
)
|
||||||
|
BeforeEach(func() {
|
||||||
|
db = test_config.NewTestDB(test_config.NewTestNode())
|
||||||
|
test_config.CleanTestDB(db)
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
test_config.CleanTestDB(db)
|
||||||
|
})
|
||||||
|
|
||||||
|
type dbAddress struct {
|
||||||
|
Id int64
|
||||||
|
Address string
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe("GetOrCreateAddress", func() {
|
||||||
|
It("creates an address record", func() {
|
||||||
|
addressId, createErr := repository.GetOrCreateAddress(db, address)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
var actualAddress dbAddress
|
||||||
|
getErr := db.Get(&actualAddress, `SELECT id, address FROM public.addresses LIMIT 1`)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
expectedAddress := dbAddress{Id: addressId, Address: address}
|
||||||
|
Expect(actualAddress).To(Equal(expectedAddress))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns the existing record id if the address already exists", func() {
|
||||||
|
createId, createErr := repository.GetOrCreateAddress(db, address)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
getId, getErr := repository.GetOrCreateAddress(db, address)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
var addressCount int
|
||||||
|
addressErr := db.Get(&addressCount, `SELECT count(*) FROM public.addresses`)
|
||||||
|
Expect(addressErr).NotTo(HaveOccurred())
|
||||||
|
Expect(addressCount).To(Equal(1))
|
||||||
|
Expect(createId).To(Equal(getId))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets upper-cased addresses", func() {
|
||||||
|
upperAddress := strings.ToUpper(address)
|
||||||
|
upperAddressId, createErr := repository.GetOrCreateAddress(db, upperAddress)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
mixedCaseAddressId, getErr := repository.GetOrCreateAddress(db, address)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
Expect(upperAddressId).To(Equal(mixedCaseAddressId))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets lower-cased addresses", func() {
|
||||||
|
lowerAddress := strings.ToLower(address)
|
||||||
|
upperAddressId, createErr := repository.GetOrCreateAddress(db, lowerAddress)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
mixedCaseAddressId, getErr := repository.GetOrCreateAddress(db, address)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
Expect(upperAddressId).To(Equal(mixedCaseAddressId))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("GetOrCreateAddressInTransaction", func() {
|
||||||
|
var (
|
||||||
|
tx *sqlx.Tx
|
||||||
|
txErr error
|
||||||
|
)
|
||||||
|
BeforeEach(func() {
|
||||||
|
tx, txErr = db.Beginx()
|
||||||
|
Expect(txErr).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
tx.Rollback()
|
||||||
|
})
|
||||||
|
|
||||||
|
It("creates an address record", func() {
|
||||||
|
addressId, createErr := repository.GetOrCreateAddressInTransaction(tx, address)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
commitErr := tx.Commit()
|
||||||
|
Expect(commitErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
var actualAddress dbAddress
|
||||||
|
getErr := db.Get(&actualAddress, `SELECT id, address FROM public.addresses LIMIT 1`)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
expectedAddress := dbAddress{Id: addressId, Address: address}
|
||||||
|
Expect(actualAddress).To(Equal(expectedAddress))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns the existing record id if the address already exists", func() {
|
||||||
|
_, createErr := repository.GetOrCreateAddressInTransaction(tx, address)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
_, getErr := repository.GetOrCreateAddressInTransaction(tx, address)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
var addressCount int
|
||||||
|
addressErr := db.Get(&addressCount, `SELECT count(*) FROM public.addresses`)
|
||||||
|
Expect(addressErr).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets upper-cased addresses", func() {
|
||||||
|
upperAddress := strings.ToUpper(address)
|
||||||
|
upperAddressId, createErr := repository.GetOrCreateAddressInTransaction(tx, upperAddress)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
mixedCaseAddressId, getErr := repository.GetOrCreateAddressInTransaction(tx, address)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
Expect(upperAddressId).To(Equal(mixedCaseAddressId))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets lower-cased addresses", func() {
|
||||||
|
lowerAddress := strings.ToLower(address)
|
||||||
|
upperAddressId, createErr := repository.GetOrCreateAddressInTransaction(tx, lowerAddress)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
mixedCaseAddressId, getErr := repository.GetOrCreateAddressInTransaction(tx, address)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
Expect(upperAddressId).To(Equal(mixedCaseAddressId))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("GetAddressById", func() {
|
||||||
|
It("gets and address by it's id", func() {
|
||||||
|
addressId, createErr := repository.GetOrCreateAddress(db, address)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
actualAddress, getErr := repository.GetAddressById(db, addressId)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
Expect(actualAddress).To(Equal(address))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns an error if the id doesn't exist", func() {
|
||||||
|
_, getErr := repository.GetAddressById(db, 0)
|
||||||
|
Expect(getErr).To(HaveOccurred())
|
||||||
|
Expect(getErr).To(MatchError("sql: no rows in result set"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -16,128 +16,12 @@
|
|||||||
|
|
||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import "github.com/jmoiron/sqlx"
|
||||||
"bytes"
|
|
||||||
"database/sql/driver"
|
|
||||||
"fmt"
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
func MarkContractWatcherHeaderCheckedInTransaction(headerID int64, tx *sqlx.Tx, checkedHeadersColumn string) error {
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarkHeaderChecked(headerID int64, db *postgres.DB, checkedHeadersColumn string) error {
|
|
||||||
_, err := db.Exec(`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`)
|
|
||||||
VALUES ($1, $2)
|
|
||||||
ON CONFLICT (header_id) DO
|
|
||||||
UPDATE SET `+checkedHeadersColumn+` = checked_headers.`+checkedHeadersColumn+` + 1`, headerID, 1)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarkHeaderCheckedInTransaction(headerID int64, tx *sqlx.Tx, checkedHeadersColumn string) error {
|
|
||||||
_, err := tx.Exec(`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`)
|
_, err := tx.Exec(`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`)
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2)
|
||||||
ON CONFLICT (header_id) DO
|
ON CONFLICT (header_id) DO
|
||||||
UPDATE SET `+checkedHeadersColumn+` = checked_headers.`+checkedHeadersColumn+` + 1`, headerID, 1)
|
UPDATE SET `+checkedHeadersColumn+` = checked_headers.`+checkedHeadersColumn+` + 1`, headerID, 1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Treats a header as missing if it's not in the headers table, or not checked for some log type
|
|
||||||
func MissingHeaders(startingBlockNumber, endingBlockNumber int64, db *postgres.DB, notCheckedSQL string) ([]core.Header, error) {
|
|
||||||
var result []core.Header
|
|
||||||
var query string
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if endingBlockNumber == -1 {
|
|
||||||
query = `SELECT headers.id, headers.block_number, headers.hash FROM headers
|
|
||||||
LEFT JOIN checked_headers on headers.id = header_id
|
|
||||||
WHERE (header_id ISNULL OR ` + notCheckedSQL + `)
|
|
||||||
AND headers.block_number >= $1
|
|
||||||
AND headers.eth_node_fingerprint = $2`
|
|
||||||
err = db.Select(&result, query, startingBlockNumber, db.Node.ID)
|
|
||||||
} else {
|
|
||||||
query = `SELECT headers.id, headers.block_number, headers.hash FROM headers
|
|
||||||
LEFT JOIN checked_headers on headers.id = header_id
|
|
||||||
WHERE (header_id ISNULL OR ` + notCheckedSQL + `)
|
|
||||||
AND headers.block_number >= $1
|
|
||||||
AND headers.block_number <= $2
|
|
||||||
AND headers.eth_node_fingerprint = $3`
|
|
||||||
err = db.Select(&result, query, startingBlockNumber, endingBlockNumber, db.Node.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetCheckedColumnNames(db *postgres.DB) ([]string, error) {
|
|
||||||
// Query returns `[]driver.Value`, nullable polymorphic interface
|
|
||||||
var queryResult []driver.Value
|
|
||||||
columnNamesQuery :=
|
|
||||||
`SELECT column_name FROM information_schema.columns
|
|
||||||
WHERE table_schema = 'public'
|
|
||||||
AND table_name = 'checked_headers'
|
|
||||||
AND column_name <> 'id'
|
|
||||||
AND column_name <> 'header_id';`
|
|
||||||
|
|
||||||
err := db.Select(&queryResult, columnNamesQuery)
|
|
||||||
if err != nil {
|
|
||||||
return []string{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform column names from `driver.Value` to strings
|
|
||||||
var columnNames []string
|
|
||||||
for _, result := range queryResult {
|
|
||||||
if columnName, ok := result.(string); ok {
|
|
||||||
columnNames = append(columnNames, columnName)
|
|
||||||
} else {
|
|
||||||
return []string{}, fmt.Errorf("incorrect value for checked_headers column name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return columnNames, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Builds a SQL string that checks if any column should be checked/rechecked.
|
|
||||||
// Defaults to FALSE when no columns are provided.
|
|
||||||
// Ex: ["columnA", "columnB"] => "NOT (columnA!=0 AND columnB!=0)"
|
|
||||||
// [] => "FALSE"
|
|
||||||
func CreateHeaderCheckedPredicateSQL(boolColumns []string, recheckHeaders constants.TransformerExecution) string {
|
|
||||||
if len(boolColumns) == 0 {
|
|
||||||
return "FALSE"
|
|
||||||
}
|
|
||||||
|
|
||||||
if recheckHeaders {
|
|
||||||
return createHeaderCheckedPredicateSQLForRecheckedHeaders(boolColumns)
|
|
||||||
} else {
|
|
||||||
return createHeaderCheckedPredicateSQLForMissingHeaders(boolColumns)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createHeaderCheckedPredicateSQLForMissingHeaders(boolColumns []string) string {
|
|
||||||
var result bytes.Buffer
|
|
||||||
result.WriteString(" (")
|
|
||||||
|
|
||||||
// Loop excluding last column name
|
|
||||||
for _, column := range boolColumns[:len(boolColumns)-1] {
|
|
||||||
result.WriteString(fmt.Sprintf("%v=0 OR ", column))
|
|
||||||
}
|
|
||||||
|
|
||||||
result.WriteString(fmt.Sprintf("%v=0)", boolColumns[len(boolColumns)-1]))
|
|
||||||
|
|
||||||
return result.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func createHeaderCheckedPredicateSQLForRecheckedHeaders(boolColumns []string) string {
|
|
||||||
var result bytes.Buffer
|
|
||||||
result.WriteString(" (")
|
|
||||||
|
|
||||||
// Loop excluding last column name
|
|
||||||
for _, column := range boolColumns[:len(boolColumns)-1] {
|
|
||||||
result.WriteString(fmt.Sprintf("%v<%s OR ", column, constants.RecheckHeaderCap))
|
|
||||||
}
|
|
||||||
|
|
||||||
// No trailing "OR" for the last column name
|
|
||||||
result.WriteString(fmt.Sprintf("%v<%s)", boolColumns[len(boolColumns)-1], constants.RecheckHeaderCap))
|
|
||||||
|
|
||||||
return result.String()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,35 +17,25 @@
|
|||||||
package repository_test
|
package repository_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
|
||||||
shared "github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
|
||||||
r2 "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/header/repository"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
"github.com/vulcanize/vulcanizedb/test_config"
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Repository", func() {
|
var _ = Describe("", func() {
|
||||||
var (
|
Describe("MarkContractWatcherHeaderCheckedInTransaction", func() {
|
||||||
checkedHeadersColumn string
|
var (
|
||||||
db *postgres.DB
|
checkedHeadersColumn string
|
||||||
)
|
db *postgres.DB
|
||||||
|
)
|
||||||
|
|
||||||
Describe("MarkHeaderChecked", func() {
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
db = test_config.NewTestDB(test_config.NewTestNode())
|
db = test_config.NewTestDB(test_config.NewTestNode())
|
||||||
test_config.CleanTestDB(db)
|
test_config.CleanTestDB(db)
|
||||||
|
|
||||||
checkedHeadersColumn = "test_column_checked"
|
checkedHeadersColumn = "test_column_checked"
|
||||||
_, migrateErr := db.Exec(`ALTER TABLE public.checked_headers
|
_, migrateErr := db.Exec(`ALTER TABLE public.checked_headers
|
||||||
ADD COLUMN ` + checkedHeadersColumn + ` integer`)
|
ADD COLUMN ` + checkedHeadersColumn + ` integer`)
|
||||||
@@ -57,247 +47,21 @@ var _ = Describe("Repository", func() {
|
|||||||
Expect(cleanupMigrateErr).NotTo(HaveOccurred())
|
Expect(cleanupMigrateErr).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("marks passed column as checked for passed header", func() {
|
It("marks passed header as checked within a passed transaction", func() {
|
||||||
headerRepository := repositories.NewHeaderRepository(db)
|
|
||||||
headerID, headerErr := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
|
|
||||||
Expect(headerErr).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err := shared.MarkHeaderChecked(headerID, db, checkedHeadersColumn)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
var checkedCount int
|
|
||||||
fetchErr := db.Get(&checkedCount, `SELECT `+checkedHeadersColumn+` FROM public.checked_headers LIMIT 1`)
|
|
||||||
Expect(fetchErr).NotTo(HaveOccurred())
|
|
||||||
Expect(checkedCount).To(Equal(1))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("MarkHeaderCheckedInTransaction", func() {
|
|
||||||
BeforeEach(func() {
|
|
||||||
db = test_config.NewTestDB(test_config.NewTestNode())
|
|
||||||
test_config.CleanTestDB(db)
|
|
||||||
|
|
||||||
checkedHeadersColumn = "test_column_checked"
|
|
||||||
_, migrateErr := db.Exec(`ALTER TABLE public.checked_headers
|
|
||||||
ADD COLUMN ` + checkedHeadersColumn + ` integer`)
|
|
||||||
Expect(migrateErr).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
AfterEach(func() {
|
|
||||||
_, cleanupMigrateErr := db.Exec(`ALTER TABLE public.checked_headers DROP COLUMN ` + checkedHeadersColumn)
|
|
||||||
Expect(cleanupMigrateErr).NotTo(HaveOccurred())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("marks passed column as checked for passed header within a passed transaction", func() {
|
|
||||||
headerRepository := repositories.NewHeaderRepository(db)
|
headerRepository := repositories.NewHeaderRepository(db)
|
||||||
headerID, headerErr := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
|
headerID, headerErr := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
|
||||||
Expect(headerErr).NotTo(HaveOccurred())
|
Expect(headerErr).NotTo(HaveOccurred())
|
||||||
tx, txErr := db.Beginx()
|
tx, txErr := db.Beginx()
|
||||||
Expect(txErr).NotTo(HaveOccurred())
|
Expect(txErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
err := shared.MarkHeaderCheckedInTransaction(headerID, tx, checkedHeadersColumn)
|
err := repository.MarkContractWatcherHeaderCheckedInTransaction(headerID, tx, checkedHeadersColumn)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
commitErr := tx.Commit()
|
commitErr := tx.Commit()
|
||||||
Expect(commitErr).NotTo(HaveOccurred())
|
Expect(commitErr).NotTo(HaveOccurred())
|
||||||
var checkedCount int
|
var checkedCount int
|
||||||
fetchErr := db.Get(&checkedCount, `SELECT `+checkedHeadersColumn+` FROM public.checked_headers LIMIT 1`)
|
fetchErr := db.Get(&checkedCount, `SELECT COUNT(*) FROM public.checked_headers WHERE header_id = $1`, headerID)
|
||||||
Expect(fetchErr).NotTo(HaveOccurred())
|
Expect(fetchErr).NotTo(HaveOccurred())
|
||||||
Expect(checkedCount).To(Equal(1))
|
Expect(checkedCount).To(Equal(1))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("MissingHeaders", func() {
|
|
||||||
var (
|
|
||||||
headerRepository datastore.HeaderRepository
|
|
||||||
startingBlockNumber int64
|
|
||||||
endingBlockNumber int64
|
|
||||||
eventSpecificBlockNumber int64
|
|
||||||
outOfRangeBlockNumber int64
|
|
||||||
blockNumbers []int64
|
|
||||||
headerIDs []int64
|
|
||||||
notCheckedSQL string
|
|
||||||
err error
|
|
||||||
hr r2.HeaderRepository
|
|
||||||
columnNames []string
|
|
||||||
)
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
|
||||||
db = test_config.NewTestDB(test_config.NewTestNode())
|
|
||||||
test_config.CleanTestDB(db)
|
|
||||||
headerRepository = repositories.NewHeaderRepository(db)
|
|
||||||
hr = r2.NewHeaderRepository(db)
|
|
||||||
hr.AddCheckColumns(getExpectedColumnNames())
|
|
||||||
|
|
||||||
columnNames, err = shared.GetCheckedColumnNames(db)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
notCheckedSQL = shared.CreateHeaderCheckedPredicateSQL(columnNames, constants.HeaderMissing)
|
|
||||||
|
|
||||||
startingBlockNumber = rand.Int63()
|
|
||||||
eventSpecificBlockNumber = startingBlockNumber + 1
|
|
||||||
endingBlockNumber = startingBlockNumber + 2
|
|
||||||
outOfRangeBlockNumber = endingBlockNumber + 1
|
|
||||||
|
|
||||||
blockNumbers = []int64{startingBlockNumber, eventSpecificBlockNumber, endingBlockNumber, outOfRangeBlockNumber}
|
|
||||||
|
|
||||||
headerIDs = []int64{}
|
|
||||||
for _, n := range blockNumbers {
|
|
||||||
headerID, err := headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(n))
|
|
||||||
headerIDs = append(headerIDs, headerID)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
AfterEach(func() {
|
|
||||||
test_config.CleanCheckedHeadersTable(db, getExpectedColumnNames())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("only treats headers as checked if the event specific logs have been checked", func() {
|
|
||||||
//add a checked_header record, but don't mark it check for any of the columns
|
|
||||||
_, err = db.Exec(`INSERT INTO public.checked_headers (header_id) VALUES ($1)`, headerIDs[1])
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
headers, err := shared.MissingHeaders(startingBlockNumber, endingBlockNumber, db, notCheckedSQL)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(headers)).To(Equal(3))
|
|
||||||
Expect(headers[0].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber)))
|
|
||||||
Expect(headers[1].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber)))
|
|
||||||
Expect(headers[2].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber)))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("only returns headers associated with the current node", func() {
|
|
||||||
dbTwo := test_config.NewTestDB(core.Node{ID: "second"})
|
|
||||||
headerRepositoryTwo := repositories.NewHeaderRepository(dbTwo)
|
|
||||||
for _, n := range blockNumbers {
|
|
||||||
_, err = headerRepositoryTwo.CreateOrUpdateHeader(fakes.GetFakeHeader(n + 10))
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
nodeOneMissingHeaders, err := shared.MissingHeaders(startingBlockNumber, endingBlockNumber, db, notCheckedSQL)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(nodeOneMissingHeaders)).To(Equal(3))
|
|
||||||
Expect(nodeOneMissingHeaders[0].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(eventSpecificBlockNumber), Equal(endingBlockNumber)))
|
|
||||||
Expect(nodeOneMissingHeaders[1].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(eventSpecificBlockNumber), Equal(endingBlockNumber)))
|
|
||||||
Expect(nodeOneMissingHeaders[2].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(startingBlockNumber), Equal(eventSpecificBlockNumber), Equal(endingBlockNumber)))
|
|
||||||
|
|
||||||
nodeTwoMissingHeaders, err := shared.MissingHeaders(startingBlockNumber, endingBlockNumber+10, dbTwo, notCheckedSQL)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(nodeTwoMissingHeaders)).To(Equal(3))
|
|
||||||
Expect(nodeTwoMissingHeaders[0].BlockNumber).To(Or(Equal(startingBlockNumber+10), Equal(eventSpecificBlockNumber+10), Equal(endingBlockNumber+10)))
|
|
||||||
Expect(nodeTwoMissingHeaders[1].BlockNumber).To(Or(Equal(startingBlockNumber+10), Equal(eventSpecificBlockNumber+10), Equal(endingBlockNumber+10)))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("handles an ending block of -1 ", func() {
|
|
||||||
endingBlock := int64(-1)
|
|
||||||
headers, err := shared.MissingHeaders(startingBlockNumber, endingBlock, db, notCheckedSQL)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(headers)).To(Equal(4))
|
|
||||||
Expect(headers[0].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber), Equal(outOfRangeBlockNumber)))
|
|
||||||
Expect(headers[1].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber), Equal(outOfRangeBlockNumber)))
|
|
||||||
Expect(headers[2].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber), Equal(outOfRangeBlockNumber)))
|
|
||||||
Expect(headers[3].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber), Equal(eventSpecificBlockNumber), Equal(outOfRangeBlockNumber)))
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
It("when a the `notCheckedSQL` argument allows for rechecks it returns headers where the checked count is less than the maximum", func() {
|
|
||||||
columnName := columnNames[0]
|
|
||||||
recheckedSQL := shared.CreateHeaderCheckedPredicateSQL([]string{columnName}, constants.HeaderRecheck)
|
|
||||||
// mark every header checked at least once
|
|
||||||
// header 4 is marked the maximum number of times, it it is not longer checked
|
|
||||||
|
|
||||||
maxCheckCount, intConversionErr := strconv.Atoi(constants.RecheckHeaderCap)
|
|
||||||
Expect(intConversionErr).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
markHeaderOneErr := shared.MarkHeaderChecked(headerIDs[0], db, columnName)
|
|
||||||
Expect(markHeaderOneErr).NotTo(HaveOccurred())
|
|
||||||
markHeaderTwoErr := shared.MarkHeaderChecked(headerIDs[1], db, columnName)
|
|
||||||
Expect(markHeaderTwoErr).NotTo(HaveOccurred())
|
|
||||||
markHeaderThreeErr := shared.MarkHeaderChecked(headerIDs[2], db, columnName)
|
|
||||||
Expect(markHeaderThreeErr).NotTo(HaveOccurred())
|
|
||||||
for i := 0; i <= maxCheckCount; i++ {
|
|
||||||
markHeaderFourErr := shared.MarkHeaderChecked(headerIDs[3], db, columnName)
|
|
||||||
Expect(markHeaderFourErr).NotTo(HaveOccurred())
|
|
||||||
}
|
|
||||||
|
|
||||||
headers, err := shared.MissingHeaders(1, -1, db, recheckedSQL)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(headers)).To(Equal(3))
|
|
||||||
Expect(headers[0].Id).To(Or(Equal(headerIDs[0]), Equal(headerIDs[1]), Equal(headerIDs[2])))
|
|
||||||
Expect(headers[1].Id).To(Or(Equal(headerIDs[0]), Equal(headerIDs[1]), Equal(headerIDs[2])))
|
|
||||||
Expect(headers[2].Id).To(Or(Equal(headerIDs[0]), Equal(headerIDs[1]), Equal(headerIDs[2])))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("GetCheckedColumnNames", func() {
|
|
||||||
It("gets the column names from checked_headers", func() {
|
|
||||||
db := test_config.NewTestDB(test_config.NewTestNode())
|
|
||||||
hr := r2.NewHeaderRepository(db)
|
|
||||||
hr.AddCheckColumns(getExpectedColumnNames())
|
|
||||||
test_config.CleanTestDB(db)
|
|
||||||
expectedColumnNames := getExpectedColumnNames()
|
|
||||||
actualColumnNames, err := shared.GetCheckedColumnNames(db)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(actualColumnNames).To(Equal(expectedColumnNames))
|
|
||||||
test_config.CleanCheckedHeadersTable(db, getExpectedColumnNames())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("CreateHeaderCheckedPredicateSQL", func() {
|
|
||||||
Describe("for headers that haven't been checked for logs", func() {
|
|
||||||
It("generates a correct SQL string for one column", func() {
|
|
||||||
columns := []string{"columnA"}
|
|
||||||
expected := " (columnA=0)"
|
|
||||||
actual := shared.CreateHeaderCheckedPredicateSQL(columns, constants.HeaderMissing)
|
|
||||||
Expect(actual).To(Equal(expected))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("generates a correct SQL string for several columns", func() {
|
|
||||||
columns := []string{"columnA", "columnB"}
|
|
||||||
expected := " (columnA=0 OR columnB=0)"
|
|
||||||
actual := shared.CreateHeaderCheckedPredicateSQL(columns, constants.HeaderMissing)
|
|
||||||
Expect(actual).To(Equal(expected))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("defaults to FALSE when there are no columns", func() {
|
|
||||||
expected := "FALSE"
|
|
||||||
actual := shared.CreateHeaderCheckedPredicateSQL([]string{}, constants.HeaderMissing)
|
|
||||||
Expect(actual).To(Equal(expected))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("for headers that are being rechecked for logs", func() {
|
|
||||||
It("generates a correct SQL string for rechecking headers for one column", func() {
|
|
||||||
columns := []string{"columnA"}
|
|
||||||
expected := fmt.Sprintf(" (columnA<%s)", constants.RecheckHeaderCap)
|
|
||||||
actual := shared.CreateHeaderCheckedPredicateSQL(columns, constants.HeaderRecheck)
|
|
||||||
Expect(actual).To(Equal(expected))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("generates a correct SQL string for rechecking headers for several columns", func() {
|
|
||||||
columns := []string{"columnA", "columnB"}
|
|
||||||
expected := fmt.Sprintf(" (columnA<%s OR columnB<%s)", constants.RecheckHeaderCap, constants.RecheckHeaderCap)
|
|
||||||
actual := shared.CreateHeaderCheckedPredicateSQL(columns, constants.HeaderRecheck)
|
|
||||||
Expect(actual).To(Equal(expected))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("defaults to FALSE when there are no columns", func() {
|
|
||||||
expected := "FALSE"
|
|
||||||
actual := shared.CreateHeaderCheckedPredicateSQL([]string{}, constants.HeaderRecheck)
|
|
||||||
Expect(actual).To(Equal(expected))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
func getExpectedColumnNames() []string {
|
|
||||||
return []string{
|
|
||||||
"column_1",
|
|
||||||
"column_2",
|
|
||||||
"column_3",
|
|
||||||
"column_4",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -46,16 +46,29 @@ const (
|
|||||||
IndexEleven = "000000000000000000000000000000000000000000000000000000000000000b"
|
IndexEleven = "000000000000000000000000000000000000000000000000000000000000000b"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func AddHashedKeys(currentMappings map[common.Hash]utils.StorageValueMetadata) map[common.Hash]utils.StorageValueMetadata {
|
||||||
|
copyOfCurrentMappings := make(map[common.Hash]utils.StorageValueMetadata)
|
||||||
|
for k, v := range currentMappings {
|
||||||
|
copyOfCurrentMappings[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range copyOfCurrentMappings {
|
||||||
|
currentMappings[hashKey(k)] = v
|
||||||
|
}
|
||||||
|
return currentMappings
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashKey(key common.Hash) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(key.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
func GetMapping(indexOnContract, key string) common.Hash {
|
func GetMapping(indexOnContract, key string) common.Hash {
|
||||||
keyBytes := common.FromHex(key + indexOnContract)
|
keyBytes := common.FromHex(key + indexOnContract)
|
||||||
encoded := crypto.Keccak256(keyBytes)
|
return crypto.Keccak256Hash(keyBytes)
|
||||||
return common.BytesToHash(encoded)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetNestedMapping(indexOnContract, primaryKey, secondaryKey string) common.Hash {
|
func GetNestedMapping(indexOnContract, primaryKey, secondaryKey string) common.Hash {
|
||||||
primaryMappingIndex := crypto.Keccak256(common.FromHex(primaryKey + indexOnContract))
|
primaryMappingIndex := crypto.Keccak256(common.FromHex(primaryKey + indexOnContract))
|
||||||
secondaryMappingIndex := crypto.Keccak256(common.FromHex(secondaryKey), primaryMappingIndex)
|
return crypto.Keccak256Hash(common.FromHex(secondaryKey), primaryMappingIndex)
|
||||||
return common.BytesToHash(secondaryMappingIndex)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIncrementedKey(original common.Hash, incrementBy int64) common.Hash {
|
func GetIncrementedKey(original common.Hash, incrementBy int64) common.Hash {
|
||||||
|
|||||||
@@ -5,9 +5,31 @@ import (
|
|||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Mappings", func() {
|
var _ = Describe("Mappings", func() {
|
||||||
|
Describe("AddHashedKeys", func() {
|
||||||
|
It("returns a copy of the map with an additional slot for the hashed version of every key", func() {
|
||||||
|
fakeMap := map[common.Hash]utils.StorageValueMetadata{}
|
||||||
|
fakeStorageKey := common.HexToHash("72c72de6b203d67cb6cd54fc93300109fcc6fd6eac88e390271a3d548794d800")
|
||||||
|
var fakeMappingKey utils.Key = "fakeKey"
|
||||||
|
fakeMetadata := utils.StorageValueMetadata{
|
||||||
|
Name: "fakeName",
|
||||||
|
Keys: map[utils.Key]string{fakeMappingKey: "fakeValue"},
|
||||||
|
Type: utils.Uint48,
|
||||||
|
}
|
||||||
|
fakeMap[fakeStorageKey] = fakeMetadata
|
||||||
|
|
||||||
|
result := storage.AddHashedKeys(fakeMap)
|
||||||
|
|
||||||
|
Expect(len(result)).To(Equal(2))
|
||||||
|
expectedHashedStorageKey := common.HexToHash("2165edb4e1c37b99b60fa510d84f939dd35d5cd1d1c8f299d6456ea09df65a76")
|
||||||
|
Expect(fakeMap[fakeStorageKey]).To(Equal(fakeMetadata))
|
||||||
|
Expect(fakeMap[expectedHashedStorageKey]).To(Equal(fakeMetadata))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Describe("GetMapping", func() {
|
Describe("GetMapping", func() {
|
||||||
It("returns the storage key for a mapping when passed the mapping's index on the contract and the desired value's key", func() {
|
It("returns the storage key for a mapping when passed the mapping's index on the contract and the desired value's key", func() {
|
||||||
// ex. solidity:
|
// ex. solidity:
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type IStorageQueue interface {
|
type IStorageQueue interface {
|
||||||
Add(row utils.StorageDiffRow) error
|
Add(diff utils.StorageDiff) error
|
||||||
Delete(id int) error
|
Delete(id int) error
|
||||||
GetAll() ([]utils.StorageDiffRow, error)
|
GetAll() ([]utils.StorageDiff, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageQueue struct {
|
type StorageQueue struct {
|
||||||
@@ -35,11 +35,11 @@ func NewStorageQueue(db *postgres.DB) StorageQueue {
|
|||||||
return StorageQueue{db: db}
|
return StorageQueue{db: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (queue StorageQueue) Add(row utils.StorageDiffRow) error {
|
func (queue StorageQueue) Add(diff utils.StorageDiff) error {
|
||||||
_, err := queue.db.Exec(`INSERT INTO public.queued_storage (contract,
|
_, err := queue.db.Exec(`INSERT INTO public.queued_storage (contract,
|
||||||
block_hash, block_height, storage_key, storage_value) VALUES
|
block_hash, block_height, storage_key, storage_value) VALUES
|
||||||
($1, $2, $3, $4, $5) ON CONFLICT DO NOTHING`, row.Contract.Bytes(), row.BlockHash.Bytes(),
|
($1, $2, $3, $4, $5) ON CONFLICT DO NOTHING`, diff.HashedAddress.Bytes(), diff.BlockHash.Bytes(),
|
||||||
row.BlockHeight, row.StorageKey.Bytes(), row.StorageValue.Bytes())
|
diff.BlockHeight, diff.StorageKey.Bytes(), diff.StorageValue.Bytes())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,8 +48,8 @@ func (queue StorageQueue) Delete(id int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (queue StorageQueue) GetAll() ([]utils.StorageDiffRow, error) {
|
func (queue StorageQueue) GetAll() ([]utils.StorageDiff, error) {
|
||||||
var result []utils.StorageDiffRow
|
var result []utils.StorageDiff
|
||||||
err := queue.db.Select(&result, `SELECT * FROM public.queued_storage`)
|
err := queue.db.Select(&result, `SELECT * FROM public.queued_storage`)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
@@ -30,35 +29,36 @@ import (
|
|||||||
var _ = Describe("Storage queue", func() {
|
var _ = Describe("Storage queue", func() {
|
||||||
var (
|
var (
|
||||||
db *postgres.DB
|
db *postgres.DB
|
||||||
row utils.StorageDiffRow
|
diff utils.StorageDiff
|
||||||
queue storage.IStorageQueue
|
queue storage.IStorageQueue
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
row = utils.StorageDiffRow{
|
fakeAddr := "0x123456"
|
||||||
Contract: common.HexToAddress("0x123456"),
|
diff = utils.StorageDiff{
|
||||||
BlockHash: common.HexToHash("0x678901"),
|
HashedAddress: utils.HexToKeccak256Hash(fakeAddr),
|
||||||
BlockHeight: 987,
|
BlockHash: common.HexToHash("0x678901"),
|
||||||
StorageKey: common.HexToHash("0x654321"),
|
BlockHeight: 987,
|
||||||
StorageValue: common.HexToHash("0x198765"),
|
StorageKey: common.HexToHash("0x654321"),
|
||||||
|
StorageValue: common.HexToHash("0x198765"),
|
||||||
}
|
}
|
||||||
db = test_config.NewTestDB(test_config.NewTestNode())
|
db = test_config.NewTestDB(test_config.NewTestNode())
|
||||||
test_config.CleanTestDB(db)
|
test_config.CleanTestDB(db)
|
||||||
queue = storage.NewStorageQueue(db)
|
queue = storage.NewStorageQueue(db)
|
||||||
addErr := queue.Add(row)
|
addErr := queue.Add(diff)
|
||||||
Expect(addErr).NotTo(HaveOccurred())
|
Expect(addErr).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("Add", func() {
|
Describe("Add", func() {
|
||||||
It("adds a storage row to the db", func() {
|
It("adds a storage diff to the db", func() {
|
||||||
var result utils.StorageDiffRow
|
var result utils.StorageDiff
|
||||||
getErr := db.Get(&result, `SELECT contract, block_hash, block_height, storage_key, storage_value FROM public.queued_storage`)
|
getErr := db.Get(&result, `SELECT contract, block_hash, block_height, storage_key, storage_value FROM public.queued_storage`)
|
||||||
Expect(getErr).NotTo(HaveOccurred())
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
Expect(result).To(Equal(row))
|
Expect(result).To(Equal(diff))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("does not duplicate storage rows", func() {
|
It("does not duplicate storage diffs", func() {
|
||||||
addErr := queue.Add(row)
|
addErr := queue.Add(diff)
|
||||||
Expect(addErr).NotTo(HaveOccurred())
|
Expect(addErr).NotTo(HaveOccurred())
|
||||||
var count int
|
var count int
|
||||||
getErr := db.Get(&count, `SELECT count(*) FROM public.queued_storage`)
|
getErr := db.Get(&count, `SELECT count(*) FROM public.queued_storage`)
|
||||||
@@ -67,12 +67,12 @@ var _ = Describe("Storage queue", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
It("deletes storage row from db", func() {
|
It("deletes storage diff from db", func() {
|
||||||
rows, getErr := queue.GetAll()
|
diffs, getErr := queue.GetAll()
|
||||||
Expect(getErr).NotTo(HaveOccurred())
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
Expect(len(rows)).To(Equal(1))
|
Expect(len(diffs)).To(Equal(1))
|
||||||
|
|
||||||
err := queue.Delete(rows[0].Id)
|
err := queue.Delete(diffs[0].Id)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
remainingRows, secondGetErr := queue.GetAll()
|
remainingRows, secondGetErr := queue.GetAll()
|
||||||
@@ -80,33 +80,34 @@ var _ = Describe("Storage queue", func() {
|
|||||||
Expect(len(remainingRows)).To(BeZero())
|
Expect(len(remainingRows)).To(BeZero())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("gets all storage rows from db", func() {
|
It("gets all storage diffs from db", func() {
|
||||||
rowTwo := utils.StorageDiffRow{
|
fakeAddr := "0x234567"
|
||||||
Contract: common.HexToAddress("0x123456"),
|
diffTwo := utils.StorageDiff{
|
||||||
BlockHash: common.HexToHash("0x678902"),
|
HashedAddress: utils.HexToKeccak256Hash(fakeAddr),
|
||||||
BlockHeight: 988,
|
BlockHash: common.HexToHash("0x678902"),
|
||||||
StorageKey: common.HexToHash("0x654322"),
|
BlockHeight: 988,
|
||||||
StorageValue: common.HexToHash("0x198766"),
|
StorageKey: common.HexToHash("0x654322"),
|
||||||
|
StorageValue: common.HexToHash("0x198766"),
|
||||||
}
|
}
|
||||||
addErr := queue.Add(rowTwo)
|
addErr := queue.Add(diffTwo)
|
||||||
Expect(addErr).NotTo(HaveOccurred())
|
Expect(addErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
rows, err := queue.GetAll()
|
diffs, err := queue.GetAll()
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(len(rows)).To(Equal(2))
|
Expect(len(diffs)).To(Equal(2))
|
||||||
Expect(rows[0]).NotTo(Equal(rows[1]))
|
Expect(diffs[0]).NotTo(Equal(diffs[1]))
|
||||||
Expect(rows[0].Id).NotTo(BeZero())
|
Expect(diffs[0].Id).NotTo(BeZero())
|
||||||
Expect(rows[0].Contract).To(Or(Equal(row.Contract), Equal(rowTwo.Contract)))
|
Expect(diffs[0].HashedAddress).To(Or(Equal(diff.HashedAddress), Equal(diffTwo.HashedAddress)))
|
||||||
Expect(rows[0].BlockHash).To(Or(Equal(row.BlockHash), Equal(rowTwo.BlockHash)))
|
Expect(diffs[0].BlockHash).To(Or(Equal(diff.BlockHash), Equal(diffTwo.BlockHash)))
|
||||||
Expect(rows[0].BlockHeight).To(Or(Equal(row.BlockHeight), Equal(rowTwo.BlockHeight)))
|
Expect(diffs[0].BlockHeight).To(Or(Equal(diff.BlockHeight), Equal(diffTwo.BlockHeight)))
|
||||||
Expect(rows[0].StorageKey).To(Or(Equal(row.StorageKey), Equal(rowTwo.StorageKey)))
|
Expect(diffs[0].StorageKey).To(Or(Equal(diff.StorageKey), Equal(diffTwo.StorageKey)))
|
||||||
Expect(rows[0].StorageValue).To(Or(Equal(row.StorageValue), Equal(rowTwo.StorageValue)))
|
Expect(diffs[0].StorageValue).To(Or(Equal(diff.StorageValue), Equal(diffTwo.StorageValue)))
|
||||||
Expect(rows[1].Id).NotTo(BeZero())
|
Expect(diffs[1].Id).NotTo(BeZero())
|
||||||
Expect(rows[1].Contract).To(Or(Equal(row.Contract), Equal(rowTwo.Contract)))
|
Expect(diffs[1].HashedAddress).To(Or(Equal(diff.HashedAddress), Equal(diffTwo.HashedAddress)))
|
||||||
Expect(rows[1].BlockHash).To(Or(Equal(row.BlockHash), Equal(rowTwo.BlockHash)))
|
Expect(diffs[1].BlockHash).To(Or(Equal(diff.BlockHash), Equal(diffTwo.BlockHash)))
|
||||||
Expect(rows[1].BlockHeight).To(Or(Equal(row.BlockHeight), Equal(rowTwo.BlockHeight)))
|
Expect(diffs[1].BlockHeight).To(Or(Equal(diff.BlockHeight), Equal(diffTwo.BlockHeight)))
|
||||||
Expect(rows[1].StorageKey).To(Or(Equal(row.StorageKey), Equal(rowTwo.StorageKey)))
|
Expect(diffs[1].StorageKey).To(Or(Equal(diff.StorageKey), Equal(diffTwo.StorageKey)))
|
||||||
Expect(rows[1].StorageValue).To(Or(Equal(row.StorageValue), Equal(rowTwo.StorageValue)))
|
Expect(diffs[1].StorageValue).To(Or(Equal(diff.StorageValue), Equal(diffTwo.StorageValue)))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,20 +27,20 @@ const (
|
|||||||
bitsPerByte = 8
|
bitsPerByte = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
func Decode(row StorageDiffRow, metadata StorageValueMetadata) (interface{}, error) {
|
func Decode(diff StorageDiff, metadata StorageValueMetadata) (interface{}, error) {
|
||||||
switch metadata.Type {
|
switch metadata.Type {
|
||||||
case Uint256:
|
case Uint256:
|
||||||
return decodeInteger(row.StorageValue.Bytes()), nil
|
return decodeInteger(diff.StorageValue.Bytes()), nil
|
||||||
case Uint48:
|
case Uint48:
|
||||||
return decodeInteger(row.StorageValue.Bytes()), nil
|
return decodeInteger(diff.StorageValue.Bytes()), nil
|
||||||
case Uint128:
|
case Uint128:
|
||||||
return decodeInteger(row.StorageValue.Bytes()), nil
|
return decodeInteger(diff.StorageValue.Bytes()), nil
|
||||||
case Address:
|
case Address:
|
||||||
return decodeAddress(row.StorageValue.Bytes()), nil
|
return decodeAddress(diff.StorageValue.Bytes()), nil
|
||||||
case Bytes32:
|
case Bytes32:
|
||||||
return row.StorageValue.Hex(), nil
|
return diff.StorageValue.Hex(), nil
|
||||||
case PackedSlot:
|
case PackedSlot:
|
||||||
return decodePackedSlot(row.StorageValue.Bytes(), metadata.PackedTypes), nil
|
return decodePackedSlot(diff.StorageValue.Bytes(), metadata.PackedTypes), nil
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("can't decode unknown type: %d", metadata.Type))
|
panic(fmt.Sprintf("can't decode unknown type: %d", metadata.Type))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ import (
|
|||||||
var _ = Describe("Storage decoder", func() {
|
var _ = Describe("Storage decoder", func() {
|
||||||
It("decodes uint256", func() {
|
It("decodes uint256", func() {
|
||||||
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000539")
|
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000539")
|
||||||
row := utils.StorageDiffRow{StorageValue: fakeInt}
|
diff := utils.StorageDiff{StorageValue: fakeInt}
|
||||||
metadata := utils.StorageValueMetadata{Type: utils.Uint256}
|
metadata := utils.StorageValueMetadata{Type: utils.Uint256}
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
result, err := utils.Decode(diff, metadata)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
||||||
@@ -40,10 +40,10 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
|
|
||||||
It("decodes uint128", func() {
|
It("decodes uint128", func() {
|
||||||
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000011123")
|
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000011123")
|
||||||
row := utils.StorageDiffRow{StorageValue: fakeInt}
|
diff := utils.StorageDiff{StorageValue: fakeInt}
|
||||||
metadata := utils.StorageValueMetadata{Type: utils.Uint128}
|
metadata := utils.StorageValueMetadata{Type: utils.Uint128}
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
result, err := utils.Decode(diff, metadata)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
||||||
@@ -51,10 +51,10 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
|
|
||||||
It("decodes uint48", func() {
|
It("decodes uint48", func() {
|
||||||
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000123")
|
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000123")
|
||||||
row := utils.StorageDiffRow{StorageValue: fakeInt}
|
diff := utils.StorageDiff{StorageValue: fakeInt}
|
||||||
metadata := utils.StorageValueMetadata{Type: utils.Uint48}
|
metadata := utils.StorageValueMetadata{Type: utils.Uint48}
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
result, err := utils.Decode(diff, metadata)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
||||||
@@ -62,10 +62,10 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
|
|
||||||
It("decodes address", func() {
|
It("decodes address", func() {
|
||||||
fakeAddress := common.HexToAddress("0x12345")
|
fakeAddress := common.HexToAddress("0x12345")
|
||||||
row := utils.StorageDiffRow{StorageValue: fakeAddress.Hash()}
|
diff := utils.StorageDiff{StorageValue: fakeAddress.Hash()}
|
||||||
metadata := utils.StorageValueMetadata{Type: utils.Address}
|
metadata := utils.StorageValueMetadata{Type: utils.Address}
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
result, err := utils.Decode(diff, metadata)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(result).To(Equal(fakeAddress.Hex()))
|
Expect(result).To(Equal(fakeAddress.Hex()))
|
||||||
@@ -75,7 +75,7 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
It("decodes uint48 items", func() {
|
It("decodes uint48 items", func() {
|
||||||
//this is a real storage data example
|
//this is a real storage data example
|
||||||
packedStorage := common.HexToHash("000000000000000000000000000000000000000000000002a300000000002a30")
|
packedStorage := common.HexToHash("000000000000000000000000000000000000000000000002a300000000002a30")
|
||||||
row := utils.StorageDiffRow{StorageValue: packedStorage}
|
diff := utils.StorageDiff{StorageValue: packedStorage}
|
||||||
packedTypes := map[int]utils.ValueType{}
|
packedTypes := map[int]utils.ValueType{}
|
||||||
packedTypes[0] = utils.Uint48
|
packedTypes[0] = utils.Uint48
|
||||||
packedTypes[1] = utils.Uint48
|
packedTypes[1] = utils.Uint48
|
||||||
@@ -85,7 +85,7 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
PackedTypes: packedTypes,
|
PackedTypes: packedTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
result, err := utils.Decode(diff, metadata)
|
||||||
decodedValues := result.(map[int]string)
|
decodedValues := result.(map[int]string)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
@@ -99,7 +99,7 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
packedStorageHex := "0000000A5D1AFFFFFFFFFFFE00000009F3C600000002A300000000002A30"
|
packedStorageHex := "0000000A5D1AFFFFFFFFFFFE00000009F3C600000002A300000000002A30"
|
||||||
|
|
||||||
packedStorage := common.HexToHash(packedStorageHex)
|
packedStorage := common.HexToHash(packedStorageHex)
|
||||||
row := utils.StorageDiffRow{StorageValue: packedStorage}
|
diff := utils.StorageDiff{StorageValue: packedStorage}
|
||||||
packedTypes := map[int]utils.ValueType{}
|
packedTypes := map[int]utils.ValueType{}
|
||||||
packedTypes[0] = utils.Uint48
|
packedTypes[0] = utils.Uint48
|
||||||
packedTypes[1] = utils.Uint48
|
packedTypes[1] = utils.Uint48
|
||||||
@@ -112,7 +112,7 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
PackedTypes: packedTypes,
|
PackedTypes: packedTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
result, err := utils.Decode(diff, metadata)
|
||||||
decodedValues := result.(map[int]string)
|
decodedValues := result.(map[int]string)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
@@ -129,7 +129,7 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
packedStorageHex := "000000038D7EA4C67FF8E502B6730000" +
|
packedStorageHex := "000000038D7EA4C67FF8E502B6730000" +
|
||||||
"0000000000000000AB54A98CEB1F0AD2"
|
"0000000000000000AB54A98CEB1F0AD2"
|
||||||
packedStorage := common.HexToHash(packedStorageHex)
|
packedStorage := common.HexToHash(packedStorageHex)
|
||||||
row := utils.StorageDiffRow{StorageValue: packedStorage}
|
diff := utils.StorageDiff{StorageValue: packedStorage}
|
||||||
packedTypes := map[int]utils.ValueType{}
|
packedTypes := map[int]utils.ValueType{}
|
||||||
packedTypes[0] = utils.Uint128
|
packedTypes[0] = utils.Uint128
|
||||||
packedTypes[1] = utils.Uint128
|
packedTypes[1] = utils.Uint128
|
||||||
@@ -139,7 +139,7 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
PackedTypes: packedTypes,
|
PackedTypes: packedTypes,
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
result, err := utils.Decode(diff, metadata)
|
||||||
decodedValues := result.(map[int]string)
|
decodedValues := result.(map[int]string)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
@@ -151,7 +151,7 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
//TODO: replace with real data when available
|
//TODO: replace with real data when available
|
||||||
addressHex := "0000000000000000000000000000000000012345"
|
addressHex := "0000000000000000000000000000000000012345"
|
||||||
packedStorage := common.HexToHash("00000002a300" + "000000002a30" + addressHex)
|
packedStorage := common.HexToHash("00000002a300" + "000000002a30" + addressHex)
|
||||||
row := utils.StorageDiffRow{StorageValue: packedStorage}
|
row := utils.StorageDiff{StorageValue: packedStorage}
|
||||||
packedTypes := map[int]utils.ValueType{}
|
packedTypes := map[int]utils.ValueType{}
|
||||||
packedTypes[0] = utils.Address
|
packedTypes[0] = utils.Address
|
||||||
packedTypes[1] = utils.Uint48
|
packedTypes[1] = utils.Uint48
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ExpectedRowLength = 5
|
||||||
|
|
||||||
|
type StorageDiff struct {
|
||||||
|
Id int
|
||||||
|
HashedAddress common.Hash `db:"contract"`
|
||||||
|
BlockHash common.Hash `db:"block_hash"`
|
||||||
|
BlockHeight int `db:"block_height"`
|
||||||
|
StorageKey common.Hash `db:"storage_key"`
|
||||||
|
StorageValue common.Hash `db:"storage_value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromParityCsvRow(csvRow []string) (StorageDiff, error) {
|
||||||
|
if len(csvRow) != ExpectedRowLength {
|
||||||
|
return StorageDiff{}, ErrRowMalformed{Length: len(csvRow)}
|
||||||
|
}
|
||||||
|
height, err := strconv.Atoi(csvRow[2])
|
||||||
|
if err != nil {
|
||||||
|
return StorageDiff{}, err
|
||||||
|
}
|
||||||
|
return StorageDiff{
|
||||||
|
HashedAddress: HexToKeccak256Hash(csvRow[0]),
|
||||||
|
BlockHash: common.HexToHash(csvRow[1]),
|
||||||
|
BlockHeight: height,
|
||||||
|
StorageKey: common.HexToHash(csvRow[3]),
|
||||||
|
StorageValue: common.HexToHash(csvRow[4]),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromGethStateDiff(account statediff.AccountDiff, stateDiff *statediff.StateDiff, storage statediff.StorageDiff) (StorageDiff, error) {
|
||||||
|
var decodedValue []byte
|
||||||
|
err := rlp.DecodeBytes(storage.Value, &decodedValue)
|
||||||
|
if err != nil {
|
||||||
|
return StorageDiff{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return StorageDiff{
|
||||||
|
HashedAddress: common.BytesToHash(account.Key),
|
||||||
|
BlockHash: stateDiff.BlockHash,
|
||||||
|
BlockHeight: int(stateDiff.BlockNumber.Int64()),
|
||||||
|
StorageKey: common.BytesToHash(storage.Key),
|
||||||
|
StorageValue: common.BytesToHash(decodedValue),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func HexToKeccak256Hash(hex string) common.Hash {
|
||||||
|
return crypto.Keccak256Hash(common.FromHex(hex))
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2019 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 utils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/test_data"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Storage row parsing", func() {
|
||||||
|
Describe("FromParityCsvRow", func() {
|
||||||
|
It("converts an array of strings to a row struct", func() {
|
||||||
|
contract := "0x123"
|
||||||
|
blockHash := "0x456"
|
||||||
|
blockHeight := "789"
|
||||||
|
storageKey := "0x987"
|
||||||
|
storageValue := "0x654"
|
||||||
|
data := []string{contract, blockHash, blockHeight, storageKey, storageValue}
|
||||||
|
|
||||||
|
result, err := utils.FromParityCsvRow(data)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
expectedKeccakOfContractAddress := utils.HexToKeccak256Hash(contract)
|
||||||
|
Expect(result.HashedAddress).To(Equal(expectedKeccakOfContractAddress))
|
||||||
|
Expect(result.BlockHash).To(Equal(common.HexToHash(blockHash)))
|
||||||
|
Expect(result.BlockHeight).To(Equal(789))
|
||||||
|
Expect(result.StorageKey).To(Equal(common.HexToHash(storageKey)))
|
||||||
|
Expect(result.StorageValue).To(Equal(common.HexToHash(storageValue)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns an error if row is missing data", func() {
|
||||||
|
_, err := utils.FromParityCsvRow([]string{"0x123"})
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(utils.ErrRowMalformed{Length: 1}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if block height malformed", func() {
|
||||||
|
_, err := utils.FromParityCsvRow([]string{"", "", "", "", ""})
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("FromGethStateDiff", func() {
|
||||||
|
var (
|
||||||
|
accountDiff = statediff.AccountDiff{Key: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}}
|
||||||
|
stateDiff = &statediff.StateDiff{
|
||||||
|
BlockNumber: big.NewInt(rand.Int63()),
|
||||||
|
BlockHash: fakes.FakeHash,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
It("adds relevant fields to diff", func() {
|
||||||
|
storageValueBytes := []byte{3}
|
||||||
|
storageValueRlp, encodeErr := rlp.EncodeToBytes(storageValueBytes)
|
||||||
|
Expect(encodeErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
storageDiff := statediff.StorageDiff{
|
||||||
|
Key: []byte{0, 9, 8, 7, 6, 5, 4, 3, 2, 1},
|
||||||
|
Value: storageValueRlp,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := utils.FromGethStateDiff(accountDiff, stateDiff, storageDiff)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
expectedAddress := common.BytesToHash(accountDiff.Key)
|
||||||
|
Expect(result.HashedAddress).To(Equal(expectedAddress))
|
||||||
|
Expect(result.BlockHash).To(Equal(fakes.FakeHash))
|
||||||
|
expectedBlockHeight := int(stateDiff.BlockNumber.Int64())
|
||||||
|
Expect(result.BlockHeight).To(Equal(expectedBlockHeight))
|
||||||
|
expectedStorageKey := common.BytesToHash(storageDiff.Key)
|
||||||
|
Expect(result.StorageKey).To(Equal(expectedStorageKey))
|
||||||
|
expectedStorageValue := common.BytesToHash(storageValueBytes)
|
||||||
|
Expect(result.StorageValue).To(Equal(expectedStorageValue))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("handles decoding large storage values from their RLP", func() {
|
||||||
|
storageValueBytes := []byte{1, 2, 3, 4, 5, 0, 9, 8, 7, 6}
|
||||||
|
storageValueRlp, encodeErr := rlp.EncodeToBytes(storageValueBytes)
|
||||||
|
Expect(encodeErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
storageDiff := statediff.StorageDiff{
|
||||||
|
Key: []byte{0, 9, 8, 7, 6, 5, 4, 3, 2, 1},
|
||||||
|
Value: storageValueRlp,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := utils.FromGethStateDiff(accountDiff, stateDiff, storageDiff)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(result.StorageValue).To(Equal(common.BytesToHash(storageValueBytes)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns an err if decoding the storage value Rlp fails", func() {
|
||||||
|
_, err := utils.FromGethStateDiff(accountDiff, stateDiff, test_data.StorageWithBadValue)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError("rlp: input contains more than one value"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
// VulcanizeDB
|
|
||||||
// Copyright © 2019 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 utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ExpectedRowLength = 5
|
|
||||||
|
|
||||||
type StorageDiffRow struct {
|
|
||||||
Id int
|
|
||||||
Contract common.Address
|
|
||||||
BlockHash common.Hash `db:"block_hash"`
|
|
||||||
BlockHeight int `db:"block_height"`
|
|
||||||
StorageKey common.Hash `db:"storage_key"`
|
|
||||||
StorageValue common.Hash `db:"storage_value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromStrings(csvRow []string) (StorageDiffRow, error) {
|
|
||||||
if len(csvRow) != ExpectedRowLength {
|
|
||||||
return StorageDiffRow{}, ErrRowMalformed{Length: len(csvRow)}
|
|
||||||
}
|
|
||||||
height, err := strconv.Atoi(csvRow[2])
|
|
||||||
if err != nil {
|
|
||||||
return StorageDiffRow{}, err
|
|
||||||
}
|
|
||||||
return StorageDiffRow{
|
|
||||||
Contract: common.HexToAddress(csvRow[0]),
|
|
||||||
BlockHash: common.HexToHash(csvRow[1]),
|
|
||||||
BlockHeight: height,
|
|
||||||
StorageKey: common.HexToHash(csvRow[3]),
|
|
||||||
StorageValue: common.HexToHash(csvRow[4]),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
// VulcanizeDB
|
|
||||||
// Copyright © 2019 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 utils_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
. "github.com/onsi/ginkgo"
|
|
||||||
. "github.com/onsi/gomega"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Describe("Storage row parsing", func() {
|
|
||||||
It("converts an array of strings to a row struct", func() {
|
|
||||||
contract := "0x123"
|
|
||||||
blockHash := "0x456"
|
|
||||||
blockHeight := "789"
|
|
||||||
storageKey := "0x987"
|
|
||||||
storageValue := "0x654"
|
|
||||||
data := []string{contract, blockHash, blockHeight, storageKey, storageValue}
|
|
||||||
|
|
||||||
result, err := utils.FromStrings(data)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(result.Contract).To(Equal(common.HexToAddress(contract)))
|
|
||||||
Expect(result.BlockHash).To(Equal(common.HexToHash(blockHash)))
|
|
||||||
Expect(result.BlockHeight).To(Equal(789))
|
|
||||||
Expect(result.StorageKey).To(Equal(common.HexToHash(storageKey)))
|
|
||||||
Expect(result.StorageValue).To(Equal(common.HexToHash(storageValue)))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("returns an error if row is missing data", func() {
|
|
||||||
_, err := utils.FromStrings([]string{"0x123"})
|
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err).To(MatchError(utils.ErrRowMalformed{Length: 1}))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("returns error if block height malformed", func() {
|
|
||||||
_, err := utils.FromStrings([]string{"", "", "", "", ""})
|
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2019 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package streamer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Streamer interface {
|
||||||
|
Stream(chan statediff.Payload) (*rpc.ClientSubscription, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type StateDiffStreamer struct {
|
||||||
|
client core.RpcClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (streamer *StateDiffStreamer) Stream(payloadChan chan statediff.Payload) (*rpc.ClientSubscription, error) {
|
||||||
|
logrus.Info("streaming diffs from geth")
|
||||||
|
return streamer.client.Subscribe("statediff", payloadChan, "stream")
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStateDiffStreamer(client core.RpcClient) StateDiffStreamer {
|
||||||
|
return StateDiffStreamer{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2019 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package streamer_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/streamer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("StateDiff Streamer", func() {
|
||||||
|
It("subscribes to the geth statediff service", func() {
|
||||||
|
client := &fakes.MockRpcClient{}
|
||||||
|
streamer := streamer.NewStateDiffStreamer(client)
|
||||||
|
payloadChan := make(chan statediff.Payload)
|
||||||
|
_, err := streamer.Stream(payloadChan)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
client.AssertSubscribeCalledWith("statediff", payloadChan, []interface{}{"stream"})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package streamer_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStreamer(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "Streamer Suite")
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func() {
|
||||||
|
logrus.SetOutput(ioutil.Discard)
|
||||||
|
})
|
||||||
@@ -17,41 +17,54 @@
|
|||||||
package test_data
|
package test_data
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GenericModel struct{}
|
type GenericModel struct{}
|
||||||
type GenericEntity struct{}
|
type GenericEntity struct{}
|
||||||
|
|
||||||
var startingBlockNumber = rand.Int63()
|
var startingBlockNumber = rand.Int63()
|
||||||
var topic = "0x" + randomString(64)
|
var topic0 = "0x" + randomString(64)
|
||||||
var address = "0x" + randomString(38)
|
|
||||||
|
|
||||||
var GenericTestLogs = []types.Log{{
|
var GenericTestLog = func() types.Log {
|
||||||
Address: common.HexToAddress(address),
|
return types.Log{
|
||||||
Topics: []common.Hash{common.HexToHash(topic)},
|
Address: fakeAddress(),
|
||||||
BlockNumber: uint64(startingBlockNumber),
|
Topics: []common.Hash{common.HexToHash(topic0), fakeHash()},
|
||||||
}}
|
Data: hexutil.MustDecode(fakeHash().Hex()),
|
||||||
|
BlockNumber: uint64(startingBlockNumber),
|
||||||
|
TxHash: fakeHash(),
|
||||||
|
TxIndex: uint(rand.Int31()),
|
||||||
|
BlockHash: fakeHash(),
|
||||||
|
Index: uint(rand.Int31()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var GenericTestConfig = transformer.EventTransformerConfig{
|
var GenericTestConfig = transformer.EventTransformerConfig{
|
||||||
TransformerName: "generic-test-transformer",
|
TransformerName: "generic-test-transformer",
|
||||||
ContractAddresses: []string{address},
|
ContractAddresses: []string{fakeAddress().Hex()},
|
||||||
ContractAbi: randomString(100),
|
ContractAbi: randomString(100),
|
||||||
Topic: topic,
|
Topic: topic0,
|
||||||
StartingBlockNumber: startingBlockNumber,
|
StartingBlockNumber: startingBlockNumber,
|
||||||
EndingBlockNumber: startingBlockNumber + 1,
|
EndingBlockNumber: startingBlockNumber + 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fakeAddress() common.Address {
|
||||||
|
return common.HexToAddress("0x" + randomString(40))
|
||||||
|
}
|
||||||
|
|
||||||
|
func fakeHash() common.Hash {
|
||||||
|
return common.HexToHash("0x" + randomString(64))
|
||||||
|
}
|
||||||
|
|
||||||
func randomString(length int) string {
|
func randomString(length int) string {
|
||||||
var seededRand = rand.New(
|
var seededRand = rand.New(
|
||||||
rand.NewSource(time.Now().UnixNano()))
|
rand.NewSource(time.Now().UnixNano()))
|
||||||
charset := "abcdefghijklmnopqrstuvwxyz1234567890"
|
charset := "abcdef1234567890"
|
||||||
b := make([]byte, length)
|
b := make([]byte, length)
|
||||||
for i := range b {
|
for i := range b {
|
||||||
b[i] = charset[seededRand.Intn(len(charset))]
|
b[i] = charset[seededRand.Intn(len(charset))]
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
// Copyright 2018 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package test_data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
BlockNumber = big.NewInt(rand.Int63())
|
||||||
|
BlockHash = "0xfa40fbe2d98d98b3363a778d52f2bcd29d6790b9b3f3cab2b167fd12d3550f73"
|
||||||
|
CodeHash = common.Hex2Bytes("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
|
||||||
|
NewNonceValue = rand.Uint64()
|
||||||
|
NewBalanceValue = rand.Int63()
|
||||||
|
ContractRoot = common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||||
|
StoragePath = common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").Bytes()
|
||||||
|
StorageKey = common.HexToHash("0000000000000000000000000000000000000000000000000000000000000001").Bytes()
|
||||||
|
SmallStorageValue = common.Hex2Bytes("03")
|
||||||
|
SmallStorageValueRlp, _ = rlp.EncodeToBytes(SmallStorageValue)
|
||||||
|
storageWithSmallValue = []statediff.StorageDiff{{
|
||||||
|
Key: StorageKey,
|
||||||
|
Value: SmallStorageValueRlp,
|
||||||
|
Path: StoragePath,
|
||||||
|
Proof: [][]byte{},
|
||||||
|
}}
|
||||||
|
LargeStorageValue = common.Hex2Bytes("00191b53778c567b14b50ba0000")
|
||||||
|
LargeStorageValueRlp, rlpErr = rlp.EncodeToBytes(LargeStorageValue)
|
||||||
|
storageWithLargeValue = []statediff.StorageDiff{{
|
||||||
|
Key: StorageKey,
|
||||||
|
Value: LargeStorageValueRlp,
|
||||||
|
Path: StoragePath,
|
||||||
|
Proof: [][]byte{},
|
||||||
|
}}
|
||||||
|
EmptyStorage = make([]statediff.StorageDiff, 0)
|
||||||
|
StorageWithBadValue = statediff.StorageDiff{
|
||||||
|
Key: StorageKey,
|
||||||
|
Value: []byte{0, 1, 2},
|
||||||
|
// this storage value will fail to be decoded as an RLP with the following error message:
|
||||||
|
// "input contains more than one value"
|
||||||
|
}
|
||||||
|
contractAddress = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592")
|
||||||
|
ContractLeafKey = crypto.Keccak256Hash(contractAddress[:])
|
||||||
|
anotherContractAddress = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476593")
|
||||||
|
AnotherContractLeafKey = crypto.Keccak256Hash(anotherContractAddress[:])
|
||||||
|
|
||||||
|
testAccount = state.Account{
|
||||||
|
Nonce: NewNonceValue,
|
||||||
|
Balance: big.NewInt(NewBalanceValue),
|
||||||
|
Root: ContractRoot,
|
||||||
|
CodeHash: CodeHash,
|
||||||
|
}
|
||||||
|
valueBytes, _ = rlp.EncodeToBytes(testAccount)
|
||||||
|
CreatedAccountDiffs = []statediff.AccountDiff{
|
||||||
|
{
|
||||||
|
Key: ContractLeafKey.Bytes(),
|
||||||
|
Value: valueBytes,
|
||||||
|
Storage: storageWithSmallValue,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdatedAccountDiffs = []statediff.AccountDiff{{
|
||||||
|
Key: AnotherContractLeafKey.Bytes(),
|
||||||
|
Value: valueBytes,
|
||||||
|
Storage: storageWithLargeValue,
|
||||||
|
}}
|
||||||
|
|
||||||
|
DeletedAccountDiffs = []statediff.AccountDiff{{
|
||||||
|
Key: AnotherContractLeafKey.Bytes(),
|
||||||
|
Value: valueBytes,
|
||||||
|
Storage: storageWithSmallValue,
|
||||||
|
}}
|
||||||
|
|
||||||
|
MockStateDiff = statediff.StateDiff{
|
||||||
|
BlockNumber: BlockNumber,
|
||||||
|
BlockHash: common.HexToHash(BlockHash),
|
||||||
|
CreatedAccounts: CreatedAccountDiffs,
|
||||||
|
DeletedAccounts: DeletedAccountDiffs,
|
||||||
|
UpdatedAccounts: UpdatedAccountDiffs,
|
||||||
|
}
|
||||||
|
MockStateDiffBytes, _ = rlp.EncodeToBytes(MockStateDiff)
|
||||||
|
|
||||||
|
mockTransaction1 = types.NewTransaction(0, common.HexToAddress("0x0"), big.NewInt(1000), 50, big.NewInt(100), nil)
|
||||||
|
mockTransaction2 = types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(2000), 100, big.NewInt(200), nil)
|
||||||
|
MockTransactions = types.Transactions{mockTransaction1, mockTransaction2}
|
||||||
|
|
||||||
|
mockReceipt1 = types.NewReceipt(common.HexToHash("0x0").Bytes(), false, 50)
|
||||||
|
mockReceipt2 = types.NewReceipt(common.HexToHash("0x1").Bytes(), false, 100)
|
||||||
|
MockReceipts = types.Receipts{mockReceipt1, mockReceipt2}
|
||||||
|
|
||||||
|
MockHeader = types.Header{
|
||||||
|
Time: 0,
|
||||||
|
Number: BlockNumber,
|
||||||
|
Root: common.HexToHash("0x0"),
|
||||||
|
TxHash: common.HexToHash("0x0"),
|
||||||
|
ReceiptHash: common.HexToHash("0x0"),
|
||||||
|
}
|
||||||
|
MockBlock = types.NewBlock(&MockHeader, MockTransactions, nil, MockReceipts)
|
||||||
|
MockBlockRlp, _ = rlp.EncodeToBytes(MockBlock)
|
||||||
|
|
||||||
|
MockStatediffPayload = statediff.Payload{
|
||||||
|
BlockRlp: MockBlockRlp,
|
||||||
|
StateDiffRlp: MockStateDiffBytes,
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
EmptyStatediffPayload = statediff.Payload{
|
||||||
|
BlockRlp: []byte{},
|
||||||
|
StateDiffRlp: []byte{},
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrStatediffPayload = statediff.Payload{
|
||||||
|
BlockRlp: []byte{},
|
||||||
|
StateDiffRlp: []byte{},
|
||||||
|
Err: errors.New("mock error"),
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -18,14 +18,12 @@ package transformer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EventTransformer interface {
|
type EventTransformer interface {
|
||||||
Execute(logs []types.Log, header core.Header) error
|
Execute(logs []core.HeaderSyncLog) error
|
||||||
GetConfig() EventTransformerConfig
|
GetConfig() EventTransformerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,14 +18,13 @@ package transformer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StorageTransformer interface {
|
type StorageTransformer interface {
|
||||||
Execute(row utils.StorageDiffRow) error
|
Execute(diff utils.StorageDiff) error
|
||||||
ContractAddress() common.Address
|
KeccakContractAddress() common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageTransformerInitializer func(db *postgres.DB) StorageTransformer
|
type StorageTransformerInitializer func(db *postgres.DB) StorageTransformer
|
||||||
|
|||||||
@@ -17,137 +17,110 @@
|
|||||||
package watcher
|
package watcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transactions"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/chunker"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/chunker"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/logs"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transactions"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const NoNewDataPause = time.Second * 7
|
||||||
|
|
||||||
type EventWatcher struct {
|
type EventWatcher struct {
|
||||||
Transformers []transformer.EventTransformer
|
blockChain core.BlockChain
|
||||||
BlockChain core.BlockChain
|
db *postgres.DB
|
||||||
DB *postgres.DB
|
LogDelegator logs.ILogDelegator
|
||||||
Fetcher fetcher.ILogFetcher
|
LogExtractor logs.ILogExtractor
|
||||||
Chunker chunker.Chunker
|
|
||||||
Addresses []common.Address
|
|
||||||
Topics []common.Hash
|
|
||||||
StartingBlock *int64
|
|
||||||
Syncer transactions.ITransactionsSyncer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEventWatcher(db *postgres.DB, bc core.BlockChain) EventWatcher {
|
func NewEventWatcher(db *postgres.DB, bc core.BlockChain) EventWatcher {
|
||||||
logChunker := chunker.NewLogChunker()
|
extractor := &logs.LogExtractor{
|
||||||
logFetcher := fetcher.NewLogFetcher(bc)
|
CheckedHeadersRepository: repositories.NewCheckedHeadersRepository(db),
|
||||||
transactionSyncer := transactions.NewTransactionsSyncer(db, bc)
|
CheckedLogsRepository: repositories.NewCheckedLogsRepository(db),
|
||||||
|
Fetcher: fetcher.NewLogFetcher(bc),
|
||||||
|
LogRepository: repositories.NewHeaderSyncLogRepository(db),
|
||||||
|
Syncer: transactions.NewTransactionsSyncer(db, bc),
|
||||||
|
}
|
||||||
|
logTransformer := &logs.LogDelegator{
|
||||||
|
Chunker: chunker.NewLogChunker(),
|
||||||
|
LogRepository: repositories.NewHeaderSyncLogRepository(db),
|
||||||
|
}
|
||||||
return EventWatcher{
|
return EventWatcher{
|
||||||
BlockChain: bc,
|
blockChain: bc,
|
||||||
DB: db,
|
db: db,
|
||||||
Fetcher: logFetcher,
|
LogExtractor: extractor,
|
||||||
Chunker: logChunker,
|
LogDelegator: logTransformer,
|
||||||
Syncer: transactionSyncer,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds transformers to the watcher and updates the chunker, so that it will consider the new transformers.
|
// Adds transformers to the watcher so that their logs will be extracted and delegated.
|
||||||
func (watcher *EventWatcher) AddTransformers(initializers []transformer.EventTransformerInitializer) {
|
func (watcher *EventWatcher) AddTransformers(initializers []transformer.EventTransformerInitializer) error {
|
||||||
var contractAddresses []common.Address
|
|
||||||
var topic0s []common.Hash
|
|
||||||
var configs []transformer.EventTransformerConfig
|
|
||||||
|
|
||||||
for _, initializer := range initializers {
|
for _, initializer := range initializers {
|
||||||
t := initializer(watcher.DB)
|
t := initializer(watcher.db)
|
||||||
watcher.Transformers = append(watcher.Transformers, t)
|
|
||||||
|
|
||||||
config := t.GetConfig()
|
watcher.LogDelegator.AddTransformer(t)
|
||||||
configs = append(configs, config)
|
err := watcher.LogExtractor.AddTransformerConfig(t.GetConfig())
|
||||||
|
|
||||||
if watcher.StartingBlock == nil {
|
|
||||||
watcher.StartingBlock = &config.StartingBlockNumber
|
|
||||||
} else if earlierStartingBlockNumber(config.StartingBlockNumber, *watcher.StartingBlock) {
|
|
||||||
watcher.StartingBlock = &config.StartingBlockNumber
|
|
||||||
}
|
|
||||||
|
|
||||||
addresses := transformer.HexStringsToAddresses(config.ContractAddresses)
|
|
||||||
contractAddresses = append(contractAddresses, addresses...)
|
|
||||||
topic0s = append(topic0s, common.HexToHash(config.Topic))
|
|
||||||
}
|
|
||||||
|
|
||||||
watcher.Addresses = append(watcher.Addresses, contractAddresses...)
|
|
||||||
watcher.Topics = append(watcher.Topics, topic0s...)
|
|
||||||
watcher.Chunker.AddConfigs(configs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (watcher *EventWatcher) Execute(recheckHeaders constants.TransformerExecution) error {
|
|
||||||
if watcher.Transformers == nil {
|
|
||||||
return fmt.Errorf("No transformers added to watcher")
|
|
||||||
}
|
|
||||||
|
|
||||||
checkedColumnNames, err := repository.GetCheckedColumnNames(watcher.DB)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
notCheckedSQL := repository.CreateHeaderCheckedPredicateSQL(checkedColumnNames, recheckHeaders)
|
|
||||||
|
|
||||||
missingHeaders, err := repository.MissingHeaders(*watcher.StartingBlock, -1, watcher.DB, notCheckedSQL)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error("Couldn't fetch missing headers in watcher: ", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, header := range missingHeaders {
|
|
||||||
// TODO Extend FetchLogs for doing several blocks at a time
|
|
||||||
logs, err := watcher.Fetcher.FetchLogs(watcher.Addresses, watcher.Topics, header)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithFields(logrus.Fields{
|
|
||||||
"headerId": header.Id,
|
|
||||||
"headerHash": header.Hash,
|
|
||||||
"blockNumber": header.BlockNumber,
|
|
||||||
}).Errorf("Couldn't fetch logs for header: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
transactionsSyncErr := watcher.Syncer.SyncTransactions(header.Id, logs)
|
|
||||||
if transactionsSyncErr != nil {
|
|
||||||
logrus.Errorf("error syncing transactions: %s", transactionsSyncErr.Error())
|
|
||||||
return transactionsSyncErr
|
|
||||||
}
|
|
||||||
|
|
||||||
transformErr := watcher.transformLogs(logs, header)
|
|
||||||
if transformErr != nil {
|
|
||||||
logrus.Error("Could not transform logs: ", transformErr)
|
|
||||||
return transformErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (watcher *EventWatcher) transformLogs(logs []types.Log, header core.Header) error {
|
|
||||||
chunkedLogs := watcher.Chunker.ChunkLogs(logs)
|
|
||||||
|
|
||||||
// Can't quit early and mark as checked if there are no logs. If we are running continuousLogSync,
|
|
||||||
// not all logs we're interested in might have been fetched.
|
|
||||||
for _, t := range watcher.Transformers {
|
|
||||||
transformerName := t.GetConfig().TransformerName
|
|
||||||
logChunk := chunkedLogs[transformerName]
|
|
||||||
err := t.Execute(logChunk, header)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("%v transformer failed to execute in watcher: %v", transformerName, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func earlierStartingBlockNumber(transformerBlock, watcherBlock int64) bool {
|
// Extracts and delegates watched log events.
|
||||||
return transformerBlock < watcherBlock
|
func (watcher *EventWatcher) Execute(recheckHeaders constants.TransformerExecution) error {
|
||||||
|
delegateErrsChan := make(chan error)
|
||||||
|
extractErrsChan := make(chan error)
|
||||||
|
defer close(delegateErrsChan)
|
||||||
|
defer close(extractErrsChan)
|
||||||
|
|
||||||
|
go watcher.extractLogs(recheckHeaders, extractErrsChan)
|
||||||
|
go watcher.delegateLogs(delegateErrsChan)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case delegateErr := <-delegateErrsChan:
|
||||||
|
logrus.Errorf("error delegating logs in event watcher: %s", delegateErr.Error())
|
||||||
|
return delegateErr
|
||||||
|
case extractErr := <-extractErrsChan:
|
||||||
|
logrus.Errorf("error extracting logs in event watcher: %s", extractErr.Error())
|
||||||
|
return extractErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (watcher *EventWatcher) extractLogs(recheckHeaders constants.TransformerExecution, errs chan error) {
|
||||||
|
err := watcher.LogExtractor.ExtractLogs(recheckHeaders)
|
||||||
|
if err != nil && err != logs.ErrNoUncheckedHeaders {
|
||||||
|
errs <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == logs.ErrNoUncheckedHeaders {
|
||||||
|
time.Sleep(NoNewDataPause)
|
||||||
|
watcher.extractLogs(recheckHeaders, errs)
|
||||||
|
} else {
|
||||||
|
watcher.extractLogs(recheckHeaders, errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (watcher *EventWatcher) delegateLogs(errs chan error) {
|
||||||
|
err := watcher.LogDelegator.DelegateLogs()
|
||||||
|
if err != nil && err != logs.ErrNoLogs {
|
||||||
|
errs <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == logs.ErrNoLogs {
|
||||||
|
time.Sleep(NoNewDataPause)
|
||||||
|
watcher.delegateLogs(errs)
|
||||||
|
} else {
|
||||||
|
watcher.delegateLogs(errs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,220 +18,161 @@ package watcher_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/logs"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/watcher"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/watcher"
|
||||||
"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/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
"github.com/vulcanize/vulcanizedb/test_config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Watcher", func() {
|
var errExecuteClosed = errors.New("this error means the mocks were finished executing")
|
||||||
It("initialises correctly", func() {
|
|
||||||
db := test_config.NewTestDB(core.Node{ID: "testNode"})
|
|
||||||
bc := fakes.NewMockBlockChain()
|
|
||||||
|
|
||||||
w := watcher.NewEventWatcher(db, bc)
|
var _ = Describe("Event Watcher", func() {
|
||||||
|
var (
|
||||||
|
delegator *mocks.MockLogDelegator
|
||||||
|
extractor *mocks.MockLogExtractor
|
||||||
|
eventWatcher *watcher.EventWatcher
|
||||||
|
)
|
||||||
|
|
||||||
Expect(w.DB).To(Equal(db))
|
BeforeEach(func() {
|
||||||
Expect(w.Fetcher).NotTo(BeNil())
|
delegator = &mocks.MockLogDelegator{}
|
||||||
Expect(w.Chunker).NotTo(BeNil())
|
extractor = &mocks.MockLogExtractor{}
|
||||||
|
eventWatcher = &watcher.EventWatcher{
|
||||||
|
LogDelegator: delegator,
|
||||||
|
LogExtractor: extractor,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
It("adds transformers", func() {
|
Describe("AddTransformers", func() {
|
||||||
w := watcher.NewEventWatcher(nil, nil)
|
|
||||||
fakeTransformer := &mocks.MockTransformer{}
|
|
||||||
fakeTransformer.SetTransformerConfig(mocks.FakeTransformerConfig)
|
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
|
||||||
|
|
||||||
Expect(len(w.Transformers)).To(Equal(1))
|
|
||||||
Expect(w.Transformers).To(ConsistOf(fakeTransformer))
|
|
||||||
Expect(w.Topics).To(Equal([]common.Hash{common.HexToHash("FakeTopic")}))
|
|
||||||
Expect(w.Addresses).To(Equal([]common.Address{common.HexToAddress("FakeAddress")}))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("adds transformers from multiple sources", func() {
|
|
||||||
w := watcher.NewEventWatcher(nil, nil)
|
|
||||||
fakeTransformer1 := &mocks.MockTransformer{}
|
|
||||||
fakeTransformer1.SetTransformerConfig(mocks.FakeTransformerConfig)
|
|
||||||
|
|
||||||
fakeTransformer2 := &mocks.MockTransformer{}
|
|
||||||
fakeTransformer2.SetTransformerConfig(mocks.FakeTransformerConfig)
|
|
||||||
|
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer1.FakeTransformerInitializer})
|
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer2.FakeTransformerInitializer})
|
|
||||||
|
|
||||||
Expect(len(w.Transformers)).To(Equal(2))
|
|
||||||
Expect(w.Topics).To(Equal([]common.Hash{common.HexToHash("FakeTopic"),
|
|
||||||
common.HexToHash("FakeTopic")}))
|
|
||||||
Expect(w.Addresses).To(Equal([]common.Address{common.HexToAddress("FakeAddress"),
|
|
||||||
common.HexToAddress("FakeAddress")}))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("calculates earliest starting block number", func() {
|
|
||||||
fakeTransformer1 := &mocks.MockTransformer{}
|
|
||||||
fakeTransformer1.SetTransformerConfig(transformer.EventTransformerConfig{StartingBlockNumber: 5})
|
|
||||||
|
|
||||||
fakeTransformer2 := &mocks.MockTransformer{}
|
|
||||||
fakeTransformer2.SetTransformerConfig(transformer.EventTransformerConfig{StartingBlockNumber: 3})
|
|
||||||
|
|
||||||
w := watcher.NewEventWatcher(nil, nil)
|
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{
|
|
||||||
fakeTransformer1.FakeTransformerInitializer,
|
|
||||||
fakeTransformer2.FakeTransformerInitializer,
|
|
||||||
})
|
|
||||||
|
|
||||||
Expect(*w.StartingBlock).To(Equal(int64(3)))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("returns an error when run without transformers", func() {
|
|
||||||
w := watcher.NewEventWatcher(nil, nil)
|
|
||||||
err := w.Execute(constants.HeaderMissing)
|
|
||||||
Expect(err).To(MatchError("No transformers added to watcher"))
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("with missing headers", func() {
|
|
||||||
var (
|
var (
|
||||||
db *postgres.DB
|
fakeTransformerOne, fakeTransformerTwo *mocks.MockEventTransformer
|
||||||
w watcher.EventWatcher
|
|
||||||
mockBlockChain fakes.MockBlockChain
|
|
||||||
headerRepository repositories.HeaderRepository
|
|
||||||
repository mocks.MockWatcherRepository
|
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
db = test_config.NewTestDB(test_config.NewTestNode())
|
fakeTransformerOne = &mocks.MockEventTransformer{}
|
||||||
test_config.CleanTestDB(db)
|
fakeTransformerOne.SetTransformerConfig(mocks.FakeTransformerConfig)
|
||||||
mockBlockChain = fakes.MockBlockChain{}
|
fakeTransformerTwo = &mocks.MockEventTransformer{}
|
||||||
headerRepository = repositories.NewHeaderRepository(db)
|
fakeTransformerTwo.SetTransformerConfig(mocks.FakeTransformerConfig)
|
||||||
_, err := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
|
initializers := []transformer.EventTransformerInitializer{
|
||||||
Expect(err).NotTo(HaveOccurred())
|
fakeTransformerOne.FakeTransformerInitializer,
|
||||||
|
fakeTransformerTwo.FakeTransformerInitializer,
|
||||||
|
}
|
||||||
|
|
||||||
repository = mocks.MockWatcherRepository{}
|
err := eventWatcher.AddTransformers(initializers)
|
||||||
w = watcher.NewEventWatcher(db, &mockBlockChain)
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("syncs transactions for fetched logs", func() {
|
It("adds initialized transformer to log delegator", func() {
|
||||||
fakeTransformer := &mocks.MockTransformer{}
|
expectedTransformers := []transformer.EventTransformer{
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
fakeTransformerOne,
|
||||||
repository.SetMissingHeaders([]core.Header{fakes.FakeHeader})
|
fakeTransformerTwo,
|
||||||
mockTransactionSyncer := &fakes.MockTransactionSyncer{}
|
}
|
||||||
w.Syncer = mockTransactionSyncer
|
Expect(delegator.AddedTransformers).To(Equal(expectedTransformers))
|
||||||
|
|
||||||
err := w.Execute(constants.HeaderMissing)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(mockTransactionSyncer.SyncTransactionsCalled).To(BeTrue())
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns error if syncing transactions fails", func() {
|
It("adds transformer config to log extractor", func() {
|
||||||
fakeTransformer := &mocks.MockTransformer{}
|
expectedConfigs := []transformer.EventTransformerConfig{
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
mocks.FakeTransformerConfig,
|
||||||
repository.SetMissingHeaders([]core.Header{fakes.FakeHeader})
|
mocks.FakeTransformerConfig,
|
||||||
mockTransactionSyncer := &fakes.MockTransactionSyncer{}
|
}
|
||||||
mockTransactionSyncer.SyncTransactionsError = fakes.FakeError
|
Expect(extractor.AddedConfigs).To(Equal(expectedConfigs))
|
||||||
w.Syncer = mockTransactionSyncer
|
})
|
||||||
|
})
|
||||||
|
|
||||||
err := w.Execute(constants.HeaderMissing)
|
Describe("Execute", func() {
|
||||||
|
|
||||||
|
It("extracts watched logs", func(done Done) {
|
||||||
|
delegator.DelegateErrors = []error{logs.ErrNoLogs}
|
||||||
|
extractor.ExtractLogsErrors = []error{nil, errExecuteClosed}
|
||||||
|
|
||||||
|
err := eventWatcher.Execute(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(MatchError(errExecuteClosed))
|
||||||
|
Eventually(func() bool {
|
||||||
|
return extractor.ExtractLogsCount > 0
|
||||||
|
}).Should(BeTrue())
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if extracting logs fails", func(done Done) {
|
||||||
|
delegator.DelegateErrors = []error{logs.ErrNoLogs}
|
||||||
|
extractor.ExtractLogsErrors = []error{fakes.FakeError}
|
||||||
|
|
||||||
|
err := eventWatcher.Execute(constants.HeaderUnchecked)
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("executes each transformer", func() {
|
It("extracts watched logs again if missing headers found", func(done Done) {
|
||||||
fakeTransformer := &mocks.MockTransformer{}
|
delegator.DelegateErrors = []error{logs.ErrNoLogs}
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
extractor.ExtractLogsErrors = []error{nil, errExecuteClosed}
|
||||||
repository.SetMissingHeaders([]core.Header{fakes.FakeHeader})
|
|
||||||
|
|
||||||
err := w.Execute(constants.HeaderMissing)
|
err := eventWatcher.Execute(constants.HeaderUnchecked)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(fakeTransformer.ExecuteWasCalled).To(BeTrue())
|
Expect(err).To(MatchError(errExecuteClosed))
|
||||||
|
Eventually(func() bool {
|
||||||
|
return extractor.ExtractLogsCount > 1
|
||||||
|
}).Should(BeTrue())
|
||||||
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns an error if transformer returns an error", func() {
|
It("returns error if extracting logs fails on subsequent run", func(done Done) {
|
||||||
fakeTransformer := &mocks.MockTransformer{ExecuteError: errors.New("Something bad happened")}
|
delegator.DelegateErrors = []error{logs.ErrNoLogs}
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
extractor.ExtractLogsErrors = []error{nil, fakes.FakeError}
|
||||||
repository.SetMissingHeaders([]core.Header{fakes.FakeHeader})
|
|
||||||
|
|
||||||
err := w.Execute(constants.HeaderMissing)
|
err := eventWatcher.Execute(constants.HeaderUnchecked)
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(fakeTransformer.ExecuteWasCalled).To(BeFalse())
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("passes only relevant logs to each transformer", func() {
|
It("delegates untransformed logs", func() {
|
||||||
transformerA := &mocks.MockTransformer{}
|
delegator.DelegateErrors = []error{nil, errExecuteClosed}
|
||||||
transformerB := &mocks.MockTransformer{}
|
extractor.ExtractLogsErrors = []error{logs.ErrNoUncheckedHeaders}
|
||||||
|
|
||||||
configA := transformer.EventTransformerConfig{TransformerName: "transformerA",
|
err := eventWatcher.Execute(constants.HeaderUnchecked)
|
||||||
ContractAddresses: []string{"0x000000000000000000000000000000000000000A"},
|
|
||||||
Topic: "0xA"}
|
|
||||||
configB := transformer.EventTransformerConfig{TransformerName: "transformerB",
|
|
||||||
ContractAddresses: []string{"0x000000000000000000000000000000000000000b"},
|
|
||||||
Topic: "0xB"}
|
|
||||||
|
|
||||||
transformerA.SetTransformerConfig(configA)
|
Expect(err).To(MatchError(errExecuteClosed))
|
||||||
transformerB.SetTransformerConfig(configB)
|
Eventually(func() bool {
|
||||||
|
return delegator.DelegateCallCount > 0
|
||||||
logA := types.Log{Address: common.HexToAddress("0xA"),
|
}).Should(BeTrue())
|
||||||
Topics: []common.Hash{common.HexToHash("0xA")}}
|
|
||||||
logB := types.Log{Address: common.HexToAddress("0xB"),
|
|
||||||
Topics: []common.Hash{common.HexToHash("0xB")}}
|
|
||||||
mockBlockChain.SetGetEthLogsWithCustomQueryReturnLogs([]types.Log{logA, logB})
|
|
||||||
|
|
||||||
repository.SetMissingHeaders([]core.Header{fakes.FakeHeader})
|
|
||||||
w = watcher.NewEventWatcher(db, &mockBlockChain)
|
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{
|
|
||||||
transformerA.FakeTransformerInitializer, transformerB.FakeTransformerInitializer})
|
|
||||||
|
|
||||||
err := w.Execute(constants.HeaderMissing)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(transformerA.PassedLogs).To(Equal([]types.Log{logA}))
|
|
||||||
Expect(transformerB.PassedLogs).To(Equal([]types.Log{logB}))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("uses the LogFetcher correctly:", func() {
|
It("returns error if delegating logs fails", func(done Done) {
|
||||||
var fakeTransformer mocks.MockTransformer
|
delegator.DelegateErrors = []error{fakes.FakeError}
|
||||||
BeforeEach(func() {
|
extractor.ExtractLogsErrors = []error{logs.ErrNoUncheckedHeaders}
|
||||||
repository.SetMissingHeaders([]core.Header{fakes.FakeHeader})
|
|
||||||
fakeTransformer = mocks.MockTransformer{}
|
|
||||||
})
|
|
||||||
|
|
||||||
It("fetches logs for added transformers", func() {
|
err := eventWatcher.Execute(constants.HeaderUnchecked)
|
||||||
addresses := []string{"0xA", "0xB"}
|
|
||||||
topic := "0x1"
|
|
||||||
fakeTransformer.SetTransformerConfig(transformer.EventTransformerConfig{
|
|
||||||
Topic: topic, ContractAddresses: addresses})
|
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
|
||||||
|
|
||||||
err := w.Execute(constants.HeaderMissing)
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
Expect(err).NotTo(HaveOccurred())
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
fakeHash := common.HexToHash(fakes.FakeHeader.Hash)
|
It("delegates logs again if untransformed logs found", func(done Done) {
|
||||||
mockBlockChain.AssertGetEthLogsWithCustomQueryCalledWith(ethereum.FilterQuery{
|
delegator.DelegateErrors = []error{nil, nil, nil, errExecuteClosed}
|
||||||
BlockHash: &fakeHash,
|
extractor.ExtractLogsErrors = []error{logs.ErrNoUncheckedHeaders}
|
||||||
Addresses: transformer.HexStringsToAddresses(addresses),
|
|
||||||
Topics: [][]common.Hash{{common.HexToHash(topic)}},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
It("propagates log fetcher errors", func() {
|
err := eventWatcher.Execute(constants.HeaderUnchecked)
|
||||||
fetcherError := errors.New("FetcherError")
|
|
||||||
mockBlockChain.SetGetEthLogsWithCustomQueryErr(fetcherError)
|
|
||||||
|
|
||||||
w.AddTransformers([]transformer.EventTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
Expect(err).To(MatchError(errExecuteClosed))
|
||||||
err := w.Execute(constants.HeaderMissing)
|
Eventually(func() bool {
|
||||||
Expect(err).To(MatchError(fetcherError))
|
return delegator.DelegateCallCount > 1
|
||||||
})
|
}).Should(BeTrue())
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if delegating logs fails on subsequent run", func(done Done) {
|
||||||
|
delegator.DelegateErrors = []error{nil, fakes.FakeError}
|
||||||
|
extractor.ExtractLogsErrors = []error{logs.ErrNoUncheckedHeaders}
|
||||||
|
|
||||||
|
err := eventWatcher.Execute(constants.HeaderUnchecked)
|
||||||
|
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
close(done)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -18,69 +18,76 @@ package watcher
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type IStorageWatcher interface {
|
||||||
|
AddTransformers(initializers []transformer.StorageTransformerInitializer)
|
||||||
|
Execute(diffsChan chan utils.StorageDiff, errsChan chan error, queueRecheckInterval time.Duration)
|
||||||
|
}
|
||||||
|
|
||||||
type StorageWatcher struct {
|
type StorageWatcher struct {
|
||||||
db *postgres.DB
|
db *postgres.DB
|
||||||
StorageFetcher fetcher.IStorageFetcher
|
StorageFetcher fetcher.IStorageFetcher
|
||||||
Queue storage.IStorageQueue
|
Queue storage.IStorageQueue
|
||||||
Transformers map[common.Address]transformer.StorageTransformer
|
KeccakAddressTransformers map[common.Hash]transformer.StorageTransformer // keccak hash of an address => transformer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorageWatcher(fetcher fetcher.IStorageFetcher, db *postgres.DB) StorageWatcher {
|
func NewStorageWatcher(fetcher fetcher.IStorageFetcher, db *postgres.DB) StorageWatcher {
|
||||||
transformers := make(map[common.Address]transformer.StorageTransformer)
|
|
||||||
queue := storage.NewStorageQueue(db)
|
queue := storage.NewStorageQueue(db)
|
||||||
|
transformers := make(map[common.Hash]transformer.StorageTransformer)
|
||||||
return StorageWatcher{
|
return StorageWatcher{
|
||||||
db: db,
|
db: db,
|
||||||
StorageFetcher: fetcher,
|
StorageFetcher: fetcher,
|
||||||
Queue: queue,
|
Queue: queue,
|
||||||
Transformers: transformers,
|
KeccakAddressTransformers: transformers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storageWatcher StorageWatcher) AddTransformers(initializers []transformer.StorageTransformerInitializer) {
|
func (storageWatcher StorageWatcher) AddTransformers(initializers []transformer.StorageTransformerInitializer) {
|
||||||
for _, initializer := range initializers {
|
for _, initializer := range initializers {
|
||||||
storageTransformer := initializer(storageWatcher.db)
|
storageTransformer := initializer(storageWatcher.db)
|
||||||
storageWatcher.Transformers[storageTransformer.ContractAddress()] = storageTransformer
|
storageWatcher.KeccakAddressTransformers[storageTransformer.KeccakContractAddress()] = storageTransformer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storageWatcher StorageWatcher) Execute(rows chan utils.StorageDiffRow, errs chan error, queueRecheckInterval time.Duration) {
|
func (storageWatcher StorageWatcher) Execute(diffsChan chan utils.StorageDiff, errsChan chan error, queueRecheckInterval time.Duration) {
|
||||||
ticker := time.NewTicker(queueRecheckInterval)
|
ticker := time.NewTicker(queueRecheckInterval)
|
||||||
go storageWatcher.StorageFetcher.FetchStorageDiffs(rows, errs)
|
go storageWatcher.StorageFetcher.FetchStorageDiffs(diffsChan, errsChan)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case fetchErr := <-errs:
|
case fetchErr := <-errsChan:
|
||||||
logrus.Warn(fmt.Sprintf("error fetching storage diffs: %s", fetchErr))
|
logrus.Warn(fmt.Sprintf("error fetching storage diffs: %s", fetchErr))
|
||||||
case row := <-rows:
|
case diff := <-diffsChan:
|
||||||
storageWatcher.processRow(row)
|
storageWatcher.processRow(diff)
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
storageWatcher.processQueue()
|
storageWatcher.processQueue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (storageWatcher StorageWatcher) processRow(row utils.StorageDiffRow) {
|
func (storageWatcher StorageWatcher) getTransformer(diff utils.StorageDiff) (transformer.StorageTransformer, bool) {
|
||||||
storageTransformer, ok := storageWatcher.Transformers[row.Contract]
|
storageTransformer, ok := storageWatcher.KeccakAddressTransformers[diff.HashedAddress]
|
||||||
|
return storageTransformer, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (storageWatcher StorageWatcher) processRow(diff utils.StorageDiff) {
|
||||||
|
storageTransformer, ok := storageWatcher.getTransformer(diff)
|
||||||
if !ok {
|
if !ok {
|
||||||
// ignore rows from unwatched contracts
|
logrus.Debug("ignoring a diff from an unwatched contract")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
executeErr := storageTransformer.Execute(row)
|
executeErr := storageTransformer.Execute(diff)
|
||||||
if executeErr != nil {
|
if executeErr != nil {
|
||||||
logrus.Warn(fmt.Sprintf("error executing storage transformer: %s", executeErr))
|
logrus.Warn(fmt.Sprintf("error executing storage transformer: %s", executeErr))
|
||||||
queueErr := storageWatcher.Queue.Add(row)
|
queueErr := storageWatcher.Queue.Add(diff)
|
||||||
if queueErr != nil {
|
if queueErr != nil {
|
||||||
logrus.Warn(fmt.Sprintf("error queueing storage diff: %s", queueErr))
|
logrus.Warn(fmt.Sprintf("error queueing storage diff: %s", queueErr))
|
||||||
}
|
}
|
||||||
@@ -88,20 +95,20 @@ func (storageWatcher StorageWatcher) processRow(row utils.StorageDiffRow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (storageWatcher StorageWatcher) processQueue() {
|
func (storageWatcher StorageWatcher) processQueue() {
|
||||||
rows, fetchErr := storageWatcher.Queue.GetAll()
|
diffs, fetchErr := storageWatcher.Queue.GetAll()
|
||||||
if fetchErr != nil {
|
if fetchErr != nil {
|
||||||
logrus.Warn(fmt.Sprintf("error getting queued storage: %s", fetchErr))
|
logrus.Warn(fmt.Sprintf("error getting queued storage: %s", fetchErr))
|
||||||
}
|
}
|
||||||
for _, row := range rows {
|
for _, diff := range diffs {
|
||||||
storageTransformer, ok := storageWatcher.Transformers[row.Contract]
|
storageTransformer, ok := storageWatcher.getTransformer(diff)
|
||||||
if !ok {
|
if !ok {
|
||||||
// delete row from queue if address no longer watched
|
// delete diff from queue if address no longer watched
|
||||||
storageWatcher.deleteRow(row.Id)
|
storageWatcher.deleteRow(diff.Id)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
executeErr := storageTransformer.Execute(row)
|
executeErr := storageTransformer.Execute(diff)
|
||||||
if executeErr == nil {
|
if executeErr == nil {
|
||||||
storageWatcher.deleteRow(row.Id)
|
storageWatcher.deleteRow(diff.Id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,10 +116,6 @@ func (storageWatcher StorageWatcher) processQueue() {
|
|||||||
func (storageWatcher StorageWatcher) deleteRow(id int) {
|
func (storageWatcher StorageWatcher) deleteRow(id int) {
|
||||||
deleteErr := storageWatcher.Queue.Delete(id)
|
deleteErr := storageWatcher.Queue.Delete(id)
|
||||||
if deleteErr != nil {
|
if deleteErr != nil {
|
||||||
logrus.Warn(fmt.Sprintf("error deleting persisted row from queue: %s", deleteErr))
|
logrus.Warn(fmt.Sprintf("error deleting persisted diff from queue: %s", deleteErr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isKeyNotFound(executeErr error) bool {
|
|
||||||
return reflect.TypeOf(executeErr) == reflect.TypeOf(utils.ErrStorageKeyNotFound{})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -17,59 +17,60 @@
|
|||||||
package watcher_test
|
package watcher_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/watcher"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/watcher"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
"github.com/vulcanize/vulcanizedb/test_config"
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Storage Watcher", func() {
|
var _ = Describe("Storage Watcher", func() {
|
||||||
It("adds transformers", func() {
|
Describe("AddTransformer", func() {
|
||||||
fakeAddress := common.HexToAddress("0x12345")
|
It("adds transformers", func() {
|
||||||
fakeTransformer := &mocks.MockStorageTransformer{Address: fakeAddress}
|
fakeHashedAddress := utils.HexToKeccak256Hash("0x12345")
|
||||||
w := watcher.NewStorageWatcher(mocks.NewMockStorageFetcher(), test_config.NewTestDB(test_config.NewTestNode()))
|
fakeTransformer := &mocks.MockStorageTransformer{KeccakOfAddress: fakeHashedAddress}
|
||||||
|
w := watcher.NewStorageWatcher(mocks.NewMockStorageFetcher(), test_config.NewTestDB(test_config.NewTestNode()))
|
||||||
|
|
||||||
w.AddTransformers([]transformer.StorageTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
w.AddTransformers([]transformer.StorageTransformerInitializer{fakeTransformer.FakeTransformerInitializer})
|
||||||
|
|
||||||
Expect(w.Transformers[fakeAddress]).To(Equal(fakeTransformer))
|
Expect(w.KeccakAddressTransformers[fakeHashedAddress]).To(Equal(fakeTransformer))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("executing watcher", func() {
|
Describe("Execute", func() {
|
||||||
var (
|
var (
|
||||||
errs chan error
|
errs chan error
|
||||||
mockFetcher *mocks.MockStorageFetcher
|
mockFetcher *mocks.MockStorageFetcher
|
||||||
mockQueue *mocks.MockStorageQueue
|
mockQueue *mocks.MockStorageQueue
|
||||||
mockTransformer *mocks.MockStorageTransformer
|
mockTransformer *mocks.MockStorageTransformer
|
||||||
row utils.StorageDiffRow
|
csvDiff utils.StorageDiff
|
||||||
rows chan utils.StorageDiffRow
|
diffs chan utils.StorageDiff
|
||||||
storageWatcher watcher.StorageWatcher
|
storageWatcher watcher.StorageWatcher
|
||||||
|
hashedAddress common.Hash
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
errs = make(chan error)
|
errs = make(chan error)
|
||||||
rows = make(chan utils.StorageDiffRow)
|
diffs = make(chan utils.StorageDiff)
|
||||||
address := common.HexToAddress("0x0123456789abcdef")
|
hashedAddress = utils.HexToKeccak256Hash("0x0123456789abcdef")
|
||||||
mockFetcher = mocks.NewMockStorageFetcher()
|
mockFetcher = mocks.NewMockStorageFetcher()
|
||||||
mockQueue = &mocks.MockStorageQueue{}
|
mockQueue = &mocks.MockStorageQueue{}
|
||||||
mockTransformer = &mocks.MockStorageTransformer{Address: address}
|
mockTransformer = &mocks.MockStorageTransformer{KeccakOfAddress: hashedAddress}
|
||||||
row = utils.StorageDiffRow{
|
csvDiff = utils.StorageDiff{
|
||||||
Id: 1337,
|
Id: 1337,
|
||||||
Contract: address,
|
HashedAddress: hashedAddress,
|
||||||
BlockHash: common.HexToHash("0xfedcba9876543210"),
|
BlockHash: common.HexToHash("0xfedcba9876543210"),
|
||||||
BlockHeight: 0,
|
BlockHeight: 0,
|
||||||
StorageKey: common.HexToHash("0xabcdef1234567890"),
|
StorageKey: common.HexToHash("0xabcdef1234567890"),
|
||||||
StorageValue: common.HexToHash("0x9876543210abcdef"),
|
StorageValue: common.HexToHash("0x9876543210abcdef"),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ var _ = Describe("Storage Watcher", func() {
|
|||||||
defer os.Remove(tempFile.Name())
|
defer os.Remove(tempFile.Name())
|
||||||
logrus.SetOutput(tempFile)
|
logrus.SetOutput(tempFile)
|
||||||
|
|
||||||
go storageWatcher.Execute(rows, errs, time.Hour)
|
go storageWatcher.Execute(diffs, errs, time.Hour)
|
||||||
|
|
||||||
Eventually(func() (string, error) {
|
Eventually(func() (string, error) {
|
||||||
logContent, err := ioutil.ReadFile(tempFile.Name())
|
logContent, err := ioutil.ReadFile(tempFile.Name())
|
||||||
@@ -92,39 +93,39 @@ var _ = Describe("Storage Watcher", func() {
|
|||||||
close(done)
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("transforming new storage diffs", func() {
|
Describe("transforming new storage diffs from csv", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
mockFetcher.RowsToReturn = []utils.StorageDiffRow{row}
|
mockFetcher.DiffsToReturn = []utils.StorageDiff{csvDiff}
|
||||||
storageWatcher = watcher.NewStorageWatcher(mockFetcher, test_config.NewTestDB(test_config.NewTestNode()))
|
storageWatcher = watcher.NewStorageWatcher(mockFetcher, test_config.NewTestDB(test_config.NewTestNode()))
|
||||||
storageWatcher.Queue = mockQueue
|
storageWatcher.Queue = mockQueue
|
||||||
storageWatcher.AddTransformers([]transformer.StorageTransformerInitializer{mockTransformer.FakeTransformerInitializer})
|
storageWatcher.AddTransformers([]transformer.StorageTransformerInitializer{mockTransformer.FakeTransformerInitializer})
|
||||||
})
|
})
|
||||||
|
|
||||||
It("executes transformer for recognized storage row", func(done Done) {
|
It("executes transformer for recognized storage diff", func(done Done) {
|
||||||
go storageWatcher.Execute(rows, errs, time.Hour)
|
go storageWatcher.Execute(diffs, errs, time.Hour)
|
||||||
|
|
||||||
Eventually(func() utils.StorageDiffRow {
|
Eventually(func() utils.StorageDiff {
|
||||||
return mockTransformer.PassedRow
|
return mockTransformer.PassedDiff
|
||||||
}).Should(Equal(row))
|
}).Should(Equal(csvDiff))
|
||||||
close(done)
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("queues row for later processing if transformer execution fails", func(done Done) {
|
It("queues diff for later processing if transformer execution fails", func(done Done) {
|
||||||
mockTransformer.ExecuteErr = fakes.FakeError
|
mockTransformer.ExecuteErr = fakes.FakeError
|
||||||
|
|
||||||
go storageWatcher.Execute(rows, errs, time.Hour)
|
go storageWatcher.Execute(diffs, errs, time.Hour)
|
||||||
|
|
||||||
Expect(<-errs).To(BeNil())
|
Expect(<-errs).To(BeNil())
|
||||||
Eventually(func() bool {
|
Eventually(func() bool {
|
||||||
return mockQueue.AddCalled
|
return mockQueue.AddCalled
|
||||||
}).Should(BeTrue())
|
}).Should(BeTrue())
|
||||||
Eventually(func() utils.StorageDiffRow {
|
Eventually(func() utils.StorageDiff {
|
||||||
return mockQueue.AddPassedRow
|
return mockQueue.AddPassedDiff
|
||||||
}).Should(Equal(row))
|
}).Should(Equal(csvDiff))
|
||||||
close(done)
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("logs error if queueing row fails", func(done Done) {
|
It("logs error if queueing diff fails", func(done Done) {
|
||||||
mockTransformer.ExecuteErr = utils.ErrStorageKeyNotFound{}
|
mockTransformer.ExecuteErr = utils.ErrStorageKeyNotFound{}
|
||||||
mockQueue.AddError = fakes.FakeError
|
mockQueue.AddError = fakes.FakeError
|
||||||
tempFile, fileErr := ioutil.TempFile("", "log")
|
tempFile, fileErr := ioutil.TempFile("", "log")
|
||||||
@@ -132,7 +133,7 @@ var _ = Describe("Storage Watcher", func() {
|
|||||||
defer os.Remove(tempFile.Name())
|
defer os.Remove(tempFile.Name())
|
||||||
logrus.SetOutput(tempFile)
|
logrus.SetOutput(tempFile)
|
||||||
|
|
||||||
go storageWatcher.Execute(rows, errs, time.Hour)
|
go storageWatcher.Execute(diffs, errs, time.Hour)
|
||||||
|
|
||||||
Eventually(func() bool {
|
Eventually(func() bool {
|
||||||
return mockQueue.AddCalled
|
return mockQueue.AddCalled
|
||||||
@@ -147,20 +148,38 @@ var _ = Describe("Storage Watcher", func() {
|
|||||||
|
|
||||||
Describe("transforming queued storage diffs", func() {
|
Describe("transforming queued storage diffs", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
mockQueue.RowsToReturn = []utils.StorageDiffRow{row}
|
mockQueue.DiffsToReturn = []utils.StorageDiff{csvDiff}
|
||||||
storageWatcher = watcher.NewStorageWatcher(mockFetcher, test_config.NewTestDB(test_config.NewTestNode()))
|
storageWatcher = watcher.NewStorageWatcher(mockFetcher, test_config.NewTestDB(test_config.NewTestNode()))
|
||||||
storageWatcher.Queue = mockQueue
|
storageWatcher.Queue = mockQueue
|
||||||
storageWatcher.AddTransformers([]transformer.StorageTransformerInitializer{mockTransformer.FakeTransformerInitializer})
|
storageWatcher.AddTransformers([]transformer.StorageTransformerInitializer{mockTransformer.FakeTransformerInitializer})
|
||||||
})
|
})
|
||||||
|
|
||||||
It("logs error if getting queued storage fails", func(done Done) {
|
It("executes transformer for storage diff", func(done Done) {
|
||||||
mockQueue.GetAllErr = fakes.FakeError
|
go storageWatcher.Execute(diffs, errs, time.Nanosecond)
|
||||||
|
|
||||||
|
Eventually(func() utils.StorageDiff {
|
||||||
|
return mockTransformer.PassedDiff
|
||||||
|
}).Should(Equal(csvDiff))
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("deletes diff from queue if transformer execution successful", func(done Done) {
|
||||||
|
go storageWatcher.Execute(diffs, errs, time.Nanosecond)
|
||||||
|
|
||||||
|
Eventually(func() int {
|
||||||
|
return mockQueue.DeletePassedId
|
||||||
|
}).Should(Equal(csvDiff.Id))
|
||||||
|
close(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("logs error if deleting persisted diff fails", func(done Done) {
|
||||||
|
mockQueue.DeleteErr = fakes.FakeError
|
||||||
tempFile, fileErr := ioutil.TempFile("", "log")
|
tempFile, fileErr := ioutil.TempFile("", "log")
|
||||||
Expect(fileErr).NotTo(HaveOccurred())
|
Expect(fileErr).NotTo(HaveOccurred())
|
||||||
defer os.Remove(tempFile.Name())
|
defer os.Remove(tempFile.Name())
|
||||||
logrus.SetOutput(tempFile)
|
logrus.SetOutput(tempFile)
|
||||||
|
|
||||||
go storageWatcher.Execute(rows, errs, time.Nanosecond)
|
go storageWatcher.Execute(diffs, errs, time.Nanosecond)
|
||||||
|
|
||||||
Eventually(func() (string, error) {
|
Eventually(func() (string, error) {
|
||||||
logContent, err := ioutil.ReadFile(tempFile.Name())
|
logContent, err := ioutil.ReadFile(tempFile.Name())
|
||||||
@@ -169,68 +188,34 @@ var _ = Describe("Storage Watcher", func() {
|
|||||||
close(done)
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("executes transformer for storage row", func(done Done) {
|
It("deletes obsolete diff from queue if contract not recognized", func(done Done) {
|
||||||
go storageWatcher.Execute(rows, errs, time.Nanosecond)
|
obsoleteDiff := utils.StorageDiff{
|
||||||
|
Id: csvDiff.Id + 1,
|
||||||
|
HashedAddress: utils.HexToKeccak256Hash("0xfedcba9876543210"),
|
||||||
|
}
|
||||||
|
mockQueue.DiffsToReturn = []utils.StorageDiff{obsoleteDiff}
|
||||||
|
|
||||||
Eventually(func() utils.StorageDiffRow {
|
go storageWatcher.Execute(diffs, errs, time.Nanosecond)
|
||||||
return mockTransformer.PassedRow
|
|
||||||
}).Should(Equal(row))
|
|
||||||
close(done)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("deletes row from queue if transformer execution successful", func(done Done) {
|
|
||||||
go storageWatcher.Execute(rows, errs, time.Nanosecond)
|
|
||||||
|
|
||||||
Eventually(func() int {
|
Eventually(func() int {
|
||||||
return mockQueue.DeletePassedId
|
return mockQueue.DeletePassedId
|
||||||
}).Should(Equal(row.Id))
|
}).Should(Equal(obsoleteDiff.Id))
|
||||||
close(done)
|
close(done)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("logs error if deleting persisted row fails", func(done Done) {
|
It("logs error if deleting obsolete diff fails", func(done Done) {
|
||||||
|
obsoleteDiff := utils.StorageDiff{
|
||||||
|
Id: csvDiff.Id + 1,
|
||||||
|
HashedAddress: utils.HexToKeccak256Hash("0xfedcba9876543210"),
|
||||||
|
}
|
||||||
|
mockQueue.DiffsToReturn = []utils.StorageDiff{obsoleteDiff}
|
||||||
mockQueue.DeleteErr = fakes.FakeError
|
mockQueue.DeleteErr = fakes.FakeError
|
||||||
tempFile, fileErr := ioutil.TempFile("", "log")
|
tempFile, fileErr := ioutil.TempFile("", "log")
|
||||||
Expect(fileErr).NotTo(HaveOccurred())
|
Expect(fileErr).NotTo(HaveOccurred())
|
||||||
defer os.Remove(tempFile.Name())
|
defer os.Remove(tempFile.Name())
|
||||||
logrus.SetOutput(tempFile)
|
logrus.SetOutput(tempFile)
|
||||||
|
|
||||||
go storageWatcher.Execute(rows, errs, time.Nanosecond)
|
go storageWatcher.Execute(diffs, errs, time.Nanosecond)
|
||||||
|
|
||||||
Eventually(func() (string, error) {
|
|
||||||
logContent, err := ioutil.ReadFile(tempFile.Name())
|
|
||||||
return string(logContent), err
|
|
||||||
}).Should(ContainSubstring(fakes.FakeError.Error()))
|
|
||||||
close(done)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("deletes obsolete row from queue if contract not recognized", func(done Done) {
|
|
||||||
obsoleteRow := utils.StorageDiffRow{
|
|
||||||
Id: row.Id + 1,
|
|
||||||
Contract: common.HexToAddress("0xfedcba9876543210"),
|
|
||||||
}
|
|
||||||
mockQueue.RowsToReturn = []utils.StorageDiffRow{obsoleteRow}
|
|
||||||
|
|
||||||
go storageWatcher.Execute(rows, errs, time.Nanosecond)
|
|
||||||
|
|
||||||
Eventually(func() int {
|
|
||||||
return mockQueue.DeletePassedId
|
|
||||||
}).Should(Equal(obsoleteRow.Id))
|
|
||||||
close(done)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("logs error if deleting obsolete row fails", func(done Done) {
|
|
||||||
obsoleteRow := utils.StorageDiffRow{
|
|
||||||
Id: row.Id + 1,
|
|
||||||
Contract: common.HexToAddress("0xfedcba9876543210"),
|
|
||||||
}
|
|
||||||
mockQueue.RowsToReturn = []utils.StorageDiffRow{obsoleteRow}
|
|
||||||
mockQueue.DeleteErr = fakes.FakeError
|
|
||||||
tempFile, fileErr := ioutil.TempFile("", "log")
|
|
||||||
Expect(fileErr).NotTo(HaveOccurred())
|
|
||||||
defer os.Remove(tempFile.Name())
|
|
||||||
logrus.SetOutput(tempFile)
|
|
||||||
|
|
||||||
go storageWatcher.Execute(rows, errs, time.Nanosecond)
|
|
||||||
|
|
||||||
Eventually(func() (string, error) {
|
Eventually(func() (string, error) {
|
||||||
logContent, err := ioutil.ReadFile(tempFile.Name())
|
logContent, err := ioutil.ReadFile(tempFile.Name())
|
||||||
@@ -239,6 +224,5 @@ var _ = Describe("Storage Watcher", func() {
|
|||||||
close(done)
|
close(done)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package retriever
|
package retriever
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -41,7 +43,10 @@ func NewBlockRetriever(db *postgres.DB) (r *blockRetriever) {
|
|||||||
func (r *blockRetriever) RetrieveFirstBlock(contractAddr string) (int64, error) {
|
func (r *blockRetriever) RetrieveFirstBlock(contractAddr string) (int64, error) {
|
||||||
i, err := r.retrieveFirstBlockFromReceipts(contractAddr)
|
i, err := r.retrieveFirstBlockFromReceipts(contractAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i, err = r.retrieveFirstBlockFromLogs(contractAddr)
|
if err == sql.ErrNoRows {
|
||||||
|
i, err = r.retrieveFirstBlockFromLogs(contractAddr)
|
||||||
|
}
|
||||||
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return i, err
|
return i, err
|
||||||
@@ -49,18 +54,22 @@ func (r *blockRetriever) RetrieveFirstBlock(contractAddr string) (int64, error)
|
|||||||
|
|
||||||
// For some contracts the contract creation transaction receipt doesn't have the contract address so this doesn't work (e.g. Sai)
|
// For some contracts the contract creation transaction receipt doesn't have the contract address so this doesn't work (e.g. Sai)
|
||||||
func (r *blockRetriever) retrieveFirstBlockFromReceipts(contractAddr string) (int64, error) {
|
func (r *blockRetriever) retrieveFirstBlockFromReceipts(contractAddr string) (int64, error) {
|
||||||
var firstBlock int
|
var firstBlock int64
|
||||||
|
addressId, getAddressErr := repository.GetOrCreateAddress(r.db, contractAddr)
|
||||||
|
if getAddressErr != nil {
|
||||||
|
return firstBlock, getAddressErr
|
||||||
|
}
|
||||||
err := r.db.Get(
|
err := r.db.Get(
|
||||||
&firstBlock,
|
&firstBlock,
|
||||||
`SELECT number FROM blocks
|
`SELECT number FROM blocks
|
||||||
WHERE id = (SELECT block_id FROM full_sync_receipts
|
WHERE id = (SELECT block_id FROM full_sync_receipts
|
||||||
WHERE lower(contract_address) = $1
|
WHERE contract_address_id = $1
|
||||||
ORDER BY block_id ASC
|
ORDER BY block_id ASC
|
||||||
LIMIT 1)`,
|
LIMIT 1)`,
|
||||||
contractAddr,
|
addressId,
|
||||||
)
|
)
|
||||||
|
|
||||||
return int64(firstBlock), err
|
return firstBlock, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// In which case this servers as a heuristic to find the first block by finding the first contract event log
|
// In which case this servers as a heuristic to find the first block by finding the first contract event log
|
||||||
@@ -68,7 +77,7 @@ func (r *blockRetriever) retrieveFirstBlockFromLogs(contractAddr string) (int64,
|
|||||||
var firstBlock int
|
var firstBlock int
|
||||||
err := r.db.Get(
|
err := r.db.Get(
|
||||||
&firstBlock,
|
&firstBlock,
|
||||||
"SELECT block_number FROM logs WHERE lower(address) = $1 ORDER BY block_number ASC LIMIT 1",
|
"SELECT block_number FROM full_sync_logs WHERE lower(address) = $1 ORDER BY block_number ASC LIMIT 1",
|
||||||
contractAddr,
|
contractAddr,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ var _ = Describe("Block Retriever", func() {
|
|||||||
Receipt: core.Receipt{
|
Receipt: core.Receipt{
|
||||||
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae",
|
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae",
|
||||||
ContractAddress: constants.TusdContractAddress,
|
ContractAddress: constants.TusdContractAddress,
|
||||||
Logs: []core.Log{},
|
Logs: []core.FullSyncLog{},
|
||||||
},
|
},
|
||||||
TxIndex: 0,
|
TxIndex: 0,
|
||||||
Value: "0",
|
Value: "0",
|
||||||
@@ -92,7 +92,7 @@ var _ = Describe("Block Retriever", func() {
|
|||||||
Receipt: core.Receipt{
|
Receipt: core.Receipt{
|
||||||
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs",
|
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs",
|
||||||
ContractAddress: constants.TusdContractAddress,
|
ContractAddress: constants.TusdContractAddress,
|
||||||
Logs: []core.Log{{
|
Logs: []core.FullSyncLog{{
|
||||||
BlockNumber: 3,
|
BlockNumber: 3,
|
||||||
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs",
|
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs",
|
||||||
Address: constants.TusdContractAddress,
|
Address: constants.TusdContractAddress,
|
||||||
@@ -136,7 +136,7 @@ var _ = Describe("Block Retriever", func() {
|
|||||||
Receipt: core.Receipt{
|
Receipt: core.Receipt{
|
||||||
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae",
|
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae",
|
||||||
ContractAddress: "",
|
ContractAddress: "",
|
||||||
Logs: []core.Log{{
|
Logs: []core.FullSyncLog{{
|
||||||
BlockNumber: 2,
|
BlockNumber: 2,
|
||||||
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae",
|
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae",
|
||||||
Address: constants.DaiContractAddress,
|
Address: constants.DaiContractAddress,
|
||||||
@@ -167,7 +167,7 @@ var _ = Describe("Block Retriever", func() {
|
|||||||
Receipt: core.Receipt{
|
Receipt: core.Receipt{
|
||||||
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs",
|
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs",
|
||||||
ContractAddress: "",
|
ContractAddress: "",
|
||||||
Logs: []core.Log{{
|
Logs: []core.FullSyncLog{{
|
||||||
BlockNumber: 3,
|
BlockNumber: 3,
|
||||||
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs",
|
TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad234hfs",
|
||||||
Address: constants.DaiContractAddress,
|
Address: constants.DaiContractAddress,
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ package transformer
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/config"
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/converter"
|
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/converter"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/retriever"
|
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/retriever"
|
||||||
@@ -106,7 +108,11 @@ func (tr *Transformer) Init() error {
|
|||||||
|
|
||||||
// Get contract name if it has one
|
// Get contract name if it has one
|
||||||
var name = new(string)
|
var name = new(string)
|
||||||
tr.Poller.FetchContractData(tr.Parser.Abi(), contractAddr, "name", nil, name, tr.LastBlock)
|
pollingErr := tr.Poller.FetchContractData(tr.Parser.Abi(), contractAddr, "name", nil, name, tr.LastBlock)
|
||||||
|
if pollingErr != nil {
|
||||||
|
// can't return this error because "name" might not exist on the contract
|
||||||
|
logrus.Warnf("error fetching contract data: %s", pollingErr.Error())
|
||||||
|
}
|
||||||
|
|
||||||
// Remove any potential accidental duplicate inputs in arg filter values
|
// Remove any potential accidental duplicate inputs in arg filter values
|
||||||
eventArgs := map[string]bool{}
|
eventArgs := map[string]bool{}
|
||||||
|
|||||||
@@ -89,9 +89,14 @@ func (c *Converter) Convert(logs []gethTypes.Log, event types.Event, headerID in
|
|||||||
if len(b) == 32 {
|
if len(b) == 32 {
|
||||||
seenHashes = append(seenHashes, common.HexToHash(strValues[fieldName]))
|
seenHashes = append(seenHashes, common.HexToHash(strValues[fieldName]))
|
||||||
}
|
}
|
||||||
case byte:
|
case uint8:
|
||||||
b := input.(byte)
|
u := input.(uint8)
|
||||||
strValues[fieldName] = string(b)
|
strValues[fieldName] = strconv.Itoa(int(u))
|
||||||
|
case [32]uint8:
|
||||||
|
raw := input.([32]uint8)
|
||||||
|
converted := convertUintSliceToHash(raw)
|
||||||
|
strValues[fieldName] = converted.String()
|
||||||
|
seenHashes = append(seenHashes, converted)
|
||||||
default:
|
default:
|
||||||
return nil, errors.New(fmt.Sprintf("error: unhandled abi type %T", input))
|
return nil, errors.New(fmt.Sprintf("error: unhandled abi type %T", input))
|
||||||
}
|
}
|
||||||
@@ -127,7 +132,7 @@ func (c *Converter) Convert(logs []gethTypes.Log, event types.Event, headerID in
|
|||||||
|
|
||||||
// Convert the given watched event logs into types.Logs; returns a map of event names to a slice of their converted logs
|
// Convert the given watched event logs into types.Logs; returns a map of event names to a slice of their converted logs
|
||||||
func (c *Converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.Event, headerID int64) (map[string][]types.Log, error) {
|
func (c *Converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.Event, headerID int64) (map[string][]types.Log, error) {
|
||||||
contract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil)
|
boundContract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil)
|
||||||
eventsToLogs := make(map[string][]types.Log)
|
eventsToLogs := make(map[string][]types.Log)
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
eventsToLogs[event.Name] = make([]types.Log, 0, len(logs))
|
eventsToLogs[event.Name] = make([]types.Log, 0, len(logs))
|
||||||
@@ -136,7 +141,7 @@ func (c *Converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.E
|
|||||||
// If the log is of this event type, process it as such
|
// If the log is of this event type, process it as such
|
||||||
if event.Sig() == log.Topics[0] {
|
if event.Sig() == log.Topics[0] {
|
||||||
values := make(map[string]interface{})
|
values := make(map[string]interface{})
|
||||||
err := contract.UnpackLogIntoMap(values, event.Name, log)
|
err := boundContract.UnpackLogIntoMap(values, event.Name, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -168,9 +173,14 @@ func (c *Converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.E
|
|||||||
if len(b) == 32 { // collect byte arrays of size 32 as hashes
|
if len(b) == 32 { // collect byte arrays of size 32 as hashes
|
||||||
seenHashes = append(seenHashes, common.BytesToHash(b))
|
seenHashes = append(seenHashes, common.BytesToHash(b))
|
||||||
}
|
}
|
||||||
case byte:
|
case uint8:
|
||||||
b := input.(byte)
|
u := input.(uint8)
|
||||||
strValues[fieldName] = string(b)
|
strValues[fieldName] = strconv.Itoa(int(u))
|
||||||
|
case [32]uint8:
|
||||||
|
raw := input.([32]uint8)
|
||||||
|
converted := convertUintSliceToHash(raw)
|
||||||
|
strValues[fieldName] = converted.String()
|
||||||
|
seenHashes = append(seenHashes, converted)
|
||||||
default:
|
default:
|
||||||
return nil, errors.New(fmt.Sprintf("error: unhandled abi type %T", input))
|
return nil, errors.New(fmt.Sprintf("error: unhandled abi type %T", input))
|
||||||
}
|
}
|
||||||
@@ -205,3 +215,11 @@ func (c *Converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.E
|
|||||||
|
|
||||||
return eventsToLogs, nil
|
return eventsToLogs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func convertUintSliceToHash(raw [32]uint8) common.Hash {
|
||||||
|
var asBytes []byte
|
||||||
|
for _, u := range raw {
|
||||||
|
asBytes = append(asBytes, u)
|
||||||
|
}
|
||||||
|
return common.BytesToHash(asBytes)
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ var _ = Describe("Converter", func() {
|
|||||||
var con *contract.Contract
|
var con *contract.Contract
|
||||||
var tusdWantedEvents = []string{"Transfer", "Mint"}
|
var tusdWantedEvents = []string{"Transfer", "Mint"}
|
||||||
var ensWantedEvents = []string{"NewOwner"}
|
var ensWantedEvents = []string{"NewOwner"}
|
||||||
|
var marketPlaceWantedEvents = []string{"OrderCreated"}
|
||||||
|
var molochWantedEvents = []string{"SubmitVote"}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
Describe("Update", func() {
|
Describe("Update", func() {
|
||||||
@@ -145,6 +147,34 @@ var _ = Describe("Converter", func() {
|
|||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("correctly parses bytes32", func() {
|
||||||
|
con = test_helpers.SetupMarketPlaceContract(marketPlaceWantedEvents, []string{})
|
||||||
|
event, ok := con.Events["OrderCreated"]
|
||||||
|
Expect(ok).To(BeTrue())
|
||||||
|
|
||||||
|
c := converter.Converter{}
|
||||||
|
c.Update(con)
|
||||||
|
result, err := c.Convert([]types.Log{mocks.MockOrderCreatedLog}, event, 232)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(result)).To(Equal(1))
|
||||||
|
Expect(result[0].Values["id"]).To(Equal("0x633f94affdcabe07c000231f85c752c97b9cc43966b432ec4d18641e6d178233"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("correctly parses uint8", func() {
|
||||||
|
con = test_helpers.SetupMolochContract(molochWantedEvents, []string{})
|
||||||
|
event, ok := con.Events["SubmitVote"]
|
||||||
|
Expect(ok).To(BeTrue())
|
||||||
|
|
||||||
|
c := converter.Converter{}
|
||||||
|
c.Update(con)
|
||||||
|
result, err := c.Convert([]types.Log{mocks.MockSubmitVoteLog}, event, 232)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(len(result)).To(Equal(1))
|
||||||
|
Expect(result[0].Values["uintVote"]).To(Equal("1"))
|
||||||
|
})
|
||||||
|
|
||||||
It("Fails with an empty contract", func() {
|
It("Fails with an empty contract", func() {
|
||||||
event := con.Events["Transfer"]
|
event := con.Events["Transfer"]
|
||||||
c := converter.Converter{}
|
c := converter.Converter{}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
@@ -148,7 +149,10 @@ func (r *headerRepository) MarkHeadersCheckedForAll(headers []core.Header, ids [
|
|||||||
pgStr = pgStr[:len(pgStr)-2]
|
pgStr = pgStr[:len(pgStr)-2]
|
||||||
_, err = tx.Exec(pgStr, header.Id)
|
_, err = tx.Exec(pgStr, header.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
rollbackErr := tx.Rollback()
|
||||||
|
if rollbackErr != nil {
|
||||||
|
logrus.Warnf("error rolling back transaction: %s", rollbackErr.Error())
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,7 +183,7 @@ func (r *headerRepository) MissingHeaders(startingBlockNumber, endingBlockNumber
|
|||||||
ORDER BY headers.block_number`
|
ORDER BY headers.block_number`
|
||||||
err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID)
|
err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID)
|
||||||
}
|
}
|
||||||
return contiguousHeaders(result, startingBlockNumber), err
|
return continuousHeaders(result), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns missing headers for all of the provided checked_headers column ids
|
// Returns missing headers for all of the provided checked_headers column ids
|
||||||
@@ -207,26 +211,7 @@ func (r *headerRepository) MissingHeadersForAll(startingBlockNumber, endingBlock
|
|||||||
query = baseQuery + endStr
|
query = baseQuery + endStr
|
||||||
err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID)
|
err = r.db.Select(&result, query, startingBlockNumber, endingBlockNumber, r.db.Node.ID)
|
||||||
}
|
}
|
||||||
return contiguousHeaders(result, startingBlockNumber), err
|
return continuousHeaders(result), err
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a continuous set of headers that is contiguous with the provided startingBlockNumber
|
|
||||||
func contiguousHeaders(headers []core.Header, startingBlockNumber int64) []core.Header {
|
|
||||||
if len(headers) < 1 {
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
previousHeader := headers[0].BlockNumber
|
|
||||||
if previousHeader != startingBlockNumber {
|
|
||||||
return []core.Header{}
|
|
||||||
}
|
|
||||||
for i := 1; i < len(headers); i++ {
|
|
||||||
previousHeader++
|
|
||||||
if headers[i].BlockNumber != previousHeader {
|
|
||||||
return headers[:i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns headers that have been checked for all of the provided event ids but not for the provided method ids
|
// Returns headers that have been checked for all of the provided event ids but not for the provided method ids
|
||||||
@@ -265,6 +250,7 @@ func (r *headerRepository) MissingMethodsCheckedEventsIntersection(startingBlock
|
|||||||
// Returns a continuous set of headers
|
// Returns a continuous set of headers
|
||||||
func continuousHeaders(headers []core.Header) []core.Header {
|
func continuousHeaders(headers []core.Header) []core.Header {
|
||||||
if len(headers) < 1 {
|
if len(headers) < 1 {
|
||||||
|
logrus.Trace("no headers to arrange continuously")
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
previousHeader := headers[0].BlockNumber
|
previousHeader := headers[0].BlockNumber
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user