forked from cerc-io/ipld-eth-server
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25f9c6c9e3 | ||
|
|
e252229b8a | ||
|
|
62e1378e0c | ||
|
|
b8fec5e4e3 | ||
|
|
b7675316b4 | ||
|
|
a2d249ca9d | ||
|
|
4fbde836d4 | ||
|
|
65808998b3 | ||
|
|
11b5efbfe3 | ||
|
|
3fff2896aa | ||
|
|
f7c4a6736d | ||
|
|
6c055a9e12 | ||
|
|
7be070fcea | ||
|
|
2800e6df36 | ||
|
|
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 |
+4
-4
@@ -23,10 +23,10 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/pkg/crypto"
|
"github.com/vulcanize/vulcanizedb/pkg/crypto"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/ethereum"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/ethereum"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/eth/cold_import"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/eth/converters/cold_db"
|
||||||
|
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/eth/converters/common"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/cold_import"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/converters/cold_db"
|
|
||||||
vulcCommon "github.com/vulcanize/vulcanizedb/pkg/geth/converters/common"
|
|
||||||
"github.com/vulcanize/vulcanizedb/utils"
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
"github.com/vulcanize/vulcanizedb/pkg/eth"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/history"
|
"github.com/vulcanize/vulcanizedb/pkg/history"
|
||||||
"github.com/vulcanize/vulcanizedb/utils"
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
)
|
)
|
||||||
@@ -100,7 +100,7 @@ func headerSync() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateArgs(blockChain *geth.BlockChain) {
|
func validateArgs(blockChain *eth.BlockChain) {
|
||||||
lastBlock, err := blockChain.LastBlock()
|
lastBlock, err := blockChain.LastBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Error("validateArgs: Error getting last block: ", err)
|
LogWithCommand.Error("validateArgs: Error getting last block: ", err)
|
||||||
|
|||||||
+19
-9
@@ -28,10 +28,10 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/config"
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
"github.com/vulcanize/vulcanizedb/pkg/eth"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/client"
|
"github.com/vulcanize/vulcanizedb/pkg/eth/client"
|
||||||
vRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
|
vRpc "github.com/vulcanize/vulcanizedb/pkg/eth/converters/rpc"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
|
"github.com/vulcanize/vulcanizedb/pkg/eth/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -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"))
|
||||||
}
|
}
|
||||||
@@ -151,7 +155,15 @@ func initConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlockChain() *geth.BlockChain {
|
func getBlockChain() *eth.BlockChain {
|
||||||
|
rpcClient, ethClient := getClients()
|
||||||
|
vdbEthClient := client.NewEthClient(ethClient)
|
||||||
|
vdbNode := node.MakeNode(rpcClient)
|
||||||
|
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
|
||||||
|
return eth.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,20 @@
|
|||||||
|
-- +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),
|
||||||
|
UNIQUE (block_number, hash, eth_node_fingerprint)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 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;
|
||||||
+262
-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: -
|
||||||
--
|
--
|
||||||
@@ -758,6 +921,14 @@ ALTER TABLE ONLY public.header_sync_transactions
|
|||||||
ADD CONSTRAINT header_sync_transactions_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT header_sync_transactions_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: headers headers_block_number_hash_eth_node_fingerprint_key; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.headers
|
||||||
|
ADD CONSTRAINT headers_block_number_hash_eth_node_fingerprint_key UNIQUE (block_number, hash, eth_node_fingerprint);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: headers headers_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: headers headers_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -766,14 +937,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 +1001,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 +1067,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 +1083,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 +1148,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.20.0 // 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=
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ import (
|
|||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
"github.com/vulcanize/vulcanizedb/pkg/eth"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/client"
|
"github.com/vulcanize/vulcanizedb/pkg/eth/client"
|
||||||
vRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
|
vRpc "github.com/vulcanize/vulcanizedb/pkg/eth/converters/rpc"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
|
"github.com/vulcanize/vulcanizedb/pkg/eth/node"
|
||||||
"github.com/vulcanize/vulcanizedb/test_config"
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ var _ = Describe("Rewards calculations", func() {
|
|||||||
blockChainClient := client.NewEthClient(ethClient)
|
blockChainClient := client.NewEthClient(ethClient)
|
||||||
node := node.MakeNode(rpcClient)
|
node := node.MakeNode(rpcClient)
|
||||||
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
|
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := eth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
block, err := blockChain.GetBlockByNumber(1071819)
|
block, err := blockChain.GetBlockByNumber(1071819)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(block.Reward).To(Equal("5313550000000000000"))
|
Expect(block.Reward).To(Equal("5313550000000000000"))
|
||||||
@@ -53,7 +53,7 @@ var _ = Describe("Rewards calculations", func() {
|
|||||||
blockChainClient := client.NewEthClient(ethClient)
|
blockChainClient := client.NewEthClient(ethClient)
|
||||||
node := node.MakeNode(rpcClient)
|
node := node.MakeNode(rpcClient)
|
||||||
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
|
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := eth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
block, err := blockChain.GetBlockByNumber(1071819)
|
block, err := blockChain.GetBlockByNumber(1071819)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(block.UnclesReward).To(Equal("6875000000000000000"))
|
Expect(block.UnclesReward).To(Equal("6875000000000000000"))
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ import (
|
|||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
"github.com/vulcanize/vulcanizedb/pkg/eth"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/client"
|
"github.com/vulcanize/vulcanizedb/pkg/eth/client"
|
||||||
rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
|
rpc2 "github.com/vulcanize/vulcanizedb/pkg/eth/converters/rpc"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
|
"github.com/vulcanize/vulcanizedb/pkg/eth/node"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/testing"
|
"github.com/vulcanize/vulcanizedb/pkg/eth/testing"
|
||||||
"github.com/vulcanize/vulcanizedb/test_config"
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -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",
|
||||||
@@ -56,10 +56,10 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
blockChainClient := client.NewEthClient(ethClient)
|
blockChainClient := client.NewEthClient(ethClient)
|
||||||
node := node.MakeNode(rpcClient)
|
node := node.MakeNode(rpcClient)
|
||||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := eth.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))
|
||||||
@@ -74,9 +74,9 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
blockChainClient := client.NewEthClient(ethClient)
|
blockChainClient := client.NewEthClient(ethClient)
|
||||||
node := node.MakeNode(rpcClient)
|
node := node.MakeNode(rpcClient)
|
||||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := eth.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))
|
||||||
@@ -92,7 +92,7 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
blockChainClient := client.NewEthClient(ethClient)
|
blockChainClient := client.NewEthClient(ethClient)
|
||||||
node := node.MakeNode(rpcClient)
|
node := node.MakeNode(rpcClient)
|
||||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := eth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
|
|
||||||
contract := testing.SampleContract()
|
contract := testing.SampleContract()
|
||||||
var balance = new(big.Int)
|
var balance = new(big.Int)
|
||||||
|
|||||||
@@ -1,8 +1,23 @@
|
|||||||
|
// 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 (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/config"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -11,6 +26,7 @@ import (
|
|||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/transformer"
|
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants"
|
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers"
|
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers"
|
||||||
|
|||||||
@@ -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 (
|
||||||
@@ -24,8 +40,8 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
var blockChain core.BlockChain
|
var blockChain core.BlockChain
|
||||||
var headerRepository repositories.HeaderRepository
|
var headerRepository repositories.HeaderRepository
|
||||||
var headerID int64
|
var headerID int64
|
||||||
var ensAddr = strings.ToLower(constants.EnsContractAddress)
|
var ensAddr = strings.ToLower(constants.EnsContractAddress) // 0x314159265dd8dbb310642f98f50c066173c1259b
|
||||||
var tusdAddr = strings.ToLower(constants.TusdContractAddress)
|
var tusdAddr = strings.ToLower(constants.TusdContractAddress) // 0x8dd5fbce2f6a956c3022ba3663759011dd51e73e
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
db, blockChain = test_helpers.SetupDBandBC()
|
db, blockChain = test_helpers.SetupDBandBC()
|
||||||
@@ -62,11 +78,10 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
Expect(c.Address).To(Equal(tusdAddr))
|
Expect(c.Address).To(Equal(tusdAddr))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Fails to initialize if first and block cannot be fetched from vDB headers table", func() {
|
It("initializes when no headers available in db", func() {
|
||||||
t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db)
|
t := transformer.NewTransformer(test_helpers.TusdConfig, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Does nothing if nothing if no addresses are configured", func() {
|
It("Does nothing if nothing if no addresses are configured", func() {
|
||||||
@@ -362,6 +377,42 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
Expect(transferLog.Value).To(Equal("2800000000000000000000"))
|
Expect(transferLog.Value).To(Equal("2800000000000000000000"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("Marks header checked for a contract that has no logs at that header", func() {
|
||||||
|
t := transformer.NewTransformer(test_helpers.ENSandTusdConfig, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(t.Start).To(Equal(int64(6885702)))
|
||||||
|
|
||||||
|
newOwnerLog := test_helpers.HeaderSyncNewOwnerLog{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.newowner_event", ensAddr)).StructScan(&newOwnerLog)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
transferLog := test_helpers.HeaderSyncTransferLog{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.transfer_event", tusdAddr)).StructScan(&transferLog)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(transferLog.HeaderID).ToNot(Equal(newOwnerLog.HeaderID))
|
||||||
|
|
||||||
|
type checkedHeader struct {
|
||||||
|
ID int64 `db:"id"`
|
||||||
|
HeaderID int64 `db:"header_id"`
|
||||||
|
NewOwner int64 `db:"newowner_0x314159265dd8dbb310642f98f50c066173c1259b"`
|
||||||
|
Transfer int64 `db:"transfer_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e"`
|
||||||
|
}
|
||||||
|
|
||||||
|
transferCheckedHeader := new(checkedHeader)
|
||||||
|
err = db.QueryRowx("SELECT * FROM public.checked_headers WHERE header_id = $1", transferLog.HeaderID).StructScan(transferCheckedHeader)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(transferCheckedHeader.Transfer).To(Equal(int64(1)))
|
||||||
|
Expect(transferCheckedHeader.NewOwner).To(Equal(int64(1)))
|
||||||
|
|
||||||
|
newOwnerCheckedHeader := new(checkedHeader)
|
||||||
|
err = db.QueryRowx("SELECT * FROM public.checked_headers WHERE header_id = $1", newOwnerLog.HeaderID).StructScan(newOwnerCheckedHeader)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(newOwnerCheckedHeader.NewOwner).To(Equal(int64(1)))
|
||||||
|
Expect(newOwnerCheckedHeader.Transfer).To(Equal(int64(1)))
|
||||||
|
})
|
||||||
|
|
||||||
It("Keeps track of contract-related hashes and addresses while transforming event data if they need to be used for later method polling", func() {
|
It("Keeps track of contract-related hashes and addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
var testConf config.ContractConfig
|
var testConf config.ContractConfig
|
||||||
testConf = test_helpers.ENSandTusdConfig
|
testConf = test_helpers.ENSandTusdConfig
|
||||||
|
|||||||
@@ -24,17 +24,17 @@ import (
|
|||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/eth"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/eth/client"
|
||||||
|
rpc2 "github.com/vulcanize/vulcanizedb/pkg/eth/converters/rpc"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/eth/node"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/client"
|
|
||||||
rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/history"
|
"github.com/vulcanize/vulcanizedb/pkg/history"
|
||||||
"github.com/vulcanize/vulcanizedb/test_config"
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Reading from the Geth blockchain", func() {
|
var _ = Describe("Reading from the Geth blockchain", func() {
|
||||||
var blockChain *geth.BlockChain
|
var blockChain *eth.BlockChain
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
rawRpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath)
|
rawRpcClient, err := rpc.Dial(test_config.InfuraClient.IPCPath)
|
||||||
@@ -44,7 +44,7 @@ var _ = Describe("Reading from the Geth blockchain", func() {
|
|||||||
blockChainClient := client.NewEthClient(ethClient)
|
blockChainClient := client.NewEthClient(ethClient)
|
||||||
node := node.MakeNode(rpcClient)
|
node := node.MakeNode(rpcClient)
|
||||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain = geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain = eth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
})
|
})
|
||||||
|
|
||||||
It("reads two blocks", func(done Done) {
|
It("reads two blocks", func(done Done) {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package integration_test
|
package integration_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@@ -27,3 +29,7 @@ func TestIntegrationTest(t *testing.T) {
|
|||||||
RegisterFailHandler(Fail)
|
RegisterFailHandler(Fail)
|
||||||
RunSpecs(t, "IntegrationTest Suite")
|
RunSpecs(t, "IntegrationTest Suite")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func() {
|
||||||
|
logrus.SetOutput(ioutil.Discard)
|
||||||
|
})
|
||||||
|
|||||||
@@ -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,13 @@
|
|||||||
|
|
||||||
package event
|
package event
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/core/types"
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Converter transforms log data into general InsertionModels the Repository can persist__
|
||||||
type Converter interface {
|
type Converter interface {
|
||||||
ToEntities(contractAbi string, ethLog []types.Log) ([]interface{}, error)
|
ToModels(contractAbi string, ethLog []core.HeaderSyncLog) ([]InsertionModel, error)
|
||||||
ToModels([]interface{}) ([]interface{}, error)
|
SetDB(db *postgres.DB)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,162 @@
|
|||||||
package event
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const SetLogTransformedQuery = `UPDATE public.header_sync_logs SET transformed = true WHERE id = $1`
|
||||||
|
|
||||||
|
// Repository persists transformed values to the DB
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
Create(headerID int64, models []interface{}) error
|
Create(models []InsertionModel) error
|
||||||
MarkHeaderChecked(headerID int64) error
|
|
||||||
SetDB(db *postgres.DB)
|
SetDB(db *postgres.DB)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogFK is the name of log foreign key columns
|
||||||
|
const LogFK ColumnName = "log_id"
|
||||||
|
|
||||||
|
// AddressFK is the name of address foreign key columns
|
||||||
|
const AddressFK ColumnName = "address_id"
|
||||||
|
|
||||||
|
// HeaderFK is the name of header foreign key columns
|
||||||
|
const HeaderFK ColumnName = "header_id"
|
||||||
|
|
||||||
|
// SchemaName is the schema to work with
|
||||||
|
type SchemaName string
|
||||||
|
|
||||||
|
// TableName identifies the table for inserting the data
|
||||||
|
type TableName string
|
||||||
|
|
||||||
|
// ColumnName identifies columns on the given table
|
||||||
|
type ColumnName string
|
||||||
|
|
||||||
|
// ColumnValues maps a column to the value for insertion. This is restricted to []byte, bool, float64, int64, string, time.Time
|
||||||
|
type ColumnValues map[ColumnName]interface{}
|
||||||
|
|
||||||
|
// ErrUnsupportedValue is thrown when a model supplies a type of value the postgres driver cannot handle.
|
||||||
|
var ErrUnsupportedValue = func(value interface{}) error {
|
||||||
|
return fmt.Errorf("unsupported type of value supplied in model: %v (%T)", value, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertionModel is the generalised data structure a converter returns, and contains everything the repository needs to
|
||||||
|
// persist the converted data.
|
||||||
|
type InsertionModel struct {
|
||||||
|
SchemaName SchemaName
|
||||||
|
TableName TableName
|
||||||
|
OrderedColumns []ColumnName // Defines the fields to insert, and in which order the table expects them
|
||||||
|
ColumnValues ColumnValues // Associated values for columns, restricted to []byte, bool, float64, int64, string, time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelToQuery stores memoised insertion queries to minimise computation
|
||||||
|
var ModelToQuery = map[string]string{}
|
||||||
|
|
||||||
|
// GetMemoizedQuery gets/creates a DB insertion query for the model
|
||||||
|
func GetMemoizedQuery(model InsertionModel) string {
|
||||||
|
// The schema and table name uniquely determines the insertion query, use that for memoization
|
||||||
|
queryKey := string(model.SchemaName) + string(model.TableName)
|
||||||
|
query, queryMemoized := ModelToQuery[queryKey]
|
||||||
|
if !queryMemoized {
|
||||||
|
query = GenerateInsertionQuery(model)
|
||||||
|
ModelToQuery[queryKey] = query
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateInsertionQuery creates an SQL insertion query from an insertion model.
|
||||||
|
// Should be called through GetMemoizedQuery, so the query is not generated on each call to Create.
|
||||||
|
func GenerateInsertionQuery(model InsertionModel) string {
|
||||||
|
var valuePlaceholders []string
|
||||||
|
var updateOnConflict []string
|
||||||
|
for i := 0; i < len(model.OrderedColumns); i++ {
|
||||||
|
valuePlaceholder := fmt.Sprintf("$%d", 1+i)
|
||||||
|
valuePlaceholders = append(valuePlaceholders, valuePlaceholder)
|
||||||
|
updateOnConflict = append(updateOnConflict,
|
||||||
|
fmt.Sprintf("%s = %s", model.OrderedColumns[i], valuePlaceholder))
|
||||||
|
}
|
||||||
|
|
||||||
|
baseQuery := `INSERT INTO %v.%v (%v) VALUES(%v)
|
||||||
|
ON CONFLICT (header_id, log_id) DO UPDATE SET %v;`
|
||||||
|
|
||||||
|
return fmt.Sprintf(baseQuery,
|
||||||
|
model.SchemaName,
|
||||||
|
model.TableName,
|
||||||
|
joinOrderedColumns(model.OrderedColumns),
|
||||||
|
strings.Join(valuePlaceholders, ", "),
|
||||||
|
strings.Join(updateOnConflict, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create generates an insertion query and persists to the DB, given a slice of InsertionModels.
|
||||||
|
ColumnValues are restricted to []byte, bool, float64, int64, string, time.Time.
|
||||||
|
|
||||||
|
testModel = shared.InsertionModel{
|
||||||
|
SchemaName: "public"
|
||||||
|
TableName: "testEvent",
|
||||||
|
OrderedColumns: []string{"header_id", "log_id", "variable1"},
|
||||||
|
ColumnValues: ColumnValues{
|
||||||
|
"header_id": 303
|
||||||
|
"log_id": "808",
|
||||||
|
"variable1": "value1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
func Create(models []InsertionModel, db *postgres.DB) error {
|
||||||
|
if len(models) == 0 {
|
||||||
|
return fmt.Errorf("repository got empty model slice")
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, dbErr := db.Beginx()
|
||||||
|
if dbErr != nil {
|
||||||
|
return dbErr
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, model := range models {
|
||||||
|
// Maps can't be iterated over in a reliable manner, so we rely on OrderedColumns to define the order to insert
|
||||||
|
// tx.Exec is variadically typed in the args, so if we wrap in []interface{} we can apply them all automatically
|
||||||
|
var args []interface{}
|
||||||
|
for _, col := range model.OrderedColumns {
|
||||||
|
value := model.ColumnValues[col]
|
||||||
|
// Check whether or not PG can accept the type of value in the model
|
||||||
|
okPgValue := driver.IsValue(value)
|
||||||
|
if !okPgValue {
|
||||||
|
logrus.WithField("model", model).Errorf("PG cannot handle value of this type: %T", value)
|
||||||
|
return ErrUnsupportedValue(value)
|
||||||
|
}
|
||||||
|
args = append(args, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
insertionQuery := GetMemoizedQuery(model)
|
||||||
|
_, execErr := tx.Exec(insertionQuery, args...) // couldn't pass varying types in bulk with args :: []string
|
||||||
|
|
||||||
|
if execErr != nil {
|
||||||
|
rollbackErr := tx.Rollback()
|
||||||
|
if rollbackErr != nil {
|
||||||
|
logrus.Error("failed to rollback ", rollbackErr)
|
||||||
|
}
|
||||||
|
return execErr
|
||||||
|
}
|
||||||
|
|
||||||
|
_, logErr := tx.Exec(SetLogTransformedQuery, model.ColumnValues[LogFK])
|
||||||
|
|
||||||
|
if logErr != nil {
|
||||||
|
utils.RollbackAndLogFailure(tx, logErr, "header_sync_logs.transformed")
|
||||||
|
return logErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func joinOrderedColumns(columns []ColumnName) string {
|
||||||
|
var stringColumns []string
|
||||||
|
for _, columnName := range columns {
|
||||||
|
stringColumns = append(stringColumns, string(columnName))
|
||||||
|
}
|
||||||
|
return strings.Join(stringColumns, ", ")
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,204 @@
|
|||||||
|
// 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 event_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/factories/event"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/test_data"
|
||||||
|
"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/test_config"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Repository", func() {
|
||||||
|
var db *postgres.DB
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
db = test_config.NewTestDB(test_config.NewTestNode())
|
||||||
|
test_config.CleanTestDB(db)
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Create", func() {
|
||||||
|
const createTestEventTableQuery = `CREATE TABLE public.testEvent(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
header_id INTEGER NOT NULL REFERENCES headers (id) ON DELETE CASCADE,
|
||||||
|
log_id BIGINT NOT NULL REFERENCES header_sync_logs (id) ON DELETE CASCADE,
|
||||||
|
variable1 TEXT,
|
||||||
|
UNIQUE (header_id, log_id)
|
||||||
|
);`
|
||||||
|
|
||||||
|
var (
|
||||||
|
headerID, logID int64
|
||||||
|
headerRepository repositories.HeaderRepository
|
||||||
|
testModel event.InsertionModel
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
_, tableErr := db.Exec(createTestEventTableQuery)
|
||||||
|
Expect(tableErr).NotTo(HaveOccurred())
|
||||||
|
headerRepository = repositories.NewHeaderRepository(db)
|
||||||
|
var insertHeaderErr error
|
||||||
|
headerID, insertHeaderErr = headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
|
||||||
|
Expect(insertHeaderErr).NotTo(HaveOccurred())
|
||||||
|
headerSyncLog := test_data.CreateTestLog(headerID, db)
|
||||||
|
logID = headerSyncLog.ID
|
||||||
|
|
||||||
|
testModel = event.InsertionModel{
|
||||||
|
SchemaName: "public",
|
||||||
|
TableName: "testEvent",
|
||||||
|
OrderedColumns: []event.ColumnName{
|
||||||
|
event.HeaderFK, event.LogFK, "variable1",
|
||||||
|
},
|
||||||
|
ColumnValues: event.ColumnValues{
|
||||||
|
event.HeaderFK: headerID,
|
||||||
|
event.LogFK: logID,
|
||||||
|
"variable1": "value1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
db.MustExec(`DROP TABLE public.testEvent;`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Needs to run before the other tests, since those insert keys in map
|
||||||
|
It("memoizes queries", func() {
|
||||||
|
Expect(len(event.ModelToQuery)).To(Equal(0))
|
||||||
|
event.GetMemoizedQuery(testModel)
|
||||||
|
Expect(len(event.ModelToQuery)).To(Equal(1))
|
||||||
|
event.GetMemoizedQuery(testModel)
|
||||||
|
Expect(len(event.ModelToQuery)).To(Equal(1))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("persists a model to postgres", func() {
|
||||||
|
createErr := event.Create([]event.InsertionModel{testModel}, db)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
var res TestEvent
|
||||||
|
dbErr := db.Get(&res, `SELECT log_id, variable1 FROM public.testEvent;`)
|
||||||
|
Expect(dbErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(res.LogID).To(Equal(fmt.Sprint(testModel.ColumnValues[event.LogFK])))
|
||||||
|
Expect(res.Variable1).To(Equal(testModel.ColumnValues["variable1"]))
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("returns errors", func() {
|
||||||
|
It("for empty model slice", func() {
|
||||||
|
err := event.Create([]event.InsertionModel{}, db)
|
||||||
|
Expect(err).To(MatchError("repository got empty model slice"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("for failed SQL inserts", func() {
|
||||||
|
header := fakes.GetFakeHeader(1)
|
||||||
|
headerID, headerErr := headerRepository.CreateOrUpdateHeader(header)
|
||||||
|
Expect(headerErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
brokenModel := event.InsertionModel{
|
||||||
|
SchemaName: "public",
|
||||||
|
TableName: "testEvent",
|
||||||
|
// Wrong name of last column compared to DB, will generate incorrect query
|
||||||
|
OrderedColumns: []event.ColumnName{
|
||||||
|
event.HeaderFK, event.LogFK, "variable2",
|
||||||
|
},
|
||||||
|
ColumnValues: event.ColumnValues{
|
||||||
|
event.HeaderFK: headerID,
|
||||||
|
event.LogFK: logID,
|
||||||
|
"variable1": "value1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove cached queries, or we won't generate a new (incorrect) one
|
||||||
|
delete(event.ModelToQuery, "publictestEvent")
|
||||||
|
|
||||||
|
createErr := event.Create([]event.InsertionModel{brokenModel}, db)
|
||||||
|
// Remove incorrect query, so other tests won't get it
|
||||||
|
delete(event.ModelToQuery, "publictestEvent")
|
||||||
|
|
||||||
|
Expect(createErr).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("for unsupported types in ColumnValue", func() {
|
||||||
|
unsupportedValue := big.NewInt(5)
|
||||||
|
testModel = event.InsertionModel{
|
||||||
|
SchemaName: "public",
|
||||||
|
TableName: "testEvent",
|
||||||
|
OrderedColumns: []event.ColumnName{
|
||||||
|
event.HeaderFK, event.LogFK, "variable1",
|
||||||
|
},
|
||||||
|
ColumnValues: event.ColumnValues{
|
||||||
|
event.HeaderFK: headerID,
|
||||||
|
event.LogFK: logID,
|
||||||
|
"variable1": unsupportedValue,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
createErr := event.Create([]event.InsertionModel{testModel}, db)
|
||||||
|
Expect(createErr).To(MatchError(event.ErrUnsupportedValue(unsupportedValue)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
It("upserts queries with conflicting source", func() {
|
||||||
|
conflictingModel := event.InsertionModel{
|
||||||
|
SchemaName: "public",
|
||||||
|
TableName: "testEvent",
|
||||||
|
OrderedColumns: []event.ColumnName{
|
||||||
|
event.HeaderFK, event.LogFK, "variable1",
|
||||||
|
},
|
||||||
|
ColumnValues: event.ColumnValues{
|
||||||
|
event.HeaderFK: headerID,
|
||||||
|
event.LogFK: logID,
|
||||||
|
"variable1": "conflictingValue",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
createErr := event.Create([]event.InsertionModel{testModel, conflictingModel}, db)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
var res TestEvent
|
||||||
|
dbErr := db.Get(&res, `SELECT log_id, variable1 FROM public.testEvent;`)
|
||||||
|
Expect(dbErr).NotTo(HaveOccurred())
|
||||||
|
Expect(res.Variable1).To(Equal(conflictingModel.ColumnValues["variable1"]))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("generates correct queries", func() {
|
||||||
|
actualQuery := event.GenerateInsertionQuery(testModel)
|
||||||
|
expectedQuery := `INSERT INTO public.testEvent (header_id, log_id, variable1) VALUES($1, $2, $3)
|
||||||
|
ON CONFLICT (header_id, log_id) DO UPDATE SET header_id = $1, log_id = $2, variable1 = $3;`
|
||||||
|
Expect(actualQuery).To(Equal(expectedQuery))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("marks log transformed", func() {
|
||||||
|
createErr := event.Create([]event.InsertionModel{testModel}, db)
|
||||||
|
Expect(createErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
var logTransformed bool
|
||||||
|
getErr := db.Get(&logTransformed, `SELECT transformed FROM public.header_sync_logs WHERE id = $1`, logID)
|
||||||
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
|
Expect(logTransformed).To(BeTrue())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
type TestEvent struct {
|
||||||
|
LogID string `db:"log_id"`
|
||||||
|
Variable1 string
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
@@ -32,38 +30,28 @@ type Transformer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.EventTransformer {
|
func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.EventTransformer {
|
||||||
|
transformer.Converter.SetDB(db)
|
||||||
transformer.Repository.SetDB(db)
|
transformer.Repository.SetDB(db)
|
||||||
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)
|
models, err := transformer.Converter.ToModels(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 entities to models in %v: %v", transformerName, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
models, err := transformer.Converter.ToModels(entities)
|
err = transformer.Repository.Create(models)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error converting entities to models in %v: %v", transformerName, err)
|
logrus.Errorf("error persisting %v record: %v", transformerName, err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = transformer.Repository.Create(header.Id, models)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error persisting %v record: %v", transformerName, err)
|
|
||||||
return err
|
return 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,93 +49,56 @@ 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.ToModelsCalledCounter).To(Equal(0))
|
Expect(converter.ToModelsCalledCounter).To(Equal(0))
|
||||||
Expect(repository.CreateCalledCounter).To(Equal(0))
|
Expect(repository.CreateCalledCounter).To(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("does not call repository.MarkCheckedHeader when there are logs", func() {
|
It("converts an eth log to a model", func() {
|
||||||
err := t.Execute(logs, headerOne)
|
err := t.Execute(logs)
|
||||||
|
|
||||||
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() {
|
|
||||||
err := t.Execute(logs, headerOne)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(converter.ContractAbi).To(Equal(config.ContractAbi))
|
Expect(converter.ContractAbi).To(Equal(config.ContractAbi))
|
||||||
Expect(converter.LogsToConvert).To(Equal(logs))
|
Expect(converter.LogsToConvert).To(Equal(logs))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns an error if converter fails", func() {
|
|
||||||
converter.ToEntitiesError = fakes.FakeError
|
|
||||||
|
|
||||||
err := t.Execute(logs, headerOne)
|
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("converts an entity to a model", func() {
|
|
||||||
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
|
||||||
|
|
||||||
err := t.Execute(logs, headerOne)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(converter.EntitiesToConvert[0]).To(Equal(test_data.GenericEntity{}))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("returns an error if converting to models fails", func() {
|
It("returns an error if converting to models fails", func() {
|
||||||
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))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("persists the record", func() {
|
It("persists the record", func() {
|
||||||
converter.ModelsToReturn = []interface{}{test_data.GenericModel{}}
|
converter.ModelsToReturn = []event.InsertionModel{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))
|
||||||
|
|||||||
@@ -31,15 +31,15 @@ The storage transformer depends on contract-specific implementations of code cap
|
|||||||
|
|
||||||
```golang
|
```golang
|
||||||
func (transformer Transformer) Execute(row shared.StorageDiffRow) error {
|
func (transformer Transformer) Execute(row shared.StorageDiffRow) error {
|
||||||
metadata, lookupErr := transformer.Mappings.Lookup(row.StorageKey)
|
metadata, lookupErr := transformer.StorageKeysLookup.Lookup(diff.StorageKey)
|
||||||
if lookupErr != nil {
|
if lookupErr != nil {
|
||||||
return lookupErr
|
return lookupErr
|
||||||
}
|
}
|
||||||
value, decodeErr := shared.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)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -47,20 +47,36 @@ func (transformer Transformer) Execute(row shared.StorageDiffRow) error {
|
|||||||
|
|
||||||
In order to watch an additional smart contract, a developer must create three things:
|
In order to watch an additional smart contract, a developer must create three things:
|
||||||
|
|
||||||
1. Mappings - specify how to identify keys in the contract's storage trie.
|
1. StorageKeysLoader - identify keys in the contract's storage trie, providing metadata to describe how associated values should be decoded.
|
||||||
1. Repository - specify how to persist a parsed version of the storage value matching the recognized storage key.
|
1. Repository - specify how to persist a parsed version of the storage value matching the recognized storage key.
|
||||||
1. Instance - create an instance of the storage transformer that uses your mappings and repository.
|
1. Instance - create an instance of the storage transformer that uses your mappings and repository.
|
||||||
|
|
||||||
### Mappings
|
### StorageKeysLoader
|
||||||
|
|
||||||
|
A `StorageKeysLoader` is used by the `StorageKeysLookup` object on a storage transformer.
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type Mappings interface {
|
type KeysLoader interface {
|
||||||
Lookup(key common.Hash) (shared.StorageValueMetadata, error)
|
LoadMappings() (map[common.Hash]utils.StorageValueMetadata, error)
|
||||||
SetDB(db *postgres.DB)
|
SetDB(db *postgres.DB)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
A contract-specific implementation of the mappings interface enables the storage transformer to fetch metadata associated with a storage key.
|
When a key is not found, the lookup object refreshes its known keys by calling the loader.
|
||||||
|
|
||||||
|
```golang
|
||||||
|
func (lookup *keysLookup) refreshMappings() error {
|
||||||
|
var err error
|
||||||
|
lookup.mappings, err = lookup.loader.LoadMappings()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
lookup.mappings = utils.AddHashedKeys(lookup.mappings)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
A contract-specific implementation of the loader enables the storage transformer to fetch metadata associated with a storage key.
|
||||||
|
|
||||||
Storage metadata contains: the name of the variable matching the storage key, a raw version of any keys associated with the variable (if the variable is a mapping), and the variable's type.
|
Storage metadata contains: the name of the variable matching the storage key, a raw version of any keys associated with the variable (if the variable is a mapping), and the variable's type.
|
||||||
|
|
||||||
@@ -72,7 +88,7 @@ type StorageValueMetadata struct {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Keys are only relevant if the variable is a mapping. For example, in the following Solidity code:
|
The `Keys` field on the metadata is only relevant if the variable is a mapping. For example, in the following Solidity code:
|
||||||
|
|
||||||
```solidity
|
```solidity
|
||||||
pragma solidity ^0.4.0;
|
pragma solidity ^0.4.0;
|
||||||
@@ -85,7 +101,7 @@ contract Contract {
|
|||||||
|
|
||||||
The metadata for variable `x` would not have any associated keys, but the metadata for a storage key associated with `y` would include the address used to specify that key's index in the mapping.
|
The metadata for variable `x` would not have any associated keys, but the metadata for a storage key associated with `y` would include the address used to specify that key's index in the mapping.
|
||||||
|
|
||||||
The `SetDB` function is required for the mappings to connect to the database.
|
The `SetDB` function is required for the storage key loader to connect to the database.
|
||||||
A database connection may be desired when keys in a mapping variable need to be read from log events (e.g. to lookup what addresses may exist in `y`, above).
|
A database connection may be desired when keys in a mapping variable need to be read from log events (e.g. to lookup what addresses may exist in `y`, above).
|
||||||
|
|
||||||
### Repository
|
### Repository
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// 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 storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KeysLoader interface {
|
||||||
|
LoadMappings() (map[common.Hash]utils.StorageValueMetadata, error)
|
||||||
|
SetDB(db *postgres.DB)
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// 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 storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KeysLookup interface {
|
||||||
|
Lookup(key common.Hash) (utils.StorageValueMetadata, error)
|
||||||
|
SetDB(db *postgres.DB)
|
||||||
|
}
|
||||||
|
|
||||||
|
type keysLookup struct {
|
||||||
|
loader KeysLoader
|
||||||
|
mappings map[common.Hash]utils.StorageValueMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKeysLookup(loader KeysLoader) KeysLookup {
|
||||||
|
return &keysLookup{loader: loader, mappings: make(map[common.Hash]utils.StorageValueMetadata)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lookup *keysLookup) Lookup(key common.Hash) (utils.StorageValueMetadata, error) {
|
||||||
|
metadata, ok := lookup.mappings[key]
|
||||||
|
if !ok {
|
||||||
|
refreshErr := lookup.refreshMappings()
|
||||||
|
if refreshErr != nil {
|
||||||
|
return metadata, refreshErr
|
||||||
|
}
|
||||||
|
metadata, ok = lookup.mappings[key]
|
||||||
|
if !ok {
|
||||||
|
return metadata, utils.ErrStorageKeyNotFound{Key: key.Hex()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lookup *keysLookup) refreshMappings() error {
|
||||||
|
var err error
|
||||||
|
lookup.mappings, err = lookup.loader.LoadMappings()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
lookup.mappings = utils.AddHashedKeys(lookup.mappings)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lookup *keysLookup) SetDB(db *postgres.DB) {
|
||||||
|
lookup.loader.SetDB(db)
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
// 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 storage_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/factories/storage"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Storage keys lookup", func() {
|
||||||
|
var (
|
||||||
|
fakeMetadata = utils.GetStorageValueMetadata("name", map[utils.Key]string{}, utils.Uint256)
|
||||||
|
lookup storage.KeysLookup
|
||||||
|
loader *mocks.MockStorageKeysLoader
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
loader = &mocks.MockStorageKeysLoader{}
|
||||||
|
lookup = storage.NewKeysLookup(loader)
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Lookup", func() {
|
||||||
|
Describe("when key not found", func() {
|
||||||
|
It("refreshes keys", func() {
|
||||||
|
loader.StorageKeyMappings = map[common.Hash]utils.StorageValueMetadata{fakes.FakeHash: fakeMetadata}
|
||||||
|
_, err := lookup.Lookup(fakes.FakeHash)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(loader.LoadMappingsCallCount).To(Equal(1))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if refreshing keys fails", func() {
|
||||||
|
loader.LoadMappingsError = fakes.FakeError
|
||||||
|
|
||||||
|
_, err := lookup.Lookup(fakes.FakeHash)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when key found", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
loader.StorageKeyMappings = map[common.Hash]utils.StorageValueMetadata{fakes.FakeHash: fakeMetadata}
|
||||||
|
_, err := lookup.Lookup(fakes.FakeHash)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(loader.LoadMappingsCallCount).To(Equal(1))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("does not refresh keys", func() {
|
||||||
|
_, err := lookup.Lookup(fakes.FakeHash)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(loader.LoadMappingsCallCount).To(Equal(1))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns metadata for loaded static key", func() {
|
||||||
|
loader.StorageKeyMappings = map[common.Hash]utils.StorageValueMetadata{fakes.FakeHash: fakeMetadata}
|
||||||
|
|
||||||
|
metadata, err := lookup.Lookup(fakes.FakeHash)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(metadata).To(Equal(fakeMetadata))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns metadata for hashed version of key (accommodates keys emitted from Geth)", func() {
|
||||||
|
loader.StorageKeyMappings = map[common.Hash]utils.StorageValueMetadata{fakes.FakeHash: fakeMetadata}
|
||||||
|
|
||||||
|
hashedKey := common.BytesToHash(crypto.Keccak256(fakes.FakeHash.Bytes()))
|
||||||
|
metadata, err := lookup.Lookup(hashedKey)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(metadata).To(Equal(fakeMetadata))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns key not found error if key not found", func() {
|
||||||
|
_, err := lookup.Lookup(fakes.FakeHash)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(utils.ErrStorageKeyNotFound{Key: fakes.FakeHash.Hex()}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("SetDB", func() {
|
||||||
|
It("sets the db on the loader", func() {
|
||||||
|
lookup.SetDB(test_config.NewTestDB(test_config.NewTestNode()))
|
||||||
|
|
||||||
|
Expect(loader.SetDBCalled).To(BeTrue())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
+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,38 +18,35 @@ 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/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 Transformer struct {
|
type Transformer struct {
|
||||||
Address common.Address
|
HashedAddress common.Hash
|
||||||
Mappings storage.Mappings
|
StorageKeysLookup KeysLookup
|
||||||
Repository repository.StorageRepository
|
Repository Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.StorageTransformer {
|
func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.StorageTransformer {
|
||||||
transformer.Mappings.SetDB(db)
|
transformer.StorageKeysLookup.SetDB(db)
|
||||||
transformer.Repository.SetDB(db)
|
transformer.Repository.SetDB(db)
|
||||||
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.StorageKeysLookup.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"
|
||||||
@@ -29,38 +28,38 @@ import (
|
|||||||
|
|
||||||
var _ = Describe("Storage transformer", func() {
|
var _ = Describe("Storage transformer", func() {
|
||||||
var (
|
var (
|
||||||
mappings *mocks.MockMappings
|
storageKeysLookup *mocks.MockStorageKeysLookup
|
||||||
repository *mocks.MockStorageRepository
|
repository *mocks.MockStorageRepository
|
||||||
t storage.Transformer
|
t storage.Transformer
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
mappings = &mocks.MockMappings{}
|
storageKeysLookup = &mocks.MockStorageKeysLookup{}
|
||||||
repository = &mocks.MockStorageRepository{}
|
repository = &mocks.MockStorageRepository{}
|
||||||
t = storage.Transformer{
|
t = storage.Transformer{
|
||||||
Address: common.Address{},
|
HashedAddress: common.Hash{},
|
||||||
Mappings: mappings,
|
StorageKeysLookup: storageKeysLookup,
|
||||||
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(storageKeysLookup.LookupCalled).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns error if lookup fails", func() {
|
It("returns error if lookup fails", func() {
|
||||||
mappings.LookupErr = fakes.FakeError
|
storageKeysLookup.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))
|
||||||
@@ -68,16 +67,16 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
|
|
||||||
It("creates storage row with decoded data", func() {
|
It("creates storage row with decoded data", func() {
|
||||||
fakeMetadata := utils.StorageValueMetadata{Type: utils.Address}
|
fakeMetadata := utils.StorageValueMetadata{Type: utils.Address}
|
||||||
mappings.Metadata = fakeMetadata
|
storageKeysLookup.Metadata = fakeMetadata
|
||||||
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)
|
||||||
@@ -92,10 +91,10 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
It("returns error if creating row fails", func() {
|
It("returns error if creating row fails", func() {
|
||||||
rawValue := common.HexToAddress("0x12345")
|
rawValue := common.HexToAddress("0x12345")
|
||||||
fakeMetadata := utils.StorageValueMetadata{Type: utils.Address}
|
fakeMetadata := utils.StorageValueMetadata{Type: utils.Address}
|
||||||
mappings.Metadata = fakeMetadata
|
storageKeysLookup.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))
|
||||||
@@ -119,13 +118,13 @@ 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
|
storageKeysLookup.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)
|
||||||
@@ -141,10 +140,10 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("returns error if creating a row fails", func() {
|
It("returns error if creating a row fails", func() {
|
||||||
mappings.Metadata = fakeMetadata
|
storageKeysLookup.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)
|
||||||
|
})
|
||||||
@@ -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 mocks
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockConverter struct {
|
|
||||||
ToEntitiesError error
|
|
||||||
PassedContractAddresses []string
|
|
||||||
ToModelsError error
|
|
||||||
entityConverterError error
|
|
||||||
modelConverterError error
|
|
||||||
ContractAbi string
|
|
||||||
LogsToConvert []types.Log
|
|
||||||
EntitiesToConvert []interface{}
|
|
||||||
EntitiesToReturn []interface{}
|
|
||||||
ModelsToReturn []interface{}
|
|
||||||
ToEntitiesCalledCounter int
|
|
||||||
ToModelsCalledCounter int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (converter *MockConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) {
|
|
||||||
for _, log := range ethLogs {
|
|
||||||
converter.PassedContractAddresses = append(converter.PassedContractAddresses, log.Address.Hex())
|
|
||||||
}
|
|
||||||
converter.ContractAbi = contractAbi
|
|
||||||
converter.LogsToConvert = ethLogs
|
|
||||||
return converter.EntitiesToReturn, converter.ToEntitiesError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (converter *MockConverter) ToModels(entities []interface{}) ([]interface{}, error) {
|
|
||||||
converter.EntitiesToConvert = entities
|
|
||||||
return converter.ModelsToReturn, converter.ToModelsError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (converter *MockConverter) SetToEntityConverterError(err error) {
|
|
||||||
converter.entityConverterError = err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (converter *MockConverter) SetToModelConverterError(err error) {
|
|
||||||
converter.modelConverterError = err
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// 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/factories/event"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockConverter struct {
|
||||||
|
ToModelsError error
|
||||||
|
ContractAbi string
|
||||||
|
LogsToConvert []core.HeaderSyncLog
|
||||||
|
ModelsToReturn []event.InsertionModel
|
||||||
|
PassedContractAddresses []string
|
||||||
|
SetDBCalled bool
|
||||||
|
ToModelsCalledCounter int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (converter *MockConverter) ToModels(abi string, logs []core.HeaderSyncLog) ([]event.InsertionModel, error) {
|
||||||
|
converter.LogsToConvert = logs
|
||||||
|
converter.ContractAbi = abi
|
||||||
|
converter.ToModelsCalledCounter = converter.ToModelsCalledCounter + 1
|
||||||
|
return converter.ModelsToReturn, converter.ToModelsError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (converter *MockConverter) SetDB(db *postgres.DB) {
|
||||||
|
converter.SetDBCalled = true
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// 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/factories/event"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockEventRepository struct {
|
||||||
|
createError error
|
||||||
|
PassedModels []event.InsertionModel
|
||||||
|
SetDbCalled bool
|
||||||
|
CreateCalledCounter int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repository *MockEventRepository) Create(models []event.InsertionModel) 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// 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/ethereum/go-ethereum/common"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockStorageKeysLoader struct {
|
||||||
|
LoadMappingsCallCount int
|
||||||
|
LoadMappingsError error
|
||||||
|
SetDBCalled bool
|
||||||
|
StorageKeyMappings map[common.Hash]utils.StorageValueMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *MockStorageKeysLoader) LoadMappings() (map[common.Hash]utils.StorageValueMetadata, error) {
|
||||||
|
loader.LoadMappingsCallCount++
|
||||||
|
return loader.StorageKeyMappings, loader.LoadMappingsError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *MockStorageKeysLoader) SetDB(db *postgres.DB) {
|
||||||
|
loader.SetDBCalled = true
|
||||||
|
}
|
||||||
@@ -18,22 +18,21 @@ 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/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MockMappings struct {
|
type MockStorageKeysLookup struct {
|
||||||
Metadata utils.StorageValueMetadata
|
Metadata utils.StorageValueMetadata
|
||||||
LookupCalled bool
|
LookupCalled bool
|
||||||
LookupErr error
|
LookupErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mappings *MockMappings) Lookup(key common.Hash) (utils.StorageValueMetadata, error) {
|
func (mappings *MockStorageKeysLookup) Lookup(key common.Hash) (utils.StorageValueMetadata, error) {
|
||||||
mappings.LookupCalled = true
|
mappings.LookupCalled = true
|
||||||
return mappings.Metadata, mappings.LookupErr
|
return mappings.Metadata, mappings.LookupErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*MockMappings) SetDB(db *postgres.DB) {
|
func (*MockStorageKeysLookup) SetDB(db *postgres.DB) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
@@ -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"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,143 +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 repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"database/sql/driver"
|
|
||||||
"fmt"
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
|
||||||
"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+`)
|
|
||||||
VALUES ($1, $2)
|
|
||||||
ON CONFLICT (header_id) DO
|
|
||||||
UPDATE SET `+checkedHeadersColumn+` = checked_headers.`+checkedHeadersColumn+` + 1`, headerID, 1)
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
@@ -1,303 +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 repository_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
|
||||||
. "github.com/onsi/gomega"
|
|
||||||
|
|
||||||
"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/repositories"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
|
||||||
"github.com/vulcanize/vulcanizedb/test_config"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Describe("Repository", func() {
|
|
||||||
var (
|
|
||||||
checkedHeadersColumn string
|
|
||||||
db *postgres.DB
|
|
||||||
)
|
|
||||||
|
|
||||||
Describe("MarkHeaderChecked", 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", 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)
|
|
||||||
headerID, headerErr := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
|
|
||||||
Expect(headerErr).NotTo(HaveOccurred())
|
|
||||||
tx, txErr := db.Beginx()
|
|
||||||
Expect(txErr).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
err := shared.MarkHeaderCheckedInTransaction(headerID, tx, checkedHeadersColumn)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
commitErr := tx.Commit()
|
|
||||||
Expect(commitErr).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("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",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
+7
-18
@@ -14,23 +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 storage
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"math/big"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mappings interface {
|
|
||||||
Lookup(key common.Hash) (utils.StorageValueMetadata, error)
|
|
||||||
SetDB(db *postgres.DB)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IndexZero = "0000000000000000000000000000000000000000000000000000000000000000"
|
IndexZero = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
IndexOne = "0000000000000000000000000000000000000000000000000000000000000001"
|
IndexOne = "0000000000000000000000000000000000000000000000000000000000000001"
|
||||||
@@ -46,19 +37,17 @@ const (
|
|||||||
IndexEleven = "000000000000000000000000000000000000000000000000000000000000000b"
|
IndexEleven = "000000000000000000000000000000000000000000000000000000000000000b"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetMapping(indexOnContract, key string) common.Hash {
|
func GetStorageKeyForMapping(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 GetStorageKeyForNestedMapping(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 GetIncrementedStorageKey(original common.Hash, incrementBy int64) common.Hash {
|
||||||
originalMappingAsInt := original.Big()
|
originalMappingAsInt := original.Big()
|
||||||
incremented := big.NewInt(0).Add(originalMappingAsInt, big.NewInt(incrementBy))
|
incremented := big.NewInt(0).Add(originalMappingAsInt, big.NewInt(incrementBy))
|
||||||
return common.BytesToHash(incremented.Bytes())
|
return common.BytesToHash(incremented.Bytes())
|
||||||
+31
-15
@@ -1,56 +1,72 @@
|
|||||||
package storage_test
|
// 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 (
|
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/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Mappings", func() {
|
var _ = Describe("Storage keys loader utils", func() {
|
||||||
Describe("GetMapping", func() {
|
Describe("GetStorageKeyForMapping", 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:
|
||||||
// mapping (bytes32 => uint) public amounts
|
// mapping (bytes32 => uint) public amounts
|
||||||
// to access amounts, pass in the index of the mapping on the contract + the bytes32 key for the uint val being looked up
|
// to access amounts, pass in the index of the mapping on the contract + the bytes32 key for the uint val being looked up
|
||||||
indexOfMappingOnContract := storage.IndexZero
|
indexOfMappingOnContract := utils.IndexZero
|
||||||
keyForDesiredValueInMapping := "1234567890abcdef"
|
keyForDesiredValueInMapping := "1234567890abcdef"
|
||||||
|
|
||||||
storageKey := storage.GetMapping(indexOfMappingOnContract, keyForDesiredValueInMapping)
|
storageKey := utils.GetStorageKeyForMapping(indexOfMappingOnContract, keyForDesiredValueInMapping)
|
||||||
|
|
||||||
expectedStorageKey := common.HexToHash("0xee0c1b59a3856bafbfb8730e7694c4badc271eb5f01ce4a8d7a53d8a6499676f")
|
expectedStorageKey := common.HexToHash("0xee0c1b59a3856bafbfb8730e7694c4badc271eb5f01ce4a8d7a53d8a6499676f")
|
||||||
Expect(storageKey).To(Equal(expectedStorageKey))
|
Expect(storageKey).To(Equal(expectedStorageKey))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("returns same result if value includes hex prefix", func() {
|
It("returns same result if value includes hex prefix", func() {
|
||||||
indexOfMappingOnContract := storage.IndexZero
|
indexOfMappingOnContract := utils.IndexZero
|
||||||
keyForDesiredValueInMapping := "0x1234567890abcdef"
|
keyForDesiredValueInMapping := "0x1234567890abcdef"
|
||||||
|
|
||||||
storageKey := storage.GetMapping(indexOfMappingOnContract, keyForDesiredValueInMapping)
|
storageKey := utils.GetStorageKeyForMapping(indexOfMappingOnContract, keyForDesiredValueInMapping)
|
||||||
|
|
||||||
expectedStorageKey := common.HexToHash("0xee0c1b59a3856bafbfb8730e7694c4badc271eb5f01ce4a8d7a53d8a6499676f")
|
expectedStorageKey := common.HexToHash("0xee0c1b59a3856bafbfb8730e7694c4badc271eb5f01ce4a8d7a53d8a6499676f")
|
||||||
Expect(storageKey).To(Equal(expectedStorageKey))
|
Expect(storageKey).To(Equal(expectedStorageKey))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("GetNestedMapping", func() {
|
Describe("GetStorageKeyForNestedMapping", func() {
|
||||||
It("returns the storage key for a nested mapping when passed the mapping's index on the contract and the desired value's keys", func() {
|
It("returns the storage key for a nested mapping when passed the mapping's index on the contract and the desired value's keys", func() {
|
||||||
// ex. solidity:
|
// ex. solidity:
|
||||||
// mapping (bytes32 => uint) public amounts
|
// mapping (bytes32 => uint) public amounts
|
||||||
// mapping (address => mapping (uint => bytes32)) public addressNames
|
// mapping (address => mapping (uint => bytes32)) public addressNames
|
||||||
// to access addressNames, pass in the index of the mapping on the contract + the address and uint keys for the bytes32 val being looked up
|
// to access addressNames, pass in the index of the mapping on the contract + the address and uint keys for the bytes32 val being looked up
|
||||||
indexOfMappingOnContract := storage.IndexOne
|
indexOfMappingOnContract := utils.IndexOne
|
||||||
keyForOuterMapping := "1234567890abcdef"
|
keyForOuterMapping := "1234567890abcdef"
|
||||||
keyForInnerMapping := "123"
|
keyForInnerMapping := "123"
|
||||||
|
|
||||||
storageKey := storage.GetNestedMapping(indexOfMappingOnContract, keyForOuterMapping, keyForInnerMapping)
|
storageKey := utils.GetStorageKeyForNestedMapping(indexOfMappingOnContract, keyForOuterMapping, keyForInnerMapping)
|
||||||
|
|
||||||
expectedStorageKey := common.HexToHash("0x82113529f6cd61061d1a6f0de53f2bdd067a1addd3d2b46be50a99abfcdb1661")
|
expectedStorageKey := common.HexToHash("0x82113529f6cd61061d1a6f0de53f2bdd067a1addd3d2b46be50a99abfcdb1661")
|
||||||
Expect(storageKey).To(Equal(expectedStorageKey))
|
Expect(storageKey).To(Equal(expectedStorageKey))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("GetIncrementedKey", func() {
|
Describe("GetIncrementedStorageKey", func() {
|
||||||
It("returns the storage key for later values sharing an index on the contract with other earlier values", func() {
|
It("returns the storage key for later values sharing an index on the contract with other earlier values", func() {
|
||||||
// ex. solidity:
|
// ex. solidity:
|
||||||
// mapping (bytes32 => uint) public amounts
|
// mapping (bytes32 => uint) public amounts
|
||||||
@@ -62,11 +78,11 @@ var _ = Describe("Mappings", func() {
|
|||||||
// mapping (bytes32 => Data) public itemData;
|
// mapping (bytes32 => Data) public itemData;
|
||||||
// to access quality from itemData, pass in the storage key for the zero-indexed value (quantity) + the number of increments required.
|
// to access quality from itemData, pass in the storage key for the zero-indexed value (quantity) + the number of increments required.
|
||||||
// (For "quality", we must increment the storage key for the corresponding "quantity" by 1).
|
// (For "quality", we must increment the storage key for the corresponding "quantity" by 1).
|
||||||
indexOfMappingOnContract := storage.IndexTwo
|
indexOfMappingOnContract := utils.IndexTwo
|
||||||
keyForDesiredValueInMapping := "1234567890abcdef"
|
keyForDesiredValueInMapping := "1234567890abcdef"
|
||||||
storageKeyForFirstPropertyOnStruct := storage.GetMapping(indexOfMappingOnContract, keyForDesiredValueInMapping)
|
storageKeyForFirstPropertyOnStruct := utils.GetStorageKeyForMapping(indexOfMappingOnContract, keyForDesiredValueInMapping)
|
||||||
|
|
||||||
storageKey := storage.GetIncrementedKey(storageKeyForFirstPropertyOnStruct, 1)
|
storageKey := utils.GetIncrementedStorageKey(storageKeyForFirstPropertyOnStruct, 1)
|
||||||
|
|
||||||
expectedStorageKey := common.HexToHash("0x69b38749f0a8ed5d505c8474f7fb62c7828aad8a7627f1c67e07af1d2368cad4")
|
expectedStorageKey := common.HexToHash("0x69b38749f0a8ed5d505c8474f7fb62c7828aad8a7627f1c67e07af1d2368cad4")
|
||||||
Expect(storageKey).To(Equal(expectedStorageKey))
|
Expect(storageKey).To(Equal(expectedStorageKey))
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddHashedKeys(currentMappings map[common.Hash]StorageValueMetadata) map[common.Hash]StorageValueMetadata {
|
||||||
|
copyOfCurrentMappings := make(map[common.Hash]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())
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// 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 keys lookup utils", 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 := utils.AddHashedKeys(fakeMap)
|
||||||
|
|
||||||
|
Expect(len(result)).To(Equal(2))
|
||||||
|
expectedHashedStorageKey := common.HexToHash("2165edb4e1c37b99b60fa510d84f939dd35d5cd1d1c8f299d6456ea09df65a76")
|
||||||
|
Expect(fakeMap[fakeStorageKey]).To(Equal(fakeMetadata))
|
||||||
|
Expect(fakeMap[expectedHashedStorageKey]).To(Equal(fakeMetadata))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -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/factories/event"
|
||||||
|
"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 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 GenericModel = event.InsertionModel{}
|
||||||
|
|
||||||
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))]
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user