forked from cerc-io/ipld-eth-server
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7a2e85d67 |
@@ -14,5 +14,3 @@ postgraphile/package-lock.json
|
|||||||
vulcanizedb.log
|
vulcanizedb.log
|
||||||
db/migrations/20*.sql
|
db/migrations/20*.sql
|
||||||
plugins/*.so
|
plugins/*.so
|
||||||
postgraphile/*.toml
|
|
||||||
postgraphile/schema.graphql
|
|
||||||
|
|||||||
+8
-5
@@ -1,24 +1,27 @@
|
|||||||
dist: trusty
|
dist: trusty
|
||||||
language: go
|
language: go
|
||||||
go:
|
go:
|
||||||
- 1.12
|
- 1.11
|
||||||
services:
|
services:
|
||||||
- postgresql
|
- postgresql
|
||||||
addons:
|
addons:
|
||||||
postgresql: '11.2'
|
postgresql: '9.6'
|
||||||
go_import_path: github.com/vulcanize/vulcanizedb
|
go_import_path: github.com/vulcanize/vulcanizedb
|
||||||
before_install:
|
before_install:
|
||||||
- make installtools
|
- make installtools
|
||||||
- bash ./scripts/install-postgres-11.sh
|
- bash ./scripts/install-postgres-10.sh
|
||||||
- curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
- curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||||
- echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
|
- echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
|
||||||
- sudo apt-get update && sudo apt-get install yarn
|
- sudo apt-get update && sudo apt-get install yarn
|
||||||
before_script:
|
before_script:
|
||||||
- sudo -u postgres createdb vulcanize_private
|
- sudo -u postgres createdb vulcanize_private
|
||||||
- make migrate NAME=vulcanize_private
|
- make migrate NAME=vulcanize_private
|
||||||
|
- cd postgraphile && yarn
|
||||||
script:
|
script:
|
||||||
- env GO111MODULE=on make test
|
- yarn test
|
||||||
- env GO111MODULE=on make integrationtest
|
- cd ../
|
||||||
|
- make test
|
||||||
|
- make integrationtest
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
env:
|
env:
|
||||||
|
|||||||
Generated
+564
@@ -0,0 +1,564 @@
|
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:48a213e9dc4880bbbd6999309a476fa4d3cc67560aa7127154cf8ea95bd464c2"
|
||||||
|
name = "github.com/allegro/bigcache"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"queue",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "f31987a23e44c5121ef8c8b2f2ea2e8ffa37b068"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:a313376bcbcce8ae8bddb8089a7293e0473a0f8e9e3710d6244e09e81875ccf0"
|
||||||
|
name = "github.com/aristanetworks/goarista"
|
||||||
|
packages = ["monotime"]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "ff33da284e760fcdb03c33d37a719e5ed30ba844"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:c6bf1ac7bbc0fe51637bf54d5a88ff79b171b3b42dbc665dec98303c862d8662"
|
||||||
|
name = "github.com/btcsuite/btcd"
|
||||||
|
packages = ["btcec"]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:5d47691333460db6ac83ced03c79b4bdb9aff3e322be24affb7855bed8affc6c"
|
||||||
|
name = "github.com/dave/jennifer"
|
||||||
|
packages = ["jen"]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "14e399b6b5e8456c66c45c955fc27b568bacb5c9"
|
||||||
|
version = "v1.3.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:aaeffbff5bd24654cb4c190ed75d6c7b57b4f5d6741914c1a7a6bb7447e756c5"
|
||||||
|
name = "github.com/deckarep/golang-set"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "cbaa98ba5575e67703b32b4b19f73c91f3c4159e"
|
||||||
|
version = "v1.7.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:90d36f5b581e95e00ced808cd48824ed6c320c25887828cce461bdef4cb7bc7c"
|
||||||
|
name = "github.com/ethereum/go-ethereum"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"accounts",
|
||||||
|
"accounts/abi",
|
||||||
|
"accounts/abi/bind",
|
||||||
|
"accounts/keystore",
|
||||||
|
"common",
|
||||||
|
"common/bitutil",
|
||||||
|
"common/hexutil",
|
||||||
|
"common/math",
|
||||||
|
"common/mclock",
|
||||||
|
"common/prque",
|
||||||
|
"core/rawdb",
|
||||||
|
"core/types",
|
||||||
|
"crypto",
|
||||||
|
"crypto/ecies",
|
||||||
|
"crypto/secp256k1",
|
||||||
|
"ethclient",
|
||||||
|
"ethdb",
|
||||||
|
"ethdb/leveldb",
|
||||||
|
"ethdb/memorydb",
|
||||||
|
"event",
|
||||||
|
"log",
|
||||||
|
"metrics",
|
||||||
|
"p2p",
|
||||||
|
"p2p/discover",
|
||||||
|
"p2p/discv5",
|
||||||
|
"p2p/enode",
|
||||||
|
"p2p/enr",
|
||||||
|
"p2p/nat",
|
||||||
|
"p2p/netutil",
|
||||||
|
"params",
|
||||||
|
"rlp",
|
||||||
|
"rpc",
|
||||||
|
"trie",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "cd79bc61a983d6482579d12cdd239b37bbfa12ef"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd"
|
||||||
|
name = "github.com/fsnotify/fsnotify"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||||
|
version = "v1.4.7"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:a01080d20c45c031c13f3828c56e58f4f51d926a482ad10cc0316225097eb7ea"
|
||||||
|
name = "github.com/go-stack/stack"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a"
|
||||||
|
version = "v1.8.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18"
|
||||||
|
name = "github.com/golang/protobuf"
|
||||||
|
packages = ["proto"]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||||
|
version = "v1.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:2a5888946cdbc8aa360fd43301f9fc7869d663f60d5eedae7d4e6e5e4f06f2bf"
|
||||||
|
name = "github.com/golang/snappy"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:5247b135b5492aa232a731acdcb52b08f32b874cb398f21ab460396eadbe866b"
|
||||||
|
name = "github.com/google/uuid"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:9c776d7d9c54b7ed89f119e449983c3f24c0023e75001d6092442412ebca6b94"
|
||||||
|
name = "github.com/hashicorp/golang-lru"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"simplelru",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:d14365c51dd1d34d5c79833ec91413bfbb166be978724f15701e17080dc06dec"
|
||||||
|
name = "github.com/hashicorp/hcl"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"hcl/ast",
|
||||||
|
"hcl/parser",
|
||||||
|
"hcl/printer",
|
||||||
|
"hcl/scanner",
|
||||||
|
"hcl/strconv",
|
||||||
|
"hcl/token",
|
||||||
|
"json/parser",
|
||||||
|
"json/scanner",
|
||||||
|
"json/token",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:b3c5b95e56c06f5aa72cb2500e6ee5f44fcd122872d4fec2023a488e561218bc"
|
||||||
|
name = "github.com/hpcloud/tail"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"ratelimiter",
|
||||||
|
"util",
|
||||||
|
"watch",
|
||||||
|
"winfile",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "a30252cb686a21eb2d0b98132633053ec2f7f1e5"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:b6e4cc26365c004808649862e22069de09594a9222143399a7a04904e9f7018c"
|
||||||
|
name = "github.com/huin/goupnp"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"dcps/internetgateway1",
|
||||||
|
"dcps/internetgateway2",
|
||||||
|
"httpu",
|
||||||
|
"scpd",
|
||||||
|
"soap",
|
||||||
|
"ssdp",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "1395d1447324cbea88d249fbfcfd70ea878fdfca"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||||
|
name = "github.com/inconshreveable/mousetrap"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||||
|
version = "v1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:76f836364ae83ed811c415aa92e1209ce49de9f62aad85b85fca749a8b96a110"
|
||||||
|
name = "github.com/jackpal/go-nat-pmp"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "c9cfead9f2a36ddf3daa40ba269aa7f4bbba6b62"
|
||||||
|
version = "v1.0.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:617ee2434b77e911fa26b678730be9a617f75243b194eadc8201c8ac860844aa"
|
||||||
|
name = "github.com/jmoiron/sqlx"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"reflectx",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:6a874e3ddfb9db2b42bd8c85b6875407c702fa868eed20634ff489bc896ccfd3"
|
||||||
|
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
|
||||||
|
version = "v1.0.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:29145d7af4adafd72a79df5e41456ac9e232d5a28c1cd4dacf3ff008a217fc10"
|
||||||
|
name = "github.com/lib/pq"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"oid",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:961dc3b1d11f969370533390fdf203813162980c858e1dabe827b60940c909a5"
|
||||||
|
name = "github.com/magiconair/properties"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
||||||
|
version = "v1.8.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:096a8a9182648da3d00ff243b88407838902b6703fc12657f76890e08d1899bf"
|
||||||
|
name = "github.com/mitchellh/go-homedir"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:5219b4506253ccc598f9340677162a42d6a78f340a4cc6df2d62db4d0593c4e9"
|
||||||
|
name = "github.com/mitchellh/mapstructure"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:a7fd918fb5bd2188436785c0424f8a50b4addfedf37a2b14d796be2a927b8007"
|
||||||
|
name = "github.com/onsi/ginkgo"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"config",
|
||||||
|
"internal/codelocation",
|
||||||
|
"internal/containernode",
|
||||||
|
"internal/failer",
|
||||||
|
"internal/leafnodes",
|
||||||
|
"internal/remote",
|
||||||
|
"internal/spec",
|
||||||
|
"internal/spec_iterator",
|
||||||
|
"internal/specrunner",
|
||||||
|
"internal/suite",
|
||||||
|
"internal/testingtproxy",
|
||||||
|
"internal/writer",
|
||||||
|
"reporters",
|
||||||
|
"reporters/stenographer",
|
||||||
|
"reporters/stenographer/support/go-colorable",
|
||||||
|
"reporters/stenographer/support/go-isatty",
|
||||||
|
"types",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "3774a09d95489ccaa16032e0770d08ea77ba6184"
|
||||||
|
version = "v1.6.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:3ecd0a37c4a90c12a97e31c398cdbc173824351aa891898ee178120bfe71c478"
|
||||||
|
name = "github.com/onsi/gomega"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"format",
|
||||||
|
"ghttp",
|
||||||
|
"internal/assertion",
|
||||||
|
"internal/asyncassertion",
|
||||||
|
"internal/oraclematcher",
|
||||||
|
"internal/testingtsupport",
|
||||||
|
"matchers",
|
||||||
|
"matchers/support/goraph/bipartitegraph",
|
||||||
|
"matchers/support/goraph/edge",
|
||||||
|
"matchers/support/goraph/node",
|
||||||
|
"matchers/support/goraph/util",
|
||||||
|
"types",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "7615b9433f86a8bdf29709bf288bc4fd0636a369"
|
||||||
|
version = "v1.4.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:a5484d4fa43127138ae6e7b2299a6a52ae006c7f803d98d717f60abf3e97192e"
|
||||||
|
name = "github.com/pborman/uuid"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
|
||||||
|
version = "v1.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:894aef961c056b6d85d12bac890bf60c44e99b46292888bfa66caf529f804457"
|
||||||
|
name = "github.com/pelletier/go-toml"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
||||||
|
version = "v1.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:7143292549152d009ca9e9c493b74736a2ebd93f921bea8a4b308d7cc5edc6b3"
|
||||||
|
name = "github.com/rjeczalik/notify"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8"
|
||||||
|
version = "v0.9.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:78c9cf43ddeacd0e472f412082227a0fac2ae107ee60e9112156f9371f9912cf"
|
||||||
|
name = "github.com/rs/cors"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f"
|
||||||
|
version = "v1.5.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:9d57e200ef5ccc4217fe0a34287308bac652435e7c6513f6263e0493d2245c56"
|
||||||
|
name = "github.com/sirupsen/logrus"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
|
||||||
|
version = "v1.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:d0431c2fd72e39ee43ea7742322abbc200c3e704c9102c5c3c2e2e667095b0ca"
|
||||||
|
name = "github.com/spf13/afero"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"mem",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd"
|
||||||
|
version = "v1.1.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:d0b38ba6da419a6d4380700218eeec8623841d44a856bb57369c172fbf692ab4"
|
||||||
|
name = "github.com/spf13/cast"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||||
|
version = "v1.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6"
|
||||||
|
name = "github.com/spf13/cobra"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||||
|
version = "v0.0.3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:9ceffa4ab5f7195ecf18b3a7fff90c837a9ed5e22e66d18069e4bccfe1f52aa0"
|
||||||
|
name = "github.com/spf13/jwalterweatherman"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "4a4406e478ca629068e7768fc33f3f044173c0a6"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:0a52bcb568386d98f4894575d53ce3e456f56471de6897bb8b9de13c33d9340e"
|
||||||
|
name = "github.com/spf13/pflag"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
||||||
|
version = "v1.0.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:ac25ea6cc1156aca9611411274b4a0bdd83a623845df6985aab508253955cc66"
|
||||||
|
name = "github.com/spf13/viper"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "8fb642006536c8d3760c99d4fa2389f5e2205631"
|
||||||
|
version = "v1.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:ce5194e5afac308cc34e500cab45b4ce88a0742d689e3cf7e37b607ad76bed2f"
|
||||||
|
name = "github.com/syndtr/goleveldb"
|
||||||
|
packages = [
|
||||||
|
"leveldb",
|
||||||
|
"leveldb/cache",
|
||||||
|
"leveldb/comparer",
|
||||||
|
"leveldb/errors",
|
||||||
|
"leveldb/filter",
|
||||||
|
"leveldb/iterator",
|
||||||
|
"leveldb/journal",
|
||||||
|
"leveldb/memdb",
|
||||||
|
"leveldb/opt",
|
||||||
|
"leveldb/storage",
|
||||||
|
"leveldb/table",
|
||||||
|
"leveldb/util",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:59b49c47c11a48f1054529207f65907c014ecf5f9a7c0d9c0f1616dec7b062ed"
|
||||||
|
name = "golang.org/x/crypto"
|
||||||
|
packages = [
|
||||||
|
"pbkdf2",
|
||||||
|
"scrypt",
|
||||||
|
"sha3",
|
||||||
|
"ssh/terminal",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:fbdbb6cf8db3278412c9425ad78b26bb8eb788181f26a3ffb3e4f216b314f86a"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
packages = [
|
||||||
|
"context",
|
||||||
|
"html",
|
||||||
|
"html/atom",
|
||||||
|
"html/charset",
|
||||||
|
"websocket",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
|
||||||
|
name = "golang.org/x/sync"
|
||||||
|
packages = ["errgroup"]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:70d519d5cddeb60ceda2db88c24c340b1b2d7efb25ab54bacb38f57ea1998df7"
|
||||||
|
name = "golang.org/x/sys"
|
||||||
|
packages = [
|
||||||
|
"unix",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "d641721ec2dead6fe5ca284096fe4b1fcd49e427"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
|
||||||
|
name = "golang.org/x/text"
|
||||||
|
packages = [
|
||||||
|
"encoding",
|
||||||
|
"encoding/charmap",
|
||||||
|
"encoding/htmlindex",
|
||||||
|
"encoding/internal",
|
||||||
|
"encoding/internal/identifier",
|
||||||
|
"encoding/japanese",
|
||||||
|
"encoding/korean",
|
||||||
|
"encoding/simplifiedchinese",
|
||||||
|
"encoding/traditionalchinese",
|
||||||
|
"encoding/unicode",
|
||||||
|
"internal/gen",
|
||||||
|
"internal/tag",
|
||||||
|
"internal/triegen",
|
||||||
|
"internal/ucd",
|
||||||
|
"internal/utf8internal",
|
||||||
|
"language",
|
||||||
|
"runes",
|
||||||
|
"transform",
|
||||||
|
"unicode/cldr",
|
||||||
|
"unicode/norm",
|
||||||
|
]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||||
|
version = "v0.3.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd"
|
||||||
|
name = "gopkg.in/fsnotify.v1"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||||
|
source = "gopkg.in/fsnotify/fsnotify.v1"
|
||||||
|
version = "v1.4.7"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
|
digest = "1:4f830ee018eb8c56d0def653ad7c9a1d2a053f0cef2ac6b2200f73b98fa6a681"
|
||||||
|
name = "gopkg.in/natefinch/npipe.v2"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v1"
|
||||||
|
digest = "1:a96d16bd088460f2e0685d46c39bcf1208ba46e0a977be2df49864ec7da447dd"
|
||||||
|
name = "gopkg.in/tomb.v1"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "dd632973f1e7218eb1089048e0798ec9ae7dceb8"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
|
||||||
|
name = "gopkg.in/yaml.v2"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = ""
|
||||||
|
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||||
|
version = "v2.2.1"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
input-imports = [
|
||||||
|
"github.com/dave/jennifer/jen",
|
||||||
|
"github.com/ethereum/go-ethereum",
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi",
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind",
|
||||||
|
"github.com/ethereum/go-ethereum/common",
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil",
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb",
|
||||||
|
"github.com/ethereum/go-ethereum/core/types",
|
||||||
|
"github.com/ethereum/go-ethereum/crypto",
|
||||||
|
"github.com/ethereum/go-ethereum/ethclient",
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb",
|
||||||
|
"github.com/ethereum/go-ethereum/p2p",
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5",
|
||||||
|
"github.com/ethereum/go-ethereum/params",
|
||||||
|
"github.com/ethereum/go-ethereum/rlp",
|
||||||
|
"github.com/ethereum/go-ethereum/rpc",
|
||||||
|
"github.com/hashicorp/golang-lru",
|
||||||
|
"github.com/hpcloud/tail",
|
||||||
|
"github.com/jmoiron/sqlx",
|
||||||
|
"github.com/lib/pq",
|
||||||
|
"github.com/mitchellh/go-homedir",
|
||||||
|
"github.com/onsi/ginkgo",
|
||||||
|
"github.com/onsi/gomega",
|
||||||
|
"github.com/onsi/gomega/ghttp",
|
||||||
|
"github.com/sirupsen/logrus",
|
||||||
|
"github.com/spf13/cobra",
|
||||||
|
"github.com/spf13/viper",
|
||||||
|
"golang.org/x/net/context",
|
||||||
|
"golang.org/x/sync/errgroup",
|
||||||
|
"gopkg.in/tomb.v1",
|
||||||
|
]
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
# Gopkg.toml example
|
||||||
|
#
|
||||||
|
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
|
||||||
|
|
||||||
|
[[override]]
|
||||||
|
name = "gopkg.in/fsnotify.v1"
|
||||||
|
source = "gopkg.in/fsnotify/fsnotify.v1"
|
||||||
|
|
||||||
|
[[override]]
|
||||||
|
name = "github.com/pressly/sup"
|
||||||
|
version = "0.5.3"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/onsi/ginkgo"
|
||||||
|
version = "1.4.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/lib/pq"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/sirupsen/logrus"
|
||||||
|
version = "1.2.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/spf13/cobra"
|
||||||
|
version = "0.0.1"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/ethereum/go-ethereum"
|
||||||
|
revision = "cd79bc61a983d6482579d12cdd239b37bbfa12ef"
|
||||||
@@ -3,6 +3,11 @@ BASE = $(GOPATH)/src/$(PACKAGE)
|
|||||||
PKGS = go list ./... | grep -v "^vendor/"
|
PKGS = go list ./... | grep -v "^vendor/"
|
||||||
|
|
||||||
# Tools
|
# Tools
|
||||||
|
## Dependency management
|
||||||
|
DEP = $(BIN)/dep
|
||||||
|
$(BIN)/dep:
|
||||||
|
go get -u github.com/golang/dep/cmd/dep
|
||||||
|
|
||||||
## Testing library
|
## Testing library
|
||||||
GINKGO = $(BIN)/ginkgo
|
GINKGO = $(BIN)/ginkgo
|
||||||
$(BIN)/ginkgo:
|
$(BIN)/ginkgo:
|
||||||
@@ -27,7 +32,7 @@ $(BIN)/gometalinter.v2:
|
|||||||
|
|
||||||
|
|
||||||
.PHONY: installtools
|
.PHONY: installtools
|
||||||
installtools: | $(LINT) $(GOOSE) $(GINKGO)
|
installtools: | $(LINT) $(GOOSE) $(GINKGO) $(DEP)
|
||||||
echo "Installing tools"
|
echo "Installing tools"
|
||||||
|
|
||||||
.PHONY: metalint
|
.PHONY: metalint
|
||||||
@@ -53,7 +58,11 @@ integrationtest: | $(GINKGO) $(LINT)
|
|||||||
go fmt ./...
|
go fmt ./...
|
||||||
$(GINKGO) -r integration_test/
|
$(GINKGO) -r integration_test/
|
||||||
|
|
||||||
build:
|
.PHONY: dep
|
||||||
|
dep: | $(DEP)
|
||||||
|
$(DEP) ensure
|
||||||
|
|
||||||
|
build: dep
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
go build
|
go build
|
||||||
|
|
||||||
@@ -61,8 +70,7 @@ build:
|
|||||||
HOST_NAME = localhost
|
HOST_NAME = localhost
|
||||||
PORT = 5432
|
PORT = 5432
|
||||||
NAME =
|
NAME =
|
||||||
USER = postgres
|
CONNECT_STRING=postgresql://$(HOST_NAME):$(PORT)/$(NAME)?sslmode=disable
|
||||||
CONNECT_STRING=postgresql://$(USER)@$(HOST_NAME):$(PORT)/$(NAME)?sslmode=disable
|
|
||||||
|
|
||||||
# Parameter checks
|
# Parameter checks
|
||||||
## Check that DB variables are provided
|
## Check that DB variables are provided
|
||||||
@@ -71,7 +79,6 @@ checkdbvars:
|
|||||||
test -n "$(HOST_NAME)" # $$HOST_NAME
|
test -n "$(HOST_NAME)" # $$HOST_NAME
|
||||||
test -n "$(PORT)" # $$PORT
|
test -n "$(PORT)" # $$PORT
|
||||||
test -n "$(NAME)" # $$NAME
|
test -n "$(NAME)" # $$NAME
|
||||||
test -n "$(USER)" # $$USER
|
|
||||||
@echo $(CONNECT_STRING)
|
@echo $(CONNECT_STRING)
|
||||||
|
|
||||||
## Check that the migration variable (id/timestamp) is provided
|
## Check that the migration variable (id/timestamp) is provided
|
||||||
|
|||||||
@@ -7,56 +7,49 @@
|
|||||||
|
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
1. [Background](#background)
|
1. [Background](../staging/README.md#background)
|
||||||
1. [Install](#install)
|
1. [Dependencies](../staging/README.md#dependencies)
|
||||||
1. [Usage](#usage)
|
1. [Install](../staging/README.md#install)
|
||||||
1. [Contributing](#contributing)
|
1. [Usage](../staging/README.md#usage)
|
||||||
1. [License](#license)
|
1. [Tests](../staging/README.md#tests)
|
||||||
|
1. [API](../staging/README.md#API)
|
||||||
|
1. [Contributing](../staging/README.md#contributing)
|
||||||
|
1. [License](../staging/README.md#license)
|
||||||
|
|
||||||
|
|
||||||
## Background
|
## Background
|
||||||
The same data structures and encodings that make Ethereum an effective and trust-less distributed virtual machine
|
The same data structures and encodings that make Ethereum an effective and trust-less distributed virtual machine
|
||||||
complicate data accessibility and usability for dApp developers. VulcanizeDB improves Ethereum data accessibility by
|
complicate data accessibility and usability for dApp developers.
|
||||||
providing a suite of tools to ease the extraction and transformation of data into a more useful state, including
|
|
||||||
allowing for exposing aggregate data from a suite of smart contracts.
|
|
||||||
|
|
||||||
VulanizeDB includes processes that sync, transform and expose data. Syncing involves
|
|
||||||
querying an Ethereum node and then persisting core data into a Postgres database. Transforming focuses on using previously synced data to
|
|
||||||
query for and transform log event and storage data for specifically configured smart contract addresses. Exposing data is a matter of getting
|
|
||||||
data from VulcanizeDB's underlying Postgres database and making it accessible.
|
|
||||||
|
|
||||||

|
## Dependencies
|
||||||
|
- Go 1.11+
|
||||||
## Install
|
- Postgres 10.6
|
||||||
|
|
||||||
1. [Dependencies](#dependencies)
|
|
||||||
1. [Building the project](#building-the-project)
|
|
||||||
1. [Setting up the database](#setting-up-the-database)
|
|
||||||
1. [Configuring a synced Ethereum node](#configuring-a-synced-ethereum-node)
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
- Go 1.12+
|
|
||||||
- Postgres 11.2
|
|
||||||
- Ethereum Node
|
- Ethereum Node
|
||||||
- [Go Ethereum](https://ethereum.github.io/go-ethereum/downloads/) (1.8.23+)
|
- [Go Ethereum](https://ethereum.github.io/go-ethereum/downloads/) (1.8.23+)
|
||||||
- [Parity 1.8.11+](https://github.com/paritytech/parity/releases)
|
- [Parity 1.8.11+](https://github.com/paritytech/parity/releases)
|
||||||
|
|
||||||
|
|
||||||
|
## Install
|
||||||
|
1. [Building the project](../staging/README.md#building-the-project)
|
||||||
|
1. [Setting up the database](../staging/README.md#setting-up-the-database)
|
||||||
|
1. [Configuring a synced Ethereum node](../staging/README.md#configuring-a-synced-ethereum-node)
|
||||||
|
|
||||||
### Building the project
|
### Building the project
|
||||||
Download the codebase to your local `GOPATH` via:
|
Download the codebase to your local `GOPATH` via:
|
||||||
|
|
||||||
`go get github.com/vulcanize/vulcanizedb`
|
`go get github.com/vulcanize/vulcanizedb`
|
||||||
|
|
||||||
Move to the project directory:
|
Move to the project directory and use [golang/dep](https://github.com/golang/dep) to install the dependencies:
|
||||||
|
|
||||||
`cd $GOPATH/src/github.com/vulcanize/vulcanizedb`
|
`cd $GOPATH/src/github.com/vulcanize/vulcanizedb`
|
||||||
|
|
||||||
Be sure you have enabled Go Modules (`export GO111MODULE=on`), and build the executable with:
|
`dep ensure`
|
||||||
|
|
||||||
|
Once the dependencies have been successfully installed, build the executable with:
|
||||||
|
|
||||||
`make build`
|
`make build`
|
||||||
|
|
||||||
If you need to use a different dependency than what is currently defined in `go.mod`, it may helpful to look into [the replace directive](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive).
|
|
||||||
This instruction enables you to point at a fork or the local filesystem for dependency resolution.
|
|
||||||
|
|
||||||
If you are running into issues at this stage, ensure that `GOPATH` is defined in your shell.
|
If you are running into issues at this stage, ensure that `GOPATH` is defined in your shell.
|
||||||
If necessary, `GOPATH` can be set in `~/.bashrc` or `~/.bash_profile`, depending upon your system.
|
If necessary, `GOPATH` can be set in `~/.bashrc` or `~/.bash_profile`, depending upon your system.
|
||||||
It can be additionally helpful to add `$GOPATH/bin` to your shell's `$PATH`.
|
It can be additionally helpful to add `$GOPATH/bin` to your shell's `$PATH`.
|
||||||
@@ -67,15 +60,13 @@ It can be additionally helpful to add `$GOPATH/bin` to your shell's `$PATH`.
|
|||||||
1. `createdb vulcanize_public`
|
1. `createdb vulcanize_public`
|
||||||
1. `cd $GOPATH/src/github.com/vulcanize/vulcanizedb`
|
1. `cd $GOPATH/src/github.com/vulcanize/vulcanizedb`
|
||||||
1. Run the migrations: `make migrate HOST_NAME=localhost NAME=vulcanize_public PORT=5432`
|
1. Run the migrations: `make migrate HOST_NAME=localhost NAME=vulcanize_public PORT=5432`
|
||||||
- There is an optional var `USER=username` if the database user is not the default user `postgres`
|
|
||||||
- To rollback a single step: `make rollback NAME=vulcanize_public`
|
- To rollback a single step: `make rollback NAME=vulcanize_public`
|
||||||
- To rollback to a certain migration: `make rollback_to MIGRATION=n NAME=vulcanize_public`
|
- To rollback to a certain migration: `make rollback_to MIGRATION=n NAME=vulcanize_public`
|
||||||
- To see status of migrations: `make migration_status NAME=vulcanize_public`
|
- To see status of migrations: `make migration_status NAME=vulcanize_public`
|
||||||
|
|
||||||
* See below for configuring additional environments
|
* See below for configuring additional environments
|
||||||
|
|
||||||
In some cases (such as recent Ubuntu systems), it may be necessary to overcome failures of password authentication from
|
In some cases (such as recent Ubuntu systems), it may be necessary to overcome failures of password authentication from localhost. To allow access on Ubuntu, set localhost connections via hostname, ipv4, and ipv6 from peer/md5 to trust in: /etc/postgresql/<version>/pg_hba.conf
|
||||||
localhost. To allow access on Ubuntu, set localhost connections via hostname, ipv4, and ipv6 from peer/md5 to trust in: /etc/postgresql/<version>/pg_hba.conf
|
|
||||||
|
|
||||||
(It should be noted that trusted auth should only be enabled on systems without sensitive data in them: development and local test databases)
|
(It should be noted that trusted auth should only be enabled on systems without sensitive data in them: development and local test databases)
|
||||||
|
|
||||||
@@ -87,9 +78,8 @@ localhost. To allow access on Ubuntu, set localhost connections via hostname, ip
|
|||||||
- The IPC file is called `geth.ipc`.
|
- The IPC file is called `geth.ipc`.
|
||||||
- The geth IPC file path is printed to the console when you start geth.
|
- The geth IPC file path is printed to the console when you start geth.
|
||||||
- The default location is:
|
- The default location is:
|
||||||
- Mac: `<full home path>/Library/Ethereum/geth.ipc`
|
- Mac: `<full home path>/Library/Ethereum`
|
||||||
- Linux: `<full home path>/ethereum/geth.ipc`
|
- Linux: `<full home path>/ethereum/geth.ipc`
|
||||||
- Note: the geth.ipc file may not exist until you've started the geth process
|
|
||||||
|
|
||||||
- For Parity:
|
- For Parity:
|
||||||
- The IPC file is called `jsonrpc.ipc`.
|
- The IPC file is called `jsonrpc.ipc`.
|
||||||
@@ -106,35 +96,23 @@ localhost. To allow access on Ubuntu, set localhost connections via hostname, ip
|
|||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
As mentioned above, VulcanizeDB's processes can be split into three categories: syncing, transforming and exposing data.
|
Usage is broken up into two processes:
|
||||||
|
|
||||||
### Data syncing
|
### Data syncing
|
||||||
To provide data for transformations, raw Ethereum data must first be synced into VulcanizeDB.
|
To provide data for transformations, raw Ethereum data must first be synced into vDB.
|
||||||
This is accomplished through the use of the `headerSync`, `fullSync`, or `coldImport` commands.
|
This is accomplished through the use of the `lightSync`, `sync`, or `coldImport` commands.
|
||||||
These commands are described in detail [here](documentation/data-syncing.md).
|
These commands are described in detail [here](../staging/documentation/sync.md).
|
||||||
|
|
||||||
### Data transformation
|
### Data transformation
|
||||||
Data transformation uses the raw data that has been synced into Postgres to filter out and apply transformations to
|
Contract watchers use the raw data that has been synced into Postgres to filter out and apply transformations to specific data of interest.
|
||||||
specific data of interest. Since there are different types of data that may be useful for observing smart contracts, it
|
|
||||||
follows that there are different ways to transform this data. We've started by categorizing this into Generic and
|
|
||||||
Custom transformers:
|
|
||||||
|
|
||||||
- Generic Contract Transformer: Generic contract transformation can be done using a built-in command,
|
There is a built-in `contractWatcher` command which provides generic transformation of most contract data. This command is described in detail [here](../staging/documentation/contractWatcher.md).
|
||||||
`contractWatcher`, which transforms contract events provided the contract's ABI is available. It also
|
|
||||||
provides some state variable coverage by automating polling of public methods, with some restrictions.
|
|
||||||
`contractWatcher` is described further [here](documentation/generic-transformer.md).
|
|
||||||
|
|
||||||
- Custom Transformers: In many cases custom transformers will need to be written to provide
|
In many cases a custom transformer or set of transformers will need to be written to provide complete or more comprehensive coverage or to optimize other aspects of the output for a specific end-use.
|
||||||
more comprehensive coverage of contract data. In this case we have provided the `compose`, `execute`, and
|
In this case we have provided the `compose`, `execute`, and `composeAndExecute` commands for running custom transformers from external repositories. This is described in detail [here](../staging/documentation/composeAndExecute.md).
|
||||||
`composeAndExecute` commands for running custom transformers from external repositories. Documentation on how to write,
|
|
||||||
build and run custom transformers as Go plugins can be found
|
|
||||||
[here](documentation/custom-transformers.md).
|
|
||||||
|
|
||||||
### Exposing the data
|
|
||||||
[Postgraphile](https://www.graphile.org/postgraphile/) is used to expose GraphQL endpoints for our database schemas, this is described in detail [here](documentation/postgraphile.md).
|
|
||||||
|
|
||||||
|
|
||||||
### Tests
|
## Tests
|
||||||
- Replace the empty `ipcPath` in the `environments/infura.toml` with a path to a full node's eth_jsonrpc endpoint (e.g. local geth node ipc path or infura url)
|
- Replace the empty `ipcPath` in the `environments/infura.toml` with a path to a full node's eth_jsonrpc endpoint (e.g. local geth node ipc path or infura url)
|
||||||
- Note: integration tests require configuration with an archival node
|
- Note: integration tests require configuration with an archival node
|
||||||
- `createdb vulcanize_private` will create the test db
|
- `createdb vulcanize_private` will create the test db
|
||||||
@@ -142,13 +120,15 @@ build and run custom transformers as Go plugins can be found
|
|||||||
- `make test` will run the unit tests and skip the integration tests
|
- `make test` will run the unit tests and skip the integration tests
|
||||||
- `make integrationtest` will run just the integration tests
|
- `make integrationtest` will run just the integration tests
|
||||||
|
|
||||||
|
## API
|
||||||
|
[Postgraphile](https://www.graphile.org/postgraphile/) is used to expose GraphQL endpoints for our database schemas, this is described in detail [here](../staging/postgraphile/README.md).
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Contributions are welcome!
|
Contributions are welcome! For more on this, please see [here](../staging/documentation/contributing.md).
|
||||||
|
|
||||||
VulcanizeDB follows the [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct).
|
Small note: If editing the Readme, please conform to the [standard-readme specification](https://github.com/RichardLitt/standard-readme).
|
||||||
|
|
||||||
For more information on contributing, please see [here](documentation/contributing.md).
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
[AGPL-3.0](LICENSE) © Vulcanize Inc
|
[AGPL-3.0](../staging/LICENSE) © Vulcanize Inc
|
||||||
+6
-8
@@ -39,8 +39,6 @@ var coldImportCmd = &cobra.Command{
|
|||||||
|
|
||||||
Geth must be synced over all of the desired blocks and must not be running in order to execute this command.`,
|
Geth must be synced over all of the desired blocks and must not be running in order to execute this command.`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
SubCommand = cmd.CalledAs()
|
|
||||||
LogWithCommand = *log.WithField("SubCommand", SubCommand)
|
|
||||||
coldImport()
|
coldImport()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -57,7 +55,7 @@ func coldImport() {
|
|||||||
ethDBConfig := ethereum.CreateDatabaseConfig(ethereum.Level, levelDbPath)
|
ethDBConfig := ethereum.CreateDatabaseConfig(ethereum.Level, levelDbPath)
|
||||||
ethDB, err := ethereum.CreateDatabase(ethDBConfig)
|
ethDB, err := ethereum.CreateDatabase(ethDBConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal("Error connecting to ethereum db: ", err)
|
log.Fatal("Error connecting to ethereum db: ", err)
|
||||||
}
|
}
|
||||||
mostRecentBlockNumberInDb := ethDB.GetHeadBlockNumber()
|
mostRecentBlockNumberInDb := ethDB.GetHeadBlockNumber()
|
||||||
if syncAll {
|
if syncAll {
|
||||||
@@ -65,10 +63,10 @@ func coldImport() {
|
|||||||
endingBlockNumber = mostRecentBlockNumberInDb
|
endingBlockNumber = mostRecentBlockNumberInDb
|
||||||
}
|
}
|
||||||
if endingBlockNumber < startingBlockNumber {
|
if endingBlockNumber < startingBlockNumber {
|
||||||
LogWithCommand.Fatal("Ending block number must be greater than starting block number for cold import.")
|
log.Fatal("Ending block number must be greater than starting block number for cold import.")
|
||||||
}
|
}
|
||||||
if endingBlockNumber > mostRecentBlockNumberInDb {
|
if endingBlockNumber > mostRecentBlockNumberInDb {
|
||||||
LogWithCommand.Fatal("Ending block number is greater than most recent block in db: ", mostRecentBlockNumberInDb)
|
log.Fatal("Ending block number is greater than most recent block in db: ", mostRecentBlockNumberInDb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// init pg db
|
// init pg db
|
||||||
@@ -78,13 +76,13 @@ func coldImport() {
|
|||||||
nodeBuilder := cold_import.NewColdImportNodeBuilder(reader, parser)
|
nodeBuilder := cold_import.NewColdImportNodeBuilder(reader, parser)
|
||||||
coldNode, err := nodeBuilder.GetNode(genesisBlock, levelDbPath)
|
coldNode, err := nodeBuilder.GetNode(genesisBlock, levelDbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal("Error getting node: ", err)
|
log.Fatal("Error getting node: ", err)
|
||||||
}
|
}
|
||||||
pgDB := utils.LoadPostgres(databaseConfig, coldNode)
|
pgDB := utils.LoadPostgres(databaseConfig, coldNode)
|
||||||
|
|
||||||
// init cold importer deps
|
// init cold importer deps
|
||||||
blockRepository := repositories.NewBlockRepository(&pgDB)
|
blockRepository := repositories.NewBlockRepository(&pgDB)
|
||||||
receiptRepository := repositories.FullSyncReceiptRepository{DB: &pgDB}
|
receiptRepository := repositories.ReceiptRepository{DB: &pgDB}
|
||||||
transactionConverter := cold_db.NewColdDbTransactionConverter()
|
transactionConverter := cold_db.NewColdDbTransactionConverter()
|
||||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||||
|
|
||||||
@@ -92,6 +90,6 @@ func coldImport() {
|
|||||||
coldImporter := cold_import.NewColdImporter(ethDB, blockRepository, receiptRepository, blockConverter)
|
coldImporter := cold_import.NewColdImporter(ethDB, blockRepository, receiptRepository, blockConverter)
|
||||||
err = coldImporter.Execute(startingBlockNumber, endingBlockNumber, coldNode.ID)
|
err = coldImporter.Execute(startingBlockNumber, endingBlockNumber, coldNode.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal("Error executing cold import: ", err)
|
log.Fatal("Error executing cold import: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-24
@@ -1,18 +1,17 @@
|
|||||||
// VulcanizeDB
|
// Copyright © 2019 Vulcanize, Inc
|
||||||
// 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
|
||||||
|
|
||||||
@@ -102,8 +101,6 @@ single config file or in separate command instances using different config files
|
|||||||
Specify config location when executing the command:
|
Specify config location when executing the command:
|
||||||
./vulcanizedb compose --config=./environments/config_name.toml`,
|
./vulcanizedb compose --config=./environments/config_name.toml`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
SubCommand = cmd.CalledAs()
|
|
||||||
LogWithCommand = *log.WithField("SubCommand", SubCommand)
|
|
||||||
compose()
|
compose()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -113,25 +110,23 @@ func compose() {
|
|||||||
prepConfig()
|
prepConfig()
|
||||||
|
|
||||||
// Generate code to build the plugin according to the config file
|
// Generate code to build the plugin according to the config file
|
||||||
LogWithCommand.Info("generating plugin")
|
log.Info("generating plugin")
|
||||||
generator, err := p2.NewGenerator(genConfig, databaseConfig)
|
generator, err := p2.NewGenerator(genConfig, databaseConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Debug("initializing plugin generator failed")
|
log.Fatal(err)
|
||||||
LogWithCommand.Fatal(err)
|
|
||||||
}
|
}
|
||||||
err = generator.GenerateExporterPlugin()
|
err = generator.GenerateExporterPlugin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Debug("generating plugin failed")
|
log.Debug("generating plugin failed")
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
// TODO: Embed versioning info in the .so files so we know which version of vulcanizedb to run them with
|
// TODO: Embed versioning info in the .so files so we know which version of vulcanizedb to run them with
|
||||||
_, pluginPath, err := genConfig.GetPluginPaths()
|
_, pluginPath, err := genConfig.GetPluginPaths()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Debug("getting plugin path failed")
|
log.Fatal(err)
|
||||||
LogWithCommand.Fatal(err)
|
|
||||||
}
|
}
|
||||||
fmt.Printf("Composed plugin %s", pluginPath)
|
fmt.Printf("Composed plugin %s", pluginPath)
|
||||||
LogWithCommand.Info("plugin .so file output to ", pluginPath)
|
log.Info("plugin .so file output to", pluginPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -139,38 +134,38 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func prepConfig() {
|
func prepConfig() {
|
||||||
LogWithCommand.Info("configuring plugin")
|
log.Info("configuring plugin")
|
||||||
names := viper.GetStringSlice("exporter.transformerNames")
|
names := viper.GetStringSlice("exporter.transformerNames")
|
||||||
transformers := make(map[string]config.Transformer)
|
transformers := make(map[string]config.Transformer)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
transformer := viper.GetStringMapString("exporter." + name)
|
transformer := viper.GetStringMapString("exporter." + name)
|
||||||
p, pOK := transformer["path"]
|
p, pOK := transformer["path"]
|
||||||
if !pOK || p == "" {
|
if !pOK || p == "" {
|
||||||
LogWithCommand.Fatal(name, " transformer config is missing `path` value")
|
log.Fatal(name, "transformer config is missing `path` value")
|
||||||
}
|
}
|
||||||
r, rOK := transformer["repository"]
|
r, rOK := transformer["repository"]
|
||||||
if !rOK || r == "" {
|
if !rOK || r == "" {
|
||||||
LogWithCommand.Fatal(name, " transformer config is missing `repository` value")
|
log.Fatal(name, "transformer config is missing `repository` value")
|
||||||
}
|
}
|
||||||
m, mOK := transformer["migrations"]
|
m, mOK := transformer["migrations"]
|
||||||
if !mOK || m == "" {
|
if !mOK || m == "" {
|
||||||
LogWithCommand.Fatal(name, " transformer config is missing `migrations` value")
|
log.Fatal(name, "transformer config is missing `migrations` value")
|
||||||
}
|
}
|
||||||
mr, mrOK := transformer["rank"]
|
mr, mrOK := transformer["rank"]
|
||||||
if !mrOK || mr == "" {
|
if !mrOK || mr == "" {
|
||||||
LogWithCommand.Fatal(name, " transformer config is missing `rank` value")
|
log.Fatal(name, "transformer config is missing `rank` value")
|
||||||
}
|
}
|
||||||
rank, err := strconv.ParseUint(mr, 10, 64)
|
rank, err := strconv.ParseUint(mr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal(name, " migration `rank` can't be converted to an unsigned integer")
|
log.Fatal(name, "migration `rank` can't be converted to an unsigned integer")
|
||||||
}
|
}
|
||||||
t, tOK := transformer["type"]
|
t, tOK := transformer["type"]
|
||||||
if !tOK {
|
if !tOK {
|
||||||
LogWithCommand.Fatal(name, " transformer config is missing `type` value")
|
log.Fatal(name, "transformer config is missing `type` value")
|
||||||
}
|
}
|
||||||
transformerType := config.GetTransformerType(t)
|
transformerType := config.GetTransformerType(t)
|
||||||
if transformerType == config.UnknownTransformerType {
|
if transformerType == config.UnknownTransformerType {
|
||||||
LogWithCommand.Fatal(errors.New(`unknown transformer type in exporter config accepted types are "eth_event", "eth_storage"`))
|
log.Fatal(errors.New(`unknown transformer type in exporter config accepted types are "eth_event", "eth_storage"`))
|
||||||
}
|
}
|
||||||
|
|
||||||
transformers[name] = config.Transformer{
|
transformers[name] = config.Transformer{
|
||||||
|
|||||||
+23
-35
@@ -1,36 +1,31 @@
|
|||||||
// VulcanizeDB
|
// Copyright © 2019 Vulcanize, Inc
|
||||||
// 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 (
|
||||||
"os"
|
|
||||||
"plugin"
|
|
||||||
syn "sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
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"
|
"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"
|
||||||
|
"os"
|
||||||
|
"plugin"
|
||||||
|
syn "sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// composeAndExecuteCmd represents the composeAndExecute command
|
// composeAndExecuteCmd represents the composeAndExecute command
|
||||||
@@ -106,8 +101,6 @@ single config file or in separate command instances using different config files
|
|||||||
Specify config location when executing the command:
|
Specify config location when executing the command:
|
||||||
./vulcanizedb composeAndExecute --config=./environments/config_name.toml`,
|
./vulcanizedb composeAndExecute --config=./environments/config_name.toml`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
SubCommand = cmd.CalledAs()
|
|
||||||
LogWithCommand = *log.WithField("SubCommand", SubCommand)
|
|
||||||
composeAndExecute()
|
composeAndExecute()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -117,44 +110,44 @@ func composeAndExecute() {
|
|||||||
prepConfig()
|
prepConfig()
|
||||||
|
|
||||||
// Generate code to build the plugin according to the config file
|
// Generate code to build the plugin according to the config file
|
||||||
LogWithCommand.Info("generating plugin")
|
log.Info("generating plugin")
|
||||||
generator, err := p2.NewGenerator(genConfig, databaseConfig)
|
generator, err := p2.NewGenerator(genConfig, databaseConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
err = generator.GenerateExporterPlugin()
|
err = generator.GenerateExporterPlugin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Debug("generating plugin failed")
|
log.Debug("generating plugin failed")
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the plugin path and load the plugin
|
// Get the plugin path and load the plugin
|
||||||
_, pluginPath, err := genConfig.GetPluginPaths()
|
_, pluginPath, err := genConfig.GetPluginPaths()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
if !genConfig.Save {
|
if !genConfig.Save {
|
||||||
defer helpers.ClearFiles(pluginPath)
|
defer helpers.ClearFiles(pluginPath)
|
||||||
}
|
}
|
||||||
LogWithCommand.Info("linking plugin ", pluginPath)
|
log.Info("linking plugin", pluginPath)
|
||||||
plug, err := plugin.Open(pluginPath)
|
plug, err := plugin.Open(pluginPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Debug("linking plugin failed")
|
log.Debug("linking plugin failed")
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the `Exporter` symbol from the plugin
|
// Load the `Exporter` symbol from the plugin
|
||||||
LogWithCommand.Info("loading transformers from plugin")
|
log.Info("loading transformers from plugin")
|
||||||
symExporter, err := plug.Lookup("Exporter")
|
symExporter, err := plug.Lookup("Exporter")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Debug("loading Exporter symbol failed")
|
log.Debug("loading Exporter symbol failed")
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert that the symbol is of type Exporter
|
// Assert that the symbol is of type Exporter
|
||||||
exporter, ok := symExporter.(Exporter)
|
exporter, ok := symExporter.(Exporter)
|
||||||
if !ok {
|
if !ok {
|
||||||
LogWithCommand.Debug("plugged-in symbol not of type Exporter")
|
log.Debug("plugged-in symbol not of type Exporter")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,18 +163,14 @@ 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)
|
||||||
err := ew.AddTransformers(ethEventInitializers)
|
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}
|
tailer := fs.FileTailer{Path: storageDiffsPath}
|
||||||
storageFetcher := fetcher.NewCsvTailStorageFetcher(tailer)
|
sw := watcher.NewStorageWatcher(tailer, &db)
|
||||||
sw := watcher.NewStorageWatcher(storageFetcher, &db)
|
|
||||||
sw.AddTransformers(ethStorageInitializers)
|
sw.AddTransformers(ethStorageInitializers)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go watchEthStorage(&sw, &wg)
|
go watchEthStorage(&sw, &wg)
|
||||||
@@ -198,6 +187,5 @@ func composeAndExecute() {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(composeAndExecuteCmd)
|
rootCmd.AddCommand(composeAndExecuteCmd)
|
||||||
composeAndExecuteCmd.Flags().BoolVarP(&recheckHeadersArg, "recheck-headers", "r", false, "whether to re-check headers for watched events")
|
composeAndExecuteCmd.Flags().BoolVar(&recheckHeadersArg, "recheckHeaders", false, "checks headers that are already checked for each transformer.")
|
||||||
composeAndExecuteCmd.Flags().DurationVarP(&queueRecheckInterval, "queue-recheck-interval", "q", 5*time.Minute, "interval duration for rechecking queued storage diffs (ex: 5m30s)")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import (
|
|||||||
|
|
||||||
st "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
st "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
ft "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/transformer"
|
ft "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/full/transformer"
|
||||||
ht "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/header/transformer"
|
lt "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/utils"
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -79,8 +79,6 @@ Requires a .toml config file:
|
|||||||
piping = true
|
piping = true
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
SubCommand = cmd.CalledAs()
|
|
||||||
LogWithCommand = *log.WithField("SubCommand", SubCommand)
|
|
||||||
contractWatcher()
|
contractWatcher()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -100,28 +98,28 @@ func contractWatcher() {
|
|||||||
con := config.ContractConfig{}
|
con := config.ContractConfig{}
|
||||||
con.PrepConfig()
|
con.PrepConfig()
|
||||||
switch mode {
|
switch mode {
|
||||||
case "header":
|
case "light":
|
||||||
t = ht.NewTransformer(con, blockChain, &db)
|
t = lt.NewTransformer(con, blockChain, &db)
|
||||||
case "full":
|
case "full":
|
||||||
t = ft.NewTransformer(con, blockChain, &db)
|
t = ft.NewTransformer(con, blockChain, &db)
|
||||||
default:
|
default:
|
||||||
LogWithCommand.Fatal("Invalid mode")
|
log.Fatal("Invalid mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := t.Init()
|
err := t.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal(fmt.Sprintf("Failed to initialize transformer, err: %v ", err))
|
log.Fatal(fmt.Sprintf("Failed to initialized transformer\r\nerr: %v\r\n", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Error("Execution error for transformer: ", t.GetConfig().Name, err)
|
log.Error("Execution error for transformer:", t.GetConfig().Name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(contractWatcherCmd)
|
rootCmd.AddCommand(contractWatcherCmd)
|
||||||
contractWatcherCmd.Flags().StringVarP(&mode, "mode", "o", "header", "'header' or 'full' mode to work with either header synced or fully synced vDB (default is header)")
|
contractWatcherCmd.Flags().StringVarP(&mode, "mode", "o", "light", "'light' or 'full' mode to work with either light synced or fully synced vDB (default is light)")
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-36
@@ -1,23 +1,23 @@
|
|||||||
// VulcanizeDB
|
// Copyright © 2019 Vulcanize, Inc
|
||||||
// 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"
|
||||||
|
"os"
|
||||||
"plugin"
|
"plugin"
|
||||||
syn "sync"
|
syn "sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -26,8 +26,6 @@ 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"
|
|
||||||
"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/pkg/fs"
|
||||||
@@ -64,8 +62,6 @@ must have been composed by the same version of vulcanizedb or else it will not b
|
|||||||
Specify config location when executing the command:
|
Specify config location when executing the command:
|
||||||
./vulcanizedb execute --config=./environments/config_name.toml`,
|
./vulcanizedb execute --config=./environments/config_name.toml`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
SubCommand = cmd.CalledAs()
|
|
||||||
LogWithCommand = *log.WithField("SubCommand", SubCommand)
|
|
||||||
execute()
|
execute()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -77,29 +73,30 @@ func execute() {
|
|||||||
// Get the plugin path and load the plugin
|
// Get the plugin path and load the plugin
|
||||||
_, pluginPath, err := genConfig.GetPluginPaths()
|
_, pluginPath, err := genConfig.GetPluginPaths()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Executing plugin %s", pluginPath)
|
fmt.Printf("Executing plugin %s", pluginPath)
|
||||||
LogWithCommand.Info("linking plugin ", pluginPath)
|
log.Info("linking plugin", pluginPath)
|
||||||
plug, err := plugin.Open(pluginPath)
|
plug, err := plugin.Open(pluginPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Warn("linking plugin failed")
|
log.Debug("linking plugin failed")
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the `Exporter` symbol from the plugin
|
// Load the `Exporter` symbol from the plugin
|
||||||
LogWithCommand.Info("loading transformers from plugin")
|
log.Info("loading transformers from plugin")
|
||||||
symExporter, err := plug.Lookup("Exporter")
|
symExporter, err := plug.Lookup("Exporter")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Warn("loading Exporter symbol failed")
|
log.Debug("loading Exporter symbol failed")
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert that the symbol is of type Exporter
|
// Assert that the symbol is of type Exporter
|
||||||
exporter, ok := symExporter.(Exporter)
|
exporter, ok := symExporter.(Exporter)
|
||||||
if !ok {
|
if !ok {
|
||||||
LogWithCommand.Fatal("plugged-in symbol not of type Exporter")
|
log.Debug("plugged-in symbol not of type Exporter")
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the Exporters export method to load the EventTransformerInitializer, StorageTransformerInitializer, and ContractTransformerInitializer sets
|
// Use the Exporters export method to load the EventTransformerInitializer, StorageTransformerInitializer, and ContractTransformerInitializer sets
|
||||||
@@ -114,18 +111,14 @@ 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)
|
||||||
err = ew.AddTransformers(ethEventInitializers)
|
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}
|
tailer := fs.FileTailer{Path: storageDiffsPath}
|
||||||
storageFetcher := fetcher.NewCsvTailStorageFetcher(tailer)
|
sw := watcher.NewStorageWatcher(tailer, &db)
|
||||||
sw := watcher.NewStorageWatcher(storageFetcher, &db)
|
|
||||||
sw.AddTransformers(ethStorageInitializers)
|
sw.AddTransformers(ethStorageInitializers)
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go watchEthStorage(&sw, &wg)
|
go watchEthStorage(&sw, &wg)
|
||||||
@@ -142,8 +135,7 @@ func execute() {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(executeCmd)
|
rootCmd.AddCommand(executeCmd)
|
||||||
executeCmd.Flags().BoolVarP(&recheckHeadersArg, "recheck-headers", "r", false, "whether to re-check headers for watched events")
|
executeCmd.Flags().BoolVar(&recheckHeadersArg, "recheckHeaders", false, "checks headers that are already checked for each transformer.")
|
||||||
executeCmd.Flags().DurationVarP(&queueRecheckInterval, "queue-recheck-interval", "q", 5*time.Minute, "interval duration for rechecking queued storage diffs (ex: 5m30s)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Exporter interface {
|
type Exporter interface {
|
||||||
@@ -153,36 +145,35 @@ type Exporter interface {
|
|||||||
func watchEthEvents(w *watcher.EventWatcher, wg *syn.WaitGroup) {
|
func watchEthEvents(w *watcher.EventWatcher, wg *syn.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
// Execute over the EventTransformerInitializer set using the watcher
|
// Execute over the EventTransformerInitializer set using the watcher
|
||||||
LogWithCommand.Info("executing event transformers")
|
log.Info("executing event transformers")
|
||||||
var recheck constants.TransformerExecution
|
var recheck constants.TransformerExecution
|
||||||
if recheckHeadersArg {
|
if recheckHeadersArg {
|
||||||
recheck = constants.HeaderRecheck
|
recheck = constants.HeaderRecheck
|
||||||
} else {
|
} else {
|
||||||
recheck = constants.HeaderUnchecked
|
recheck = constants.HeaderMissing
|
||||||
}
|
}
|
||||||
err := w.Execute(recheck)
|
ticker := time.NewTicker(pollingInterval)
|
||||||
if err != nil {
|
defer ticker.Stop()
|
||||||
LogWithCommand.Fatalf("error executing event watcher: %s", err.Error())
|
for range ticker.C {
|
||||||
|
w.Execute(recheck)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func watchEthStorage(w *watcher.StorageWatcher, wg *syn.WaitGroup) {
|
func watchEthStorage(w *watcher.StorageWatcher, 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")
|
log.Info("executing storage transformers")
|
||||||
ticker := time.NewTicker(pollingInterval)
|
ticker := time.NewTicker(pollingInterval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
errs := make(chan error)
|
w.Execute()
|
||||||
rows := make(chan storageUtils.StorageDiffRow)
|
|
||||||
w.Execute(rows, errs, queueRecheckInterval)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func watchEthContract(w *watcher.ContractWatcher, wg *syn.WaitGroup) {
|
func watchEthContract(w *watcher.ContractWatcher, wg *syn.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
// Execute over the ContractTransformerInitializer set using the contract watcher
|
// Execute over the ContractTransformerInitializer set using the contract watcher
|
||||||
LogWithCommand.Info("executing contract_watcher transformers")
|
log.Info("executing contract_watcher transformers")
|
||||||
ticker := time.NewTicker(pollingInterval)
|
ticker := time.NewTicker(pollingInterval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
|
|||||||
@@ -30,14 +30,14 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/utils"
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// headerSyncCmd represents the headerSync command
|
// lightSyncCmd represents the lightSync command
|
||||||
var headerSyncCmd = &cobra.Command{
|
var lightSyncCmd = &cobra.Command{
|
||||||
Use: "headerSync",
|
Use: "lightSync",
|
||||||
Short: "Syncs VulcanizeDB with local ethereum node's block headers",
|
Short: "Syncs VulcanizeDB with local ethereum node's block headers",
|
||||||
Long: `Syncs VulcanizeDB with local ethereum node. Populates
|
Long: `Syncs VulcanizeDB with local ethereum node. Populates
|
||||||
Postgres with block headers.
|
Postgres with block headers.
|
||||||
|
|
||||||
./vulcanizedb headerSync --starting-block-number 0 --config public.toml
|
./vulcanizedb lightSync --starting-block-number 0 --config public.toml
|
||||||
|
|
||||||
Expects ethereum node to be running and requires a .toml config:
|
Expects ethereum node to be running and requires a .toml config:
|
||||||
|
|
||||||
@@ -50,15 +50,13 @@ Expects ethereum node to be running and requires a .toml config:
|
|||||||
ipcPath = "/Users/user/Library/Ethereum/geth.ipc"
|
ipcPath = "/Users/user/Library/Ethereum/geth.ipc"
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
SubCommand = cmd.CalledAs()
|
lightSync()
|
||||||
LogWithCommand = *log.WithField("SubCommand", SubCommand)
|
|
||||||
headerSync()
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(headerSyncCmd)
|
rootCmd.AddCommand(lightSyncCmd)
|
||||||
headerSyncCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block number to start syncing from")
|
lightSyncCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block number to start syncing from")
|
||||||
}
|
}
|
||||||
|
|
||||||
func backFillAllHeaders(blockchain core.BlockChain, headerRepository datastore.HeaderRepository, missingBlocksPopulated chan int, startingBlockNumber int64) {
|
func backFillAllHeaders(blockchain core.BlockChain, headerRepository datastore.HeaderRepository, missingBlocksPopulated chan int, startingBlockNumber int64) {
|
||||||
@@ -66,12 +64,12 @@ func backFillAllHeaders(blockchain core.BlockChain, headerRepository datastore.H
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO Lots of possible errors in the call stack above. If errors occur, we still put
|
// TODO Lots of possible errors in the call stack above. If errors occur, we still put
|
||||||
// 0 in the channel, triggering another round
|
// 0 in the channel, triggering another round
|
||||||
LogWithCommand.Error("backfillAllHeaders: Error populating headers: ", err)
|
log.Error("backfillAllHeaders: Error populating headers: ", err)
|
||||||
}
|
}
|
||||||
missingBlocksPopulated <- populated
|
missingBlocksPopulated <- populated
|
||||||
}
|
}
|
||||||
|
|
||||||
func headerSync() {
|
func lightSync() {
|
||||||
ticker := time.NewTicker(pollingInterval)
|
ticker := time.NewTicker(pollingInterval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
blockChain := getBlockChain()
|
blockChain := getBlockChain()
|
||||||
@@ -88,9 +86,9 @@ func headerSync() {
|
|||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
window, err := validator.ValidateHeaders()
|
window, err := validator.ValidateHeaders()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Error("headerSync: ValidateHeaders failed: ", err)
|
log.Error("lightSync: ValidateHeaders failed: ", err)
|
||||||
}
|
}
|
||||||
LogWithCommand.Debug(window.GetString())
|
log.Info(window.GetString())
|
||||||
case n := <-missingBlocksPopulated:
|
case n := <-missingBlocksPopulated:
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
@@ -103,12 +101,12 @@ func headerSync() {
|
|||||||
func validateArgs(blockChain *geth.BlockChain) {
|
func validateArgs(blockChain *geth.BlockChain) {
|
||||||
lastBlock, err := blockChain.LastBlock()
|
lastBlock, err := blockChain.LastBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Error("validateArgs: Error getting last block: ", err)
|
log.Error("validateArgs: Error getting last block: ", err)
|
||||||
}
|
}
|
||||||
if lastBlock.Int64() == 0 {
|
if lastBlock.Int64() == 0 {
|
||||||
LogWithCommand.Fatal("geth initial: state sync not finished")
|
log.Fatal("geth initial: state sync not finished")
|
||||||
}
|
}
|
||||||
if startingBlockNumber > lastBlock.Int64() {
|
if startingBlockNumber > lastBlock.Int64() {
|
||||||
LogWithCommand.Fatal("starting block number > current block number")
|
log.Fatal("starting block number > current block number")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+19
-42
@@ -18,6 +18,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -35,19 +36,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cfgFile string
|
cfgFile string
|
||||||
databaseConfig config.Database
|
databaseConfig config.Database
|
||||||
genConfig config.Plugin
|
genConfig config.Plugin
|
||||||
ipc string
|
ipc string
|
||||||
levelDbPath string
|
levelDbPath string
|
||||||
queueRecheckInterval time.Duration
|
startingBlockNumber int64
|
||||||
startingBlockNumber int64
|
storageDiffsPath string
|
||||||
storageDiffsPath string
|
syncAll bool
|
||||||
syncAll bool
|
endingBlockNumber int64
|
||||||
endingBlockNumber int64
|
recheckHeadersArg bool
|
||||||
recheckHeadersArg bool
|
|
||||||
SubCommand string
|
|
||||||
LogWithCommand log.Entry
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -57,26 +55,18 @@ const (
|
|||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
Use: "vulcanizedb",
|
Use: "vulcanizedb",
|
||||||
PersistentPreRun: initFuncs,
|
PersistentPreRun: database,
|
||||||
}
|
}
|
||||||
|
|
||||||
func Execute() {
|
func Execute() {
|
||||||
log.Info("----- Starting vDB -----")
|
log.Info("----- Starting vDB -----")
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initFuncs(cmd *cobra.Command, args []string) {
|
func database(cmd *cobra.Command, args []string) {
|
||||||
setViperConfigs()
|
|
||||||
logLvlErr := logLevel()
|
|
||||||
if logLvlErr != nil {
|
|
||||||
log.Fatal("Could not set log level: ", logLvlErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
||||||
@@ -90,19 +80,6 @@ func setViperConfigs() {
|
|||||||
viper.Set("database.config", databaseConfig)
|
viper.Set("database.config", databaseConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logLevel() error {
|
|
||||||
lvl, err := log.ParseLevel(viper.GetString("log.level"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.SetLevel(lvl)
|
|
||||||
if lvl > log.InfoLevel {
|
|
||||||
log.SetReportCaller(true)
|
|
||||||
}
|
|
||||||
log.Info("Log level set to ", lvl.String())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize(initConfig)
|
cobra.OnInitialize(initConfig)
|
||||||
// When searching for env variables, replace dots in config keys with underscores
|
// When searching for env variables, replace dots in config keys with underscores
|
||||||
@@ -119,7 +96,6 @@ func init() {
|
|||||||
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("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")
|
|
||||||
|
|
||||||
viper.BindPFlag("database.name", rootCmd.PersistentFlags().Lookup("database-name"))
|
viper.BindPFlag("database.name", rootCmd.PersistentFlags().Lookup("database-name"))
|
||||||
viper.BindPFlag("database.port", rootCmd.PersistentFlags().Lookup("database-port"))
|
viper.BindPFlag("database.port", rootCmd.PersistentFlags().Lookup("database-port"))
|
||||||
@@ -130,7 +106,6 @@ func init() {
|
|||||||
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("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"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initConfig() {
|
func initConfig() {
|
||||||
@@ -140,14 +115,16 @@ func initConfig() {
|
|||||||
noConfigError := "No config file passed with --config flag"
|
noConfigError := "No config file passed with --config flag"
|
||||||
fmt.Println("Error: ", noConfigError)
|
fmt.Println("Error: ", noConfigError)
|
||||||
log.Fatal(noConfigError)
|
log.Fatal(noConfigError)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := viper.ReadInConfig(); err == nil {
|
if err := viper.ReadInConfig(); err == nil {
|
||||||
log.Printf("Using config file: %s\n\n", viper.ConfigFileUsed())
|
log.Printf("Using config file: %s\n\n", viper.ConfigFileUsed())
|
||||||
} else {
|
} else {
|
||||||
invalidConfigError := "Couldn't read config file"
|
invalidConfigError := "Couldn't read config file"
|
||||||
formattedError := fmt.Sprintf("%s: %s", invalidConfigError, err.Error())
|
fmt.Println("Error: ", invalidConfigError)
|
||||||
log.Fatal(formattedError)
|
log.Fatal(invalidConfigError)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +132,7 @@ func getBlockChain() *geth.BlockChain {
|
|||||||
rawRpcClient, err := rpc.Dial(ipc)
|
rawRpcClient, err := rpc.Dial(ipc)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
rpcClient := client.NewRpcClient(rawRpcClient, ipc)
|
rpcClient := client.NewRpcClient(rawRpcClient, ipc)
|
||||||
ethClient := ethclient.NewClient(rawRpcClient)
|
ethClient := ethclient.NewClient(rawRpcClient)
|
||||||
|
|||||||
@@ -29,14 +29,14 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/utils"
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fullSyncCmd represents the fullSync command
|
// syncCmd represents the sync command
|
||||||
var fullSyncCmd = &cobra.Command{
|
var syncCmd = &cobra.Command{
|
||||||
Use: "fullSync",
|
Use: "sync",
|
||||||
Short: "Syncs VulcanizeDB with local ethereum node",
|
Short: "Syncs VulcanizeDB with local ethereum node",
|
||||||
Long: `Syncs VulcanizeDB with local ethereum node. Populates
|
Long: `Syncs VulcanizeDB with local ethereum node. Populates
|
||||||
Postgres with blocks, transactions, receipts, and logs.
|
Postgres with blocks, transactions, receipts, and logs.
|
||||||
|
|
||||||
./vulcanizedb fullSync --starting-block-number 0 --config public.toml
|
./vulcanizedb sync --starting-block-number 0 --config public.toml
|
||||||
|
|
||||||
Expects ethereum node to be running and requires a .toml config:
|
Expects ethereum node to be running and requires a .toml config:
|
||||||
|
|
||||||
@@ -49,39 +49,38 @@ Expects ethereum node to be running and requires a .toml config:
|
|||||||
ipcPath = "/Users/user/Library/Ethereum/geth.ipc"
|
ipcPath = "/Users/user/Library/Ethereum/geth.ipc"
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
SubCommand = cmd.CalledAs()
|
sync()
|
||||||
LogWithCommand = *log.WithField("SubCommand", SubCommand)
|
|
||||||
fullSync()
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(fullSyncCmd)
|
rootCmd.AddCommand(syncCmd)
|
||||||
fullSyncCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block number to start syncing from")
|
|
||||||
|
syncCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block number to start syncing from")
|
||||||
}
|
}
|
||||||
|
|
||||||
func backFillAllBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, missingBlocksPopulated chan int, startingBlockNumber int64) {
|
func backFillAllBlocks(blockchain core.BlockChain, blockRepository datastore.BlockRepository, missingBlocksPopulated chan int, startingBlockNumber int64) {
|
||||||
populated, err := history.PopulateMissingBlocks(blockchain, blockRepository, startingBlockNumber)
|
populated, err := history.PopulateMissingBlocks(blockchain, blockRepository, startingBlockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Error("backfillAllBlocks: error in populateMissingBlocks: ", err)
|
log.Error("backfillAllBlocks: error in populateMissingBlocks: ", err)
|
||||||
}
|
}
|
||||||
missingBlocksPopulated <- populated
|
missingBlocksPopulated <- populated
|
||||||
}
|
}
|
||||||
|
|
||||||
func fullSync() {
|
func sync() {
|
||||||
ticker := time.NewTicker(pollingInterval)
|
ticker := time.NewTicker(pollingInterval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
blockChain := getBlockChain()
|
blockChain := getBlockChain()
|
||||||
lastBlock, err := blockChain.LastBlock()
|
lastBlock, err := blockChain.LastBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Error("fullSync: Error getting last block: ", err)
|
log.Error("sync: Error getting last block: ", err)
|
||||||
}
|
}
|
||||||
if lastBlock.Int64() == 0 {
|
if lastBlock.Int64() == 0 {
|
||||||
LogWithCommand.Fatal("geth initial: state sync not finished")
|
log.Fatal("geth initial: state sync not finished")
|
||||||
}
|
}
|
||||||
if startingBlockNumber > lastBlock.Int64() {
|
if startingBlockNumber > lastBlock.Int64() {
|
||||||
LogWithCommand.Fatal("fullSync: starting block number > current block number")
|
log.Fatal("sync: starting block number > current block number")
|
||||||
}
|
}
|
||||||
|
|
||||||
db := utils.LoadPostgres(databaseConfig, blockChain.Node())
|
db := utils.LoadPostgres(databaseConfig, blockChain.Node())
|
||||||
@@ -95,9 +94,9 @@ func fullSync() {
|
|||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
window, err := validator.ValidateBlocks()
|
window, err := validator.ValidateBlocks()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
LogWithCommand.Error("fullSync: error in validateBlocks: ", err)
|
log.Error("sync: error in validateBlocks: ", err)
|
||||||
}
|
}
|
||||||
LogWithCommand.Debug(window.GetString())
|
log.Info(window.GetString())
|
||||||
case <-missingBlocksPopulated:
|
case <-missingBlocksPopulated:
|
||||||
go backFillAllBlocks(blockChain, blockRepository, missingBlocksPopulated, startingBlockNumber)
|
go backFillAllBlocks(blockChain, blockRepository, missingBlocksPopulated, startingBlockNumber)
|
||||||
}
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
-- +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;
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-- +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;
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
CREATE TABLE public.addresses
|
|
||||||
(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
address character varying(42),
|
|
||||||
UNIQUE (address)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP TABLE public.addresses;
|
|
||||||
@@ -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 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;
|
||||||
@@ -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_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;
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
-- +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);
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
-- +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;
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
-- +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;
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
-- +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;
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- +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;
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
CREATE TABLE public.headers
|
|
||||||
(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
hash VARCHAR(66),
|
|
||||||
block_number BIGINT,
|
|
||||||
raw JSONB,
|
|
||||||
block_timestamp NUMERIC,
|
|
||||||
check_count INTEGER NOT NULL DEFAULT 0,
|
|
||||||
eth_node_id INTEGER NOT NULL REFERENCES eth_nodes (id) ON DELETE CASCADE,
|
|
||||||
eth_node_fingerprint VARCHAR(128)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Index is removed when table is
|
|
||||||
CREATE INDEX headers_block_number ON public.headers (block_number);
|
|
||||||
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP TABLE public.headers;
|
|
||||||
+1
-2
@@ -5,8 +5,7 @@ CREATE TABLE public.queued_storage (
|
|||||||
block_hash BYTEA,
|
block_hash BYTEA,
|
||||||
contract BYTEA,
|
contract BYTEA,
|
||||||
storage_key BYTEA,
|
storage_key BYTEA,
|
||||||
storage_value BYTEA,
|
storage_value BYTEA
|
||||||
UNIQUE (block_height, block_hash, contract, storage_key, storage_value)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
-- +goose Up
|
-- +goose Up
|
||||||
CREATE TABLE header_sync_transactions (
|
CREATE TABLE light_sync_transactions (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
header_id INTEGER NOT NULL REFERENCES headers(id) ON DELETE CASCADE,
|
header_id INTEGER NOT NULL REFERENCES headers(id) ON DELETE CASCADE,
|
||||||
hash VARCHAR(66),
|
hash VARCHAR(66),
|
||||||
@@ -16,4 +16,4 @@ CREATE TABLE header_sync_transactions (
|
|||||||
);
|
);
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
DROP TABLE header_sync_transactions;
|
DROP TABLE light_sync_transactions;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE light_sync_receipts(
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
transaction_id INTEGER NOT NULL REFERENCES light_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 light_sync_receipts;
|
||||||
@@ -1,19 +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_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;
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
-- +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;
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
-- +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;
|
|
||||||
+220
-410
@@ -2,8 +2,8 @@
|
|||||||
-- PostgreSQL database dump
|
-- PostgreSQL database dump
|
||||||
--
|
--
|
||||||
|
|
||||||
-- Dumped from database version 11.4
|
-- Dumped from database version 10.6
|
||||||
-- Dumped by pg_dump version 11.4
|
-- Dumped by pg_dump version 10.6
|
||||||
|
|
||||||
SET statement_timeout = 0;
|
SET statement_timeout = 0;
|
||||||
SET lock_timeout = 0;
|
SET lock_timeout = 0;
|
||||||
@@ -12,49 +12,32 @@ SET client_encoding = 'UTF8';
|
|||||||
SET standard_conforming_strings = on;
|
SET standard_conforming_strings = on;
|
||||||
SELECT pg_catalog.set_config('search_path', '', false);
|
SELECT pg_catalog.set_config('search_path', '', false);
|
||||||
SET check_function_bodies = false;
|
SET check_function_bodies = false;
|
||||||
SET xmloption = content;
|
|
||||||
SET client_min_messages = warning;
|
SET client_min_messages = warning;
|
||||||
SET row_security = off;
|
SET row_security = off;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
|
||||||
|
|
||||||
|
|
||||||
SET default_tablespace = '';
|
SET default_tablespace = '';
|
||||||
|
|
||||||
SET default_with_oids = false;
|
SET default_with_oids = false;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: addresses; Type: TABLE; Schema: public; Owner: -
|
-- Name: logs; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|
||||||
CREATE TABLE public.addresses (
|
CREATE TABLE public.logs (
|
||||||
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),
|
||||||
@@ -74,9 +57,9 @@ CREATE TABLE public.full_sync_logs (
|
|||||||
--
|
--
|
||||||
|
|
||||||
CREATE VIEW public.block_stats AS
|
CREATE VIEW public.block_stats AS
|
||||||
SELECT max(full_sync_logs.block_number) AS max_block,
|
SELECT max(logs.block_number) AS max_block,
|
||||||
min(full_sync_logs.block_number) AS min_block
|
min(logs.block_number) AS min_block
|
||||||
FROM public.full_sync_logs;
|
FROM public.logs;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -168,33 +151,13 @@ 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_id integer NOT NULL,
|
contract_address character varying(42),
|
||||||
cumulative_gas_used numeric,
|
cumulative_gas_used numeric,
|
||||||
gas_used numeric,
|
gas_used numeric,
|
||||||
state_root character varying(66),
|
state_root character varying(66),
|
||||||
@@ -296,124 +259,6 @@ 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: -
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE public.header_sync_receipts (
|
|
||||||
id integer NOT NULL,
|
|
||||||
transaction_id integer NOT NULL,
|
|
||||||
header_id integer NOT NULL,
|
|
||||||
contract_address_id integer NOT NULL,
|
|
||||||
cumulative_gas_used numeric,
|
|
||||||
gas_used numeric,
|
|
||||||
state_root character varying(66),
|
|
||||||
status integer,
|
|
||||||
tx_hash character varying(66),
|
|
||||||
rlp bytea
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_receipts_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE SEQUENCE public.header_sync_receipts_id_seq
|
|
||||||
AS integer
|
|
||||||
START WITH 1
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MINVALUE
|
|
||||||
NO MAXVALUE
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_receipts_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER SEQUENCE public.header_sync_receipts_id_seq OWNED BY public.header_sync_receipts.id;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_transactions; Type: TABLE; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE TABLE public.header_sync_transactions (
|
|
||||||
id integer NOT NULL,
|
|
||||||
header_id integer NOT NULL,
|
|
||||||
hash character varying(66),
|
|
||||||
gas_limit numeric,
|
|
||||||
gas_price numeric,
|
|
||||||
input_data bytea,
|
|
||||||
nonce numeric,
|
|
||||||
raw bytea,
|
|
||||||
tx_from character varying(44),
|
|
||||||
tx_index integer,
|
|
||||||
tx_to character varying(44),
|
|
||||||
value numeric
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_transactions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE SEQUENCE public.header_sync_transactions_id_seq
|
|
||||||
AS integer
|
|
||||||
START WITH 1
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MINVALUE
|
|
||||||
NO MAXVALUE
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_transactions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER SEQUENCE public.header_sync_transactions_id_seq OWNED BY public.header_sync_transactions.id;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: headers; Type: TABLE; Schema: public; Owner: -
|
-- Name: headers; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -424,7 +269,6 @@ 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)
|
||||||
);
|
);
|
||||||
@@ -450,6 +294,84 @@ CREATE SEQUENCE public.headers_id_seq
|
|||||||
ALTER SEQUENCE public.headers_id_seq OWNED BY public.headers.id;
|
ALTER SEQUENCE public.headers_id_seq OWNED BY public.headers.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_receipts; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.light_sync_receipts (
|
||||||
|
id integer NOT NULL,
|
||||||
|
transaction_id integer NOT NULL,
|
||||||
|
header_id integer NOT NULL,
|
||||||
|
contract_address character varying(42),
|
||||||
|
cumulative_gas_used numeric,
|
||||||
|
gas_used numeric,
|
||||||
|
state_root character varying(66),
|
||||||
|
status integer,
|
||||||
|
tx_hash character varying(66),
|
||||||
|
rlp bytea
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_receipts_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.light_sync_receipts_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_receipts_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.light_sync_receipts_id_seq OWNED BY public.light_sync_receipts.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_transactions; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.light_sync_transactions (
|
||||||
|
id integer NOT NULL,
|
||||||
|
header_id integer NOT NULL,
|
||||||
|
hash character varying(66),
|
||||||
|
gas_limit numeric,
|
||||||
|
gas_price numeric,
|
||||||
|
input_data bytea,
|
||||||
|
nonce numeric,
|
||||||
|
raw bytea,
|
||||||
|
tx_from character varying(44),
|
||||||
|
tx_index integer,
|
||||||
|
tx_to character varying(44),
|
||||||
|
value numeric
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_transactions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.light_sync_transactions_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_transactions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.light_sync_transactions_id_seq OWNED BY public.light_sync_transactions.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: log_filters; Type: TABLE; Schema: public; Owner: -
|
-- Name: log_filters; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -490,6 +412,26 @@ 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: -
|
||||||
--
|
--
|
||||||
@@ -618,59 +560,21 @@ 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,
|
||||||
full_sync_logs.id,
|
logs.id,
|
||||||
full_sync_logs.block_number,
|
logs.block_number,
|
||||||
full_sync_logs.address,
|
logs.address,
|
||||||
full_sync_logs.tx_hash,
|
logs.tx_hash,
|
||||||
full_sync_logs.index,
|
logs.index,
|
||||||
full_sync_logs.topic0,
|
logs.topic0,
|
||||||
full_sync_logs.topic1,
|
logs.topic1,
|
||||||
full_sync_logs.topic2,
|
logs.topic2,
|
||||||
full_sync_logs.topic3,
|
logs.topic3,
|
||||||
full_sync_logs.data,
|
logs.data,
|
||||||
full_sync_logs.receipt_id
|
logs.receipt_id
|
||||||
FROM ((public.log_filters
|
FROM ((public.log_filters
|
||||||
CROSS JOIN public.block_stats)
|
CROSS JOIN public.block_stats)
|
||||||
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)))))
|
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)))))
|
||||||
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)));
|
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)));
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- 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);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -694,13 +598,6 @@ 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: -
|
||||||
--
|
--
|
||||||
@@ -722,27 +619,6 @@ 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: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_receipts ALTER COLUMN id SET DEFAULT nextval('public.header_sync_receipts_id_seq'::regclass);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_transactions id; Type: DEFAULT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_transactions ALTER COLUMN id SET DEFAULT nextval('public.header_sync_transactions_id_seq'::regclass);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: headers id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: headers id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -750,6 +626,20 @@ ALTER TABLE ONLY public.header_sync_transactions ALTER COLUMN id SET DEFAULT nex
|
|||||||
ALTER TABLE ONLY public.headers ALTER COLUMN id SET DEFAULT nextval('public.headers_id_seq'::regclass);
|
ALTER TABLE ONLY public.headers ALTER COLUMN id SET DEFAULT nextval('public.headers_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_receipts id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_receipts ALTER COLUMN id SET DEFAULT nextval('public.light_sync_receipts_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_transactions id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_transactions ALTER COLUMN id SET DEFAULT nextval('public.light_sync_transactions_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: log_filters id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: log_filters id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -757,6 +647,13 @@ 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: -
|
||||||
--
|
--
|
||||||
@@ -778,29 +675,6 @@ 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: -
|
||||||
--
|
--
|
||||||
@@ -841,14 +715,6 @@ 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: -
|
||||||
--
|
--
|
||||||
@@ -873,54 +739,6 @@ 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: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_receipts
|
|
||||||
ADD CONSTRAINT header_sync_receipts_header_id_transaction_id_key UNIQUE (header_id, transaction_id);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_receipts header_sync_receipts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_receipts
|
|
||||||
ADD CONSTRAINT header_sync_receipts_pkey PRIMARY KEY (id);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_transactions header_sync_transactions_header_id_hash_key; Type: CONSTRAINT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_transactions
|
|
||||||
ADD CONSTRAINT header_sync_transactions_header_id_hash_key UNIQUE (header_id, hash);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_transactions header_sync_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_transactions
|
|
||||||
ADD CONSTRAINT header_sync_transactions_pkey PRIMARY KEY (id);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: headers headers_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: headers headers_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -929,6 +747,46 @@ ALTER TABLE ONLY public.headers
|
|||||||
ADD CONSTRAINT headers_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT headers_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_receipts light_sync_receipts_header_id_transaction_id_key; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_receipts
|
||||||
|
ADD CONSTRAINT light_sync_receipts_header_id_transaction_id_key UNIQUE (header_id, transaction_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_receipts light_sync_receipts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_receipts
|
||||||
|
ADD CONSTRAINT light_sync_receipts_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_transactions light_sync_transactions_header_id_hash_key; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_transactions
|
||||||
|
ADD CONSTRAINT light_sync_transactions_header_id_hash_key UNIQUE (header_id, hash);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_transactions light_sync_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_transactions
|
||||||
|
ADD CONSTRAINT light_sync_transactions_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: -
|
||||||
--
|
--
|
||||||
@@ -945,14 +803,6 @@ ALTER TABLE ONLY public.eth_nodes
|
|||||||
ADD CONSTRAINT nodes_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT nodes_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: queued_storage queued_storage_block_height_block_hash_contract_storage_key_key; Type: CONSTRAINT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.queued_storage
|
|
||||||
ADD CONSTRAINT queued_storage_block_height_block_hash_contract_storage_key_key UNIQUE (block_height, block_hash, contract, storage_key, storage_value);
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: queued_storage queued_storage_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: queued_storage queued_storage_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -993,14 +843,6 @@ 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: -
|
||||||
--
|
--
|
||||||
@@ -1059,14 +901,6 @@ 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: -
|
||||||
--
|
--
|
||||||
@@ -1075,54 +909,6 @@ 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: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_receipts
|
|
||||||
ADD CONSTRAINT header_sync_receipts_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_receipts header_sync_receipts_transaction_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_receipts
|
|
||||||
ADD CONSTRAINT header_sync_receipts_transaction_id_fkey FOREIGN KEY (transaction_id) REFERENCES public.header_sync_transactions(id) ON DELETE CASCADE;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_sync_transactions header_sync_transactions_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
ALTER TABLE ONLY public.header_sync_transactions
|
|
||||||
ADD CONSTRAINT header_sync_transactions_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: headers headers_eth_node_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: headers headers_eth_node_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -1131,6 +917,30 @@ ALTER TABLE ONLY public.headers
|
|||||||
ADD CONSTRAINT headers_eth_node_id_fkey FOREIGN KEY (eth_node_id) REFERENCES public.eth_nodes(id) ON DELETE CASCADE;
|
ADD CONSTRAINT headers_eth_node_id_fkey FOREIGN KEY (eth_node_id) REFERENCES public.eth_nodes(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_receipts light_sync_receipts_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_receipts
|
||||||
|
ADD CONSTRAINT light_sync_receipts_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_receipts light_sync_receipts_transaction_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_receipts
|
||||||
|
ADD CONSTRAINT light_sync_receipts_transaction_id_fkey FOREIGN KEY (transaction_id) REFERENCES public.light_sync_transactions(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: light_sync_transactions light_sync_transactions_header_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.light_sync_transactions
|
||||||
|
ADD CONSTRAINT light_sync_transactions_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: blocks node_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: blocks node_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -1140,10 +950,10 @@ ALTER TABLE ONLY public.blocks
|
|||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: full_sync_logs receipts_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: logs receipts_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|
||||||
ALTER TABLE ONLY public.full_sync_logs
|
ALTER TABLE ONLY public.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;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ S
|
|||||||
`Dockerfile` will build an alpine image containing:
|
`Dockerfile` will build an alpine image containing:
|
||||||
- vDB as a binary with runtime deps statically linked: `/app/vulcanizedb`
|
- vDB as a binary with runtime deps statically linked: `/app/vulcanizedb`
|
||||||
- The migration tool goose: `/app/goose`
|
- The migration tool goose: `/app/goose`
|
||||||
- Two services for running `headerSync` and `continuousLogSync`, started with the default configuration `environments/staging.toml`.
|
- Two services for running `lightSync` and `continuousLogSync`, started with the default configuration `environments/staging.toml`.
|
||||||
|
|
||||||
By default, vDB is configured towards the Kovan deploy. The configuration values can be overridden using environment variables, using the same hierarchical naming pattern but in CAPS and using underscores. For example, the contract address for the `Pit` can be set with the variable `CONTRACT_ADDRESS_PIT="0x123..."`.
|
By default, vDB is configured towards the Kovan deploy. The configuration values can be overridden using environment variables, using the same hierarchical naming pattern but in CAPS and using underscores. For example, the contract address for the `Pit` can be set with the variable `CONTRACT_ADDRESS_PIT="0x123..."`.
|
||||||
|
|
||||||
@@ -18,8 +18,8 @@ e`
|
|||||||
* `CONTRACT_ADDRESS_[CONTRACT NAME]=0x123...`
|
* `CONTRACT_ADDRESS_[CONTRACT NAME]=0x123...`
|
||||||
* `CONTRACT_ABI_[CONTRACT NAME]="ABI STRING"`
|
* `CONTRACT_ABI_[CONTRACT NAME]="ABI STRING"`
|
||||||
* `CONTRACT_DEPLOYMENT-BLOCK_[CONTRACT NAME]=0` (doesn't really matter on a short chain, just avoids long unnecessary searching)
|
* `CONTRACT_DEPLOYMENT-BLOCK_[CONTRACT NAME]=0` (doesn't really matter on a short chain, just avoids long unnecessary searching)
|
||||||
6. Start the `headerSync` and `continuousLogSync` services:
|
6. Start the `lightSync` and `continuousLogSync` services:
|
||||||
* `./vulcanizedb headerSync --config environments/staging.toml`
|
* `./vulcanizedb lightSync --config environments/staging.toml`
|
||||||
* `./vulcanizedb continuousLogSync --config environments/staging.toml`
|
* `./vulcanizedb continuousLogSync --config environments/staging.toml`
|
||||||
|
|
||||||
### Automated
|
### Automated
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Runs the migrations and starts the headerSync and continuousLogSync services
|
# Runs the migrations and starts the lightSync and continuousLogSync services
|
||||||
|
|
||||||
# Exit if the variable tests fail
|
# Exit if the variable tests fail
|
||||||
set -e
|
set -e
|
||||||
@@ -21,7 +21,7 @@ set +e
|
|||||||
./goose postgres "$CONNECT_STRING" up
|
./goose postgres "$CONNECT_STRING" up
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
# Fire up the services
|
# Fire up the services
|
||||||
./vulcanizedb headerSync --config environments/staging.toml &
|
./vulcanizedb lightSync --config environments/staging.toml &
|
||||||
./vulcanizedb continuousLogSync --config environments/staging.toml &
|
./vulcanizedb continuousLogSync --config environments/staging.toml &
|
||||||
else
|
else
|
||||||
echo "Could not run migrations. Are the database details correct?"
|
echo "Could not run migrations. Are the database details correct?"
|
||||||
|
|||||||
@@ -1,30 +1,26 @@
|
|||||||
# Custom Transformers
|
# composeAndExecute
|
||||||
When the capabilities of the generic `contractWatcher` are not sufficient, custom transformers tailored to a specific
|
The `composeAndExecute` command is used to compose and execute over an arbitrary set of custom transformers.
|
||||||
purpose can be leveraged.
|
This is accomplished by generating a Go pluggin which allows the `vulcanizedb` binary to link to external transformers, so
|
||||||
|
long as they abide by one of the standard [interfaces](../staging/libraries/shared/transformer).
|
||||||
|
|
||||||
Individual custom transformers can be composed together from any number of external repositories and executed as a
|
This command requires Go 1.11+ and [Go plugins](https://golang.org/pkg/plugin/) only work on Unix-based systems.
|
||||||
single process using the `compose` and `execute` commands or the `composeAndExecute` command. This is accomplished by
|
|
||||||
generating a Go plugin which allows the `vulcanizedb` binary to link to the external transformers, so long as they
|
|
||||||
abide by one of the standard [interfaces](../staging/libraries/shared/transformer).
|
|
||||||
|
|
||||||
## Writing custom transformers
|
## Writing custom transformers
|
||||||
For help with writing different types of custom transformers please see below:
|
Storage Transformers
|
||||||
|
|
||||||
Storage Transformers: transform data derived from contract storage tries
|
|
||||||
* [Guide](../../staging/libraries/shared/factories/storage/README.md)
|
* [Guide](../../staging/libraries/shared/factories/storage/README.md)
|
||||||
* [Example](../../staging/libraries/shared/factories/storage/EXAMPLE.md)
|
* [Example](../../staging/libraries/shared/factories/storage/EXAMPLE.md)
|
||||||
|
|
||||||
Event Transformers: transform data derived from Ethereum log events
|
Event Transformers
|
||||||
* [Guide](../../staging/libraries/shared/factories/event/README.md)
|
* [Guide](../../staging/libraries/shared/factories/event/README.md)
|
||||||
* [Example 1](https://github.com/vulcanize/ens_transformers/tree/master/transformers/registar)
|
* [Example 1](https://github.com/vulcanize/ens_transformers/tree/master/transformers/registar)
|
||||||
* [Example 2](https://github.com/vulcanize/ens_transformers/tree/master/transformers/registry)
|
* [Example 2](https://github.com/vulcanize/ens_transformers/tree/master/transformers/registry)
|
||||||
* [Example 3](https://github.com/vulcanize/ens_transformers/tree/master/transformers/resolver)
|
* [Example 3](https://github.com/vulcanize/ens_transformers/tree/master/transformers/resolver)
|
||||||
|
|
||||||
Contract Transformers: transform data derived from Ethereum log events and use it to poll public contract methods
|
Contract Transformers
|
||||||
* [Example 1](https://github.com/vulcanize/account_transformers)
|
* [Example 1](https://github.com/vulcanize/account_transformers)
|
||||||
* [Example 2](https://github.com/vulcanize/ens_transformers/tree/master/transformers/domain_records)
|
* [Example 2](https://github.com/vulcanize/ens_transformers/tree/master/transformers/domain_records)
|
||||||
|
|
||||||
## Preparing custom transformers to work as part of a plugin
|
## Preparing transformers to work as a plugin for composeAndExecute
|
||||||
To plug in an external transformer we need to:
|
To plug in an external transformer we need to:
|
||||||
|
|
||||||
1. Create a package that exports a variable `TransformerInitializer`, `StorageTransformerInitializer`, or `ContractTransformerInitializer` that are of type [TransformerInitializer](../staging/libraries/shared/transformer/event_transformer.go#L33)
|
1. Create a package that exports a variable `TransformerInitializer`, `StorageTransformerInitializer`, or `ContractTransformerInitializer` that are of type [TransformerInitializer](../staging/libraries/shared/transformer/event_transformer.go#L33)
|
||||||
@@ -39,56 +35,16 @@ or [contract](../../staging/libraries/shared/watcher/contract_watcher.go#L68) wa
|
|||||||
* If the base vDB migrations occupy this path as well, they need to be in their `goose fix`ed form
|
* If the base vDB migrations occupy this path as well, they need to be in their `goose fix`ed form
|
||||||
as they are [here](../../staging/db/migrations)
|
as they are [here](../../staging/db/migrations)
|
||||||
|
|
||||||
To update a plugin repository with changes to the core vulcanizedb repository, use your dependency manager to install the desired version of vDB.
|
To update a plugin repository with changes to the core vulcanizedb repository, replace the vulcanizedb vendored in the plugin repo (`plugin_repo/vendor/github.com/vulcanize/vulcanizedb`)
|
||||||
|
with the newly updated version
|
||||||
|
* The entire vendor lib within the vendored vulcanizedb needs to be deleted (`plugin_repo/vendor/github.com/vulcanize/vulcanizedb/vendor`)
|
||||||
|
* These complications arise due to this [conflict](https://github.com/golang/go/issues/20481) between `dep` and Go plugins
|
||||||
|
|
||||||
## Building and Running Custom Transformers
|
## Configuration
|
||||||
### Commands
|
A .toml config file is specified when executing the command:
|
||||||
* The `compose`, `execute`, `composeAndExecute` commands require Go 1.11+ and use [Go plugins](https://golang
|
`./vulcanizedb composeAndExecute --config=./environments/config_name.toml`
|
||||||
.org/pkg/plugin/) which only work on Unix-based systems.
|
|
||||||
|
|
||||||
* There is an ongoing [conflict](https://github.com/golang/go/issues/20481) between Go plugins and the use of vendored
|
The config provides information for composing a set of transformers:
|
||||||
dependencies which imposes certain limitations on how the plugins are built.
|
|
||||||
|
|
||||||
* Separate `compose` and `execute` commands allow pre-building and linking to the pre-built .so file. So, if
|
|
||||||
these are run independently, instead of using `composeAndExecute`, a couple of things need to be considered:
|
|
||||||
* It is necessary that the .so file was built with the same exact dependencies that are present in the execution
|
|
||||||
environment, i.e. we need to `compose` and `execute` the plugin .so file with the same exact version of vulcanizeDB.
|
|
||||||
* The plugin migrations are run during the plugin's composition. As such, if `execute` is used to run a prebuilt .so
|
|
||||||
in a different environment than the one it was composed in, then the database structure will need to be loaded
|
|
||||||
into the environment's Postgres database. This can either be done by manually loading the plugin's schema into
|
|
||||||
Postgres, or by manually running the plugin's migrations.
|
|
||||||
|
|
||||||
* The `compose` and `composeAndExecute` commands assume you are in the vulcanizdb directory located at your system's
|
|
||||||
`$GOPATH`, and that the plugin dependencies are present at their `$GOPATH` directories.
|
|
||||||
|
|
||||||
* The `execute` command does not require the plugin transformer dependencies be located in their `$GOPATH` directories,
|
|
||||||
instead it expects a .so file (of the name specified in the config file) to be in
|
|
||||||
`$GOPATH/src/github.com/vulcanize/vulcanizedb/plugins/` and, as noted above, also expects the plugin db migrations to
|
|
||||||
have already been ran against the database.
|
|
||||||
|
|
||||||
* Usage:
|
|
||||||
* compose: `./vulcanizedb compose --config=environments/config_name.toml`
|
|
||||||
|
|
||||||
* execute: `./vulcanizedb execute --config=environments/config_name.toml`
|
|
||||||
|
|
||||||
* composeAndExecute: `./vulcanizedb composeAndExecute --config=environments/config_name.toml`
|
|
||||||
|
|
||||||
### Flags
|
|
||||||
The `execute` and `composeAndExecute` commands can be passed optional flags to specify the operation of the watchers:
|
|
||||||
|
|
||||||
- `--recheck-headers`/`-r` - specifies whether to re-check headers for events after the header has already been queried for watched logs.
|
|
||||||
Can be useful for redundancy if you suspect that your node is not always returning all desired logs on every query.
|
|
||||||
Argument is expected to be a boolean: e.g. `-r=true`.
|
|
||||||
Defaults to `false`.
|
|
||||||
|
|
||||||
- `query-recheck-interval`/`-q` - specifies interval for re-checking storage diffs that haven been queued for later processing
|
|
||||||
(by default, the storage watched queues storage diffs if transformer execution fails, on the assumption that subsequent data derived from the event transformers may enable us to decode storage keys that we don't recognize right now).
|
|
||||||
Argument is expected to be a duration (integer measured in nanoseconds): e.g. `-q=10m30s` (for 10 minute, 30 second intervals).
|
|
||||||
Defaults to `5m` (5 minutes).
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
A .toml config file is specified when executing the commands.
|
|
||||||
The config provides information for composing a set of transformers from external repositories:
|
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[database]
|
[database]
|
||||||
@@ -151,7 +107,7 @@ The config provides information for composing a set of transformers from externa
|
|||||||
that fetches event logs from an ETH node
|
that fetches event logs from an ETH node
|
||||||
- `eth_contract` indicates the transformer works with the [contract watcher](../staging/libraries/shared/watcher/contract_watcher.go)
|
- `eth_contract` indicates the transformer works with the [contract watcher](../staging/libraries/shared/watcher/contract_watcher.go)
|
||||||
that is made to work with [contract_watcher pkg](../../staging/pkg/contract_watcher)
|
that is made to work with [contract_watcher pkg](../../staging/pkg/contract_watcher)
|
||||||
based transformers which work with either a header or full sync vDB to watch events and poll public methods ([example1](https://github.com/vulcanize/account_transformers/tree/master/transformers/account/light), [example2](https://github.com/vulcanize/ens_transformers/tree/working/transformers/domain_records))
|
based transformers which work with either a light or full sync vDB to watch events and poll public methods ([example1](https://github.com/vulcanize/account_transformers/tree/master/transformers/account/light), [example2](https://github.com/vulcanize/ens_transformers/tree/working/transformers/domain_records))
|
||||||
- `migrations` is the relative path from `repository` to the db migrations directory for the transformer
|
- `migrations` is the relative path from `repository` to the db migrations directory for the transformer
|
||||||
- `rank` determines the order that migrations are ran, with lower ranked migrations running first
|
- `rank` determines the order that migrations are ran, with lower ranked migrations running first
|
||||||
- this is to help isolate any potential conflicts between transformer migrations
|
- this is to help isolate any potential conflicts between transformer migrations
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
# Generic Transformer
|
# contractWatcher
|
||||||
The `contractWatcher` command is a built-in generic contract watcher. It can watch any and all events for a given contract provided the contract's ABI is available.
|
The `contractWatcher` command is a built-in generic contract watcher. It can watch any and all events for a given contract provided the contract's ABI is available.
|
||||||
It also provides some state variable coverage by automating polling of public methods, with some restrictions:
|
It also provides some state variable coverage by automating polling of public methods, with some restrictions:
|
||||||
1. The method must have 2 or less arguments
|
1. The method must have 2 or less arguments
|
||||||
1. The method's arguments must all be of type address or bytes32 (hash)
|
1. The method's arguments must all be of type address or bytes32 (hash)
|
||||||
1. The method must return a single value
|
1. The method must return a single value
|
||||||
|
|
||||||
This command operates in two modes- `header` and `full`- which require a header or full-synced vulcanizeDB, respectively.
|
This command operates in two modes- `light` and `full`- which require a light or full-synced vulcanizeDB, respectively.
|
||||||
|
|
||||||
This command requires the contract ABI be available on Etherscan if it is not provided in the config file by the user.
|
This command requires the contract ABI be available on Etherscan if it is not provided in the config file by the user.
|
||||||
|
|
||||||
If method polling is turned on we require an archival node at the ETH ipc endpoint in our config, whether or not we are operating in `header` or `full` mode.
|
If method polling is turned on we require an archival node at the ETH ipc endpoint in our config, whether or not we are operating in `light` or `full` mode.
|
||||||
Otherwise we only need to connect to a full node.
|
Otherwise we only need to connect to a full node.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
@@ -97,16 +97,16 @@ Modify `./environments/example.toml` to replace the empty `ipcPath` with a path
|
|||||||
This endpoint should be for an archival eth node if we want to perform method polling as this configuration is currently set up to do. To work with a non-archival full node,
|
This endpoint should be for an archival eth node if we want to perform method polling as this configuration is currently set up to do. To work with a non-archival full node,
|
||||||
remove the `balanceOf` method from the `0x8dd5fbce2f6a956c3022ba3663759011dd51e73e` (TrueUSD) contract.
|
remove the `balanceOf` method from the `0x8dd5fbce2f6a956c3022ba3663759011dd51e73e` (TrueUSD) contract.
|
||||||
|
|
||||||
If you are operating a header sync vDB, run:
|
If you are operating a light sync vDB, run:
|
||||||
|
|
||||||
`./vulcanizedb contractWatcher --config=./environments/example.toml --mode=header`
|
`./vulcanizedb contractWatcher --config=./environments/example.toml --mode=light`
|
||||||
|
|
||||||
If instead you are operating a full sync vDB and provided an archival node IPC path, run in full mode:
|
If instead you are operating a full sync vDB and provided an archival node IPC path, run in full mode:
|
||||||
|
|
||||||
`./vulcanizedb contractWatcher --config=./environments/example.toml --mode=full`
|
`./vulcanizedb contractWatcher --config=./environments/example.toml --mode=full`
|
||||||
|
|
||||||
This will run the contractWatcher and configures it to watch the contracts specified in the config file. Note that
|
This will run the contractWatcher and configures it to watch the contracts specified in the config file. Note that
|
||||||
by default we operate in `header` mode but the flag is included here to demonstrate its use.
|
by default we operate in `light` mode but the flag is included here to demonstrate its use.
|
||||||
|
|
||||||
The example config we link to in this example watches two contracts, the ENS Registry (0x314159265dD8dbb310642f98f50C066173C1259b) and TrueUSD (0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E).
|
The example config we link to in this example watches two contracts, the ENS Registry (0x314159265dD8dbb310642f98f50C066173C1259b) and TrueUSD (0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E).
|
||||||
|
|
||||||
@@ -117,43 +117,43 @@ The TrueUSD contract is configured with two events (`Transfer` and `Mint`) and a
|
|||||||
to poll the `balanceOf` method with those addresses at every block. Note that we do not provide an ABI for TrueUSD as its ABI can be fetched from Etherscan.
|
to poll the `balanceOf` method with those addresses at every block. Note that we do not provide an ABI for TrueUSD as its ABI can be fetched from Etherscan.
|
||||||
|
|
||||||
For the ENS contract, it produces and populates a schema with four tables"
|
For the ENS contract, it produces and populates a schema with four tables"
|
||||||
`header_0x314159265dd8dbb310642f98f50c066173c1259b.newowner_event`
|
`light_0x314159265dd8dbb310642f98f50c066173c1259b.newowner_event`
|
||||||
`header_0x314159265dd8dbb310642f98f50c066173c1259b.newresolver_event`
|
`light_0x314159265dd8dbb310642f98f50c066173c1259b.newresolver_event`
|
||||||
`header_0x314159265dd8dbb310642f98f50c066173c1259b.newttl_event`
|
`light_0x314159265dd8dbb310642f98f50c066173c1259b.newttl_event`
|
||||||
`header_0x314159265dd8dbb310642f98f50c066173c1259b.transfer_event`
|
`light_0x314159265dd8dbb310642f98f50c066173c1259b.transfer_event`
|
||||||
|
|
||||||
For the TrusUSD contract, it produces and populates a schema with three tables:
|
For the TrusUSD contract, it produces and populates a schema with three tables:
|
||||||
|
|
||||||
`header_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event`
|
`light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event`
|
||||||
`header_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.mint_event`
|
`light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.mint_event`
|
||||||
`header_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method`
|
`light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method`
|
||||||
|
|
||||||
Column ids and types for these tables are generated based on the event and method argument names and types and method return types, resulting in tables such as:
|
Column ids and types for these tables are generated based on the event and method argument names and types and method return types, resulting in tables such as:
|
||||||
|
|
||||||
Table "header_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event"
|
Table "light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event"
|
||||||
|
|
||||||
| Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
| Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
||||||
|:----------:|:---------------------:|:---------:|:--------:|:--------------------------------------------------------------------------------------------:|:--------:|:------------:|:-----------:|
|
|:----------:|:---------------------:|:---------:|:--------:|:-------------------------------------------------------------------------------------------:|:--------:|:------------:|:-----------:|
|
||||||
| id | integer | | not null | nextval('header_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event_id_seq'::regclass) | plain | | |
|
| id | integer | | not null | nextval('light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.transfer_event_id_seq'::regclass) | plain | | |
|
||||||
| header_id | integer | | not null | | plain | | |
|
| header_id | integer | | not null | | plain | | |
|
||||||
| token_name | character varying(66) | | not null | | extended | | |
|
| token_name | character varying(66) | | not null | | extended | | |
|
||||||
| raw_log | jsonb | | | | extended | | |
|
| raw_log | jsonb | | | | extended | | |
|
||||||
| log_idx | integer | | not null | | plain | | |
|
| log_idx | integer | | not null | | plain | | |
|
||||||
| tx_idx | integer | | not null | | plain | | |
|
| tx_idx | integer | | not null | | plain | | |
|
||||||
| from_ | character varying(66) | | not null | | extended | | |
|
| from_ | character varying(66) | | not null | | extended | | |
|
||||||
| to_ | character varying(66) | | not null | | extended | | |
|
| to_ | character varying(66) | | not null | | extended | | |
|
||||||
| value_ | numeric | | not null | | main | | |
|
| value_ | numeric | | not null | | main | | |
|
||||||
|
|
||||||
|
|
||||||
Table "header_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method"
|
Table "light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method"
|
||||||
|
|
||||||
| Column | Type | Collation | Nullable | Default | Storage | Stats target | Description |
|
| Column | Type | Collation | Nullable | Default | Storage | Stats target | Description |
|
||||||
|:----------:|:---------------------:|:---------:|:--------:|:----------------------------------------------------------------------------------------------:|:--------:|:------------:|:-----------:|
|
|:----------:|:---------------------:|:---------:|:--------:|:-------------------------------------------------------------------------------------------:|:--------:|:------------:|:-----------:|
|
||||||
| id | integer | | not null | nextval('header_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method_id_seq'::regclass) | plain | | |
|
| id | integer | | not null | nextval('light_0x8dd5fbce2f6a956c3022ba3663759011dd51e73e.balanceof_method_id_seq'::regclass) | plain | | |
|
||||||
| token_name | character varying(66) | | not null | | extended | | |
|
| token_name | character varying(66) | | not null | | extended | | |
|
||||||
| block | integer | | not null | | plain | | |
|
| block | integer | | not null | | plain | | |
|
||||||
| who_ | character varying(66) | | not null | | extended | | |
|
| who_ | character varying(66) | | not null | | extended | | |
|
||||||
| returned | numeric | | not null | | main | | |
|
| returned | numeric | | not null | | main | | |
|
||||||
|
|
||||||
The addition of '_' after table names is to prevent collisions with reserved Postgres words.
|
The addition of '_' after table names is to prevent collisions with reserved Postgres words.
|
||||||
|
|
||||||
@@ -1,50 +1,11 @@
|
|||||||
# Contribution guidelines
|
# Contribution guidelines
|
||||||
|
|
||||||
Contributions are welcome! Please open an Issues or Pull Request for any changes.
|
Contributions are welcome! In addition to core contributions, developers are encouraged to build their own custom transformers which
|
||||||
|
can be run together with other custom transformers using the [composeAndExeucte](../../staging/documentation/composeAndExecute.md) command.
|
||||||
In addition to core contributions, developers are encouraged to build their own custom transformers which
|
|
||||||
can be run together with other custom transformers using the [composeAndExecute](../../staging/documentation/custom-transformers.md) command.
|
|
||||||
|
|
||||||
## Pull Requests
|
|
||||||
- `go fmt` is run as part of `make test` and `make integrationtest`, please make sure to check in the format changes.
|
|
||||||
- Ensure that new code is well tested, including integration testing if applicable.
|
|
||||||
- Make sure the build is passing.
|
|
||||||
- Update the README or any [documentation files](./) as necessary. If editing the Readme, please
|
|
||||||
conform to the
|
|
||||||
[standard-readme specification](https://github.com/RichardLitt/standard-readme).
|
|
||||||
- Once a Pull Request has received two approvals it can be merged in by a core developer.
|
|
||||||
|
|
||||||
## Creating a new migration file
|
## Creating a new migration file
|
||||||
1. `make new_migration NAME=add_columnA_to_table1`
|
1. `make new_migration NAME=add_columnA_to_table1`
|
||||||
- This will create a new timestamped migration file in `db/migrations`
|
- This will create a new timestamped migration file in `db/migrations`
|
||||||
1. Write the migration code in the created file, under the respective `goose` pragma
|
1. Write the migration code in the created file, under the respective `goose` pragma
|
||||||
- Goose automatically runs each migration in a transaction; don't add `BEGIN` and `COMMIT` statements.
|
- Goose automatically runs each migration in a transaction; don't add `BEGIN` and `COMMIT` statements.
|
||||||
1. Core migrations should be committed in their `goose fix`ed form. To do this, run `make version_migrations` which
|
1. Core migrations should be committed in their `goose fix`ed form.
|
||||||
converts timestamped migrations to migrations versioned by an incremented integer.
|
|
||||||
|
|
||||||
## Diagrams
|
|
||||||
- Diagrams were created with [draw.io](https://www.draw.io).
|
|
||||||
- To update a diagram:
|
|
||||||
1. Go to [draw.io](https://www.draw.io).
|
|
||||||
1. Click on *File > Open from* and choose the location of the diagram you want to update.
|
|
||||||
1. Once open in draw.io, you may update it.
|
|
||||||
1. Export the diagram to this repository's directory and commit it.
|
|
||||||
|
|
||||||
|
|
||||||
## Generating the Changelog
|
|
||||||
We use [github-changelog-generator](https://github.com/github-changelog-generator/github-changelog-generator) to generate release Changelogs. To be consistent with previous Changelogs, the following flags should be passed to the command:
|
|
||||||
|
|
||||||
```
|
|
||||||
--user vulcanize
|
|
||||||
--project vulcanizedb
|
|
||||||
--token {YOUR_GITHUB_TOKEN}
|
|
||||||
--no-issues
|
|
||||||
--usernames-as-github-logins
|
|
||||||
--since-tag {PREVIOUS_RELEASE_TAG}
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information on why your github token is needed, and how to generate it see [https://github
|
|
||||||
.com/github-changelog-generator/github-changelog-generator#github-token](https://github.com/github-changelog-generator/github-changelog-generator#github-token).
|
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
VulcanizeDB follows the [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct).
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
# Syncing commands
|
|
||||||
These commands are used to sync raw Ethereum data into Postgres, with varying levels of data granularity.
|
|
||||||
|
|
||||||
## headerSync
|
|
||||||
Syncs block headers from a running Ethereum node into the VulcanizeDB table `headers`.
|
|
||||||
- Queries the Ethereum node using RPC calls.
|
|
||||||
- Validates headers from the last 15 blocks to ensure that data is up to date.
|
|
||||||
- Useful when you want a minimal baseline from which to track targeted data on the blockchain (e.g. individual smart
|
|
||||||
contract storage values or event logs).
|
|
||||||
- Handles chain reorgs by [validating the most recent blocks' hashes](../pkg/history/header_validator.go). If the hash is
|
|
||||||
different from what we have already stored in the database, the header record will be updated.
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
- Run: `./vulcanizedb headerSync --config <config.toml> --starting-block-number <block-number>`
|
|
||||||
- The config file must be formatted as follows, and should contain an ipc path to a running Ethereum node:
|
|
||||||
```toml
|
|
||||||
[database]
|
|
||||||
name = "vulcanize_public"
|
|
||||||
hostname = "localhost"
|
|
||||||
user = "vulcanize"
|
|
||||||
password = "vulcanize"
|
|
||||||
port = 5432
|
|
||||||
|
|
||||||
[client]
|
|
||||||
ipcPath = <path to a running Ethereum node>
|
|
||||||
```
|
|
||||||
- Alternatively, the ipc path can be passed as a flag instead `--client-ipcPath`.
|
|
||||||
|
|
||||||
## fullSync
|
|
||||||
Syncs blocks, transactions, receipts and logs from a running Ethereum node into VulcanizeDB tables named
|
|
||||||
`blocks`, `uncles`, `full_sync_transactions`, `full_sync_receipts` and `logs`.
|
|
||||||
- Queries the Ethereum node using RPC calls.
|
|
||||||
- Validates headers from the last 15 blocks to ensure that data is up to date.
|
|
||||||
- Useful when you want to maintain a broad cache of what's happening on the blockchain.
|
|
||||||
- Handles chain reorgs by [validating the most recent blocks' hashes](../pkg/history/header_validator.go). If the hash is
|
|
||||||
different from what we have already stored in the database, the header record will be updated.
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
- Run `./vulcanizedb fullSync --config <config.toml> --starting-block-number <block-number>`
|
|
||||||
- The config file must be formatted as follows, and should contain an ipc path to a running Ethereum node:
|
|
||||||
```toml
|
|
||||||
[database]
|
|
||||||
name = "vulcanize_public"
|
|
||||||
hostname = "localhost"
|
|
||||||
user = "vulcanize"
|
|
||||||
password = "vulcanize"
|
|
||||||
port = 5432
|
|
||||||
|
|
||||||
[client]
|
|
||||||
ipcPath = <path to a running Ethereum node>
|
|
||||||
```
|
|
||||||
- Alternatively, the ipc path can be passed as a flag instead `--client-ipcPath`.
|
|
||||||
|
|
||||||
*Please note, that if you are fast syncing your Ethereum node, wait for the initial sync to finish.*
|
|
||||||
|
|
||||||
## coldImport
|
|
||||||
Syncs VulcanizeDB from Geth's underlying LevelDB datastore and persists Ethereum blocks,
|
|
||||||
transactions, receipts and logs into VulcanizeDB tables named `blocks`, `uncles`,
|
|
||||||
`full_sync_transactions`, `full_sync_receipts` and `logs` respectively.
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
1. Ensure the Ethereum node you're point at is not running, and that it has synced to the desired block height.
|
|
||||||
1. Run `./vulcanizedb coldImport --config <config.toml>`
|
|
||||||
1. Optional flags:
|
|
||||||
- `--starting-block-number <block number>`/`-s <block number>`: block number to start syncing from
|
|
||||||
- `--ending-block-number <block number>`/`-e <block number>`: block number to sync to
|
|
||||||
- `--all`/`-a`: sync all missing blocks
|
|
||||||
|
|
||||||
The config file can be formatted as follows, and must contain the LevelDB path.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[database]
|
|
||||||
name = "vulcanize_public"
|
|
||||||
hostname = "localhost"
|
|
||||||
user = "vulcanize"
|
|
||||||
password = "vulcanize"
|
|
||||||
port = 5432
|
|
||||||
|
|
||||||
[client]
|
|
||||||
leveldbpath = "/Users/user/Library/Ethereum/geth/chaindata"
|
|
||||||
```
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 52 KiB |
@@ -1,34 +0,0 @@
|
|||||||
# Postgraphile
|
|
||||||
|
|
||||||
You can expose VulcanizeDB data via [Postgraphile](https://github.com/graphile/postgraphile).
|
|
||||||
Check out [their documentation](https://www.graphile.org/postgraphile/) for the most up-to-date instructions on installing, running, and customizing Postgraphile.
|
|
||||||
|
|
||||||
## Simple Setup
|
|
||||||
|
|
||||||
As of April 30, 2019, you can run Postgraphile pointed at the default `vulcanize_public` database with the following commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install -g postgraphile
|
|
||||||
postgraphile --connection postgres://localhost/vulcanize_public --schema=public,custom --disable-default-mutations --no-ignore-rbac
|
|
||||||
```
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
- `--connection` specifies the database. The above command connects to the default `vulcanize_public` database
|
|
||||||
defined in [the example config](../environments/public.toml.example).
|
|
||||||
- `--schema` defines what schema(s) to expose. The above exposes the `public` schema (for core VulcanizeDB data) as well as a `custom` schema (where `custom` is the name of a schema defined in executed transformers).
|
|
||||||
- `--disable-default-mutations` prevents Postgraphile from exposing create, update, and delete operations on your data, which are otherwise enabled by default.
|
|
||||||
- `--no-ignore-rbac` ensures that Postgraphile will only expose the tables, columns, fields, and query functions that the user has explicit access to.
|
|
||||||
|
|
||||||
## Customizing Postgraphile
|
|
||||||
|
|
||||||
By default, Postgraphile will expose queries for all tables defined in your chosen database/schema(s), including [filtering](https://www.graphile.org/postgraphile/filtering/) and [auto-discovered relations](https://www.graphile.org/postgraphile/relations/).
|
|
||||||
|
|
||||||
If you'd like to expose more customized windows into your data, there are some techniques you can apply when writing migrations:
|
|
||||||
|
|
||||||
- [Computed columns](https://www.graphile.org/postgraphile/computed-columns/) enable you to derive additional fields from types defined in your database.
|
|
||||||
For example, you could write a function to expose a block header's state root over Postgraphile with a computed column - without modifying the `public.headers` table.
|
|
||||||
- [Custom queries](https://www.graphile.org/postgraphile/custom-queries/) enable you to provide on-demand access to more complex data (e.g. the product of joining and filtering several tables' data based on a passed argument).
|
|
||||||
For example, you could write a custom query to get the block timestamp for every transaction originating from a given address.
|
|
||||||
- [Subscriptions](https://www.graphile.org/postgraphile/subscriptions/) enable you to publish data as it is coming into your database.
|
|
||||||
|
|
||||||
The above list is not exhaustive - please see the Postgraphile documentation for a more comprehensive and up-to-date description of available features.
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Syncing commands
|
||||||
|
These commands are used to sync raw Ethereum data into Postgres.
|
||||||
|
|
||||||
|
## lightSync
|
||||||
|
Syncs VulcanizeDB with the configured Ethereum node, populating only block headers.
|
||||||
|
This command is useful when you want a minimal baseline from which to track targeted data on the blockchain (e.g. individual smart contract storage values or event logs).
|
||||||
|
1. Start Ethereum node
|
||||||
|
1. In a separate terminal start VulcanizeDB:
|
||||||
|
- `./vulcanizedb lightSync --config <config.toml> --starting-block-number <block-number>`
|
||||||
|
|
||||||
|
## sync
|
||||||
|
Syncs VulcanizeDB with the configured Ethereum node, populating blocks, transactions, receipts, and logs.
|
||||||
|
This command is useful when you want to maintain a broad cache of what's happening on the blockchain.
|
||||||
|
1. Start Ethereum node (**if fast syncing your Ethereum node, wait for initial sync to finish**)
|
||||||
|
1. In a separate terminal start VulcanizeDB:
|
||||||
|
- `./vulcanizedb sync --config <config.toml> --starting-block-number <block-number>`
|
||||||
|
|
||||||
|
## coldImport
|
||||||
|
Sync VulcanizeDB from the LevelDB underlying a Geth node.
|
||||||
|
1. Assure node is not running, and that it has synced to the desired block height.
|
||||||
|
1. Start vulcanize_db
|
||||||
|
- `./vulcanizedb coldImport --config <config.toml>`
|
||||||
|
1. Optional flags:
|
||||||
|
- `--starting-block-number <block number>`/`-s <block number>`: block number to start syncing from
|
||||||
|
- `--ending-block-number <block number>`/`-e <block number>`: block number to sync to
|
||||||
|
- `--all`/`-a`: sync all missing blocks
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
module github.com/vulcanize/vulcanizedb
|
|
||||||
|
|
||||||
go 1.12
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/allegro/bigcache v1.2.1 // indirect
|
|
||||||
github.com/aristanetworks/goarista v0.0.0-20190712234253-ed1100a1c015 // indirect
|
|
||||||
github.com/dave/jennifer v1.3.0
|
|
||||||
github.com/deckarep/golang-set v1.7.1 // indirect
|
|
||||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
|
||||||
github.com/elastic/gosigar v0.10.4 // indirect
|
|
||||||
github.com/ethereum/go-ethereum v1.9.5
|
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
|
||||||
github.com/gorilla/websocket v1.4.1 // indirect
|
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20190724201507-010347b5f9e6 // indirect
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1
|
|
||||||
github.com/hpcloud/tail v1.0.0
|
|
||||||
github.com/huin/goupnp v1.0.0 // indirect
|
|
||||||
github.com/jackpal/go-nat-pmp v1.0.1 // indirect
|
|
||||||
github.com/jmoiron/sqlx v0.0.0-20181024163419-82935fac6c1a
|
|
||||||
github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8 // indirect
|
|
||||||
github.com/lib/pq v1.0.0
|
|
||||||
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/mitchellh/go-homedir v1.1.0
|
|
||||||
github.com/olekukonko/tablewriter v0.0.1 // indirect
|
|
||||||
github.com/onsi/ginkgo v1.7.0
|
|
||||||
github.com/onsi/gomega v1.4.3
|
|
||||||
github.com/pborman/uuid v1.2.0 // indirect
|
|
||||||
github.com/pressly/goose v2.6.0+incompatible
|
|
||||||
github.com/prometheus/tsdb v0.10.0 // indirect
|
|
||||||
github.com/rjeczalik/notify v0.9.2 // indirect
|
|
||||||
github.com/rs/cors v1.7.0 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.2.0
|
|
||||||
github.com/spf13/cobra v0.0.3
|
|
||||||
github.com/spf13/viper v1.3.2
|
|
||||||
github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 // indirect
|
|
||||||
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 // indirect
|
|
||||||
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
|
|
||||||
github.com/syndtr/goleveldb 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
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
|
||||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff // indirect
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
|
|
||||||
)
|
|
||||||
@@ -1,307 +0,0 @@
|
|||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
|
||||||
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/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/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
|
||||||
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/go.mod h1:CUfFqErhFhXneJendyQ/rRcuA8kH8JxHvYnbOozmlCU=
|
|
||||||
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 v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
|
||||||
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/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
|
||||||
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/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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
|
|
||||||
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
|
||||||
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
|
|
||||||
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
|
||||||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
|
|
||||||
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/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
|
|
||||||
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/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
|
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
|
|
||||||
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-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
|
|
||||||
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/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/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
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.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
|
||||||
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/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/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
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.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-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.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
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/howeyc/fsnotify v0.9.0 h1:0gtV5JmOKH4A8SsFxG2BczSeXWWPvcMT0euZt5gDAxY=
|
|
||||||
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/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
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/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
|
||||||
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/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/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-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/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
|
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
|
||||||
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/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/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
|
||||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
|
||||||
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/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/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
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.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/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/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
|
||||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
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.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/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/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
|
||||||
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
|
|
||||||
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/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
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.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/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
|
||||||
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/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/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.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/pressly/goose v2.6.0+incompatible h1:3f8zIQ8rfgP9tyI0Hmcs2YNAqUCL1c+diLe3iU8Qd/k=
|
|
||||||
github.com/pressly/goose v2.6.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8=
|
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
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.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/tsdb v0.9.1/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
|
|
||||||
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.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.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/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
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/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
|
||||||
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.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/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
|
||||||
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/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
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.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/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
|
|
||||||
github.com/steakknife/bloomfilter v0.0.0-20180906043351-99ee86d9200f/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
|
|
||||||
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-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.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
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/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/syndtr/goleveldb v0.0.0-20180815032940-ae2bd5eed72d/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
|
|
||||||
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.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/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/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-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-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
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/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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
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-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/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-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-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/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/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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
|
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
|
|
||||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff h1:uuol9OUzSvZntY1v963NAbVd7A+PHLMz1FlCe3Lorcs=
|
|
||||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190709231704-1e4459ed25ff/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
@@ -38,7 +38,7 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
|
|
||||||
Describe("Getting a contract attribute", func() {
|
Describe("Getting a contract attribute", func() {
|
||||||
It("retrieves the event log for a specific block and contract", func() {
|
It("retrieves the event log for a specific block and contract", func() {
|
||||||
expectedLogZero := core.FullSyncLog{
|
expectedLogZero := core.Log{
|
||||||
BlockNumber: 4703824,
|
BlockNumber: 4703824,
|
||||||
TxHash: "0xf896bfd1eb539d881a1a31102b78de9f25cd591bf1fe1924b86148c0b205fd5d",
|
TxHash: "0xf896bfd1eb539d881a1a31102b78de9f25cd591bf1fe1924b86148c0b205fd5d",
|
||||||
Address: "0xd26114cd6ee289accf82350c8d8487fedb8a0c07",
|
Address: "0xd26114cd6ee289accf82350c8d8487fedb8a0c07",
|
||||||
@@ -59,7 +59,7 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
contract := testing.SampleContract()
|
contract := testing.SampleContract()
|
||||||
|
|
||||||
logs, err := blockChain.GetFullSyncLogs(contract, big.NewInt(4703824), nil)
|
logs, err := blockChain.GetLogs(contract, big.NewInt(4703824), nil)
|
||||||
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(len(logs)).To(Equal(3))
|
Expect(len(logs)).To(Equal(3))
|
||||||
@@ -76,7 +76,7 @@ var _ = Describe("Reading contracts", func() {
|
|||||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
|
|
||||||
logs, err := blockChain.GetFullSyncLogs(core.Contract{Hash: "0x123"}, big.NewInt(4703824), nil)
|
logs, err := blockChain.GetLogs(core.Contract{Hash: "0x123"}, big.NewInt(4703824), nil)
|
||||||
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(len(logs)).To(Equal(0))
|
Expect(len(logs)).To(Equal(0))
|
||||||
|
|||||||
@@ -1,19 +1,3 @@
|
|||||||
// 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 (
|
||||||
@@ -302,7 +286,7 @@ var _ = Describe("contractWatcher full transformer", func() {
|
|||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
log := test_helpers.HeaderSyncNewOwnerLog{}
|
log := test_helpers.LightNewOwnerLog{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.newowner_event", ensAddr)).StructScan(&log)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.newowner_event", ensAddr)).StructScan(&log)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("does not exist"))
|
Expect(err.Error()).To(ContainSubstring("does not exist"))
|
||||||
|
|||||||
+24
-47
@@ -1,19 +1,3 @@
|
|||||||
// 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 (
|
||||||
@@ -25,7 +9,7 @@ import (
|
|||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/config"
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/header/transformer"
|
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/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"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks"
|
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/helpers/test_helpers/mocks"
|
||||||
@@ -34,7 +18,7 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("contractWatcher headerSync transformer", func() {
|
var _ = Describe("contractWatcher light transformer", func() {
|
||||||
var db *postgres.DB
|
var db *postgres.DB
|
||||||
var err error
|
var err error
|
||||||
var blockChain core.BlockChain
|
var blockChain core.BlockChain
|
||||||
@@ -65,13 +49,6 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
c, ok := t.Contracts[tusdAddr]
|
c, ok := t.Contracts[tusdAddr]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
|
|
||||||
// TODO: Fix this
|
|
||||||
// This test sometimes randomly fails because
|
|
||||||
// for some reason the starting block number is not updated from
|
|
||||||
// its original value (5197514) to the block number (6194632)
|
|
||||||
// of the earliest header (mocks.MockHeader1) in the repository
|
|
||||||
// It is not clear how this happens without one of the above insertErrs
|
|
||||||
// having been thrown and without any errors thrown during the Init() call
|
|
||||||
Expect(c.StartingBlock).To(Equal(int64(6194632)))
|
Expect(c.StartingBlock).To(Equal(int64(6194632)))
|
||||||
Expect(c.Abi).To(Equal(constants.TusdAbiString))
|
Expect(c.Abi).To(Equal(constants.TusdAbiString))
|
||||||
Expect(c.Name).To(Equal("TrueUSD"))
|
Expect(c.Name).To(Equal("TrueUSD"))
|
||||||
@@ -123,8 +100,8 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
log := test_helpers.HeaderSyncTransferLog{}
|
log := test_helpers.LightTransferLog{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.transfer_event", tusdAddr)).StructScan(&log)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.transfer_event", tusdAddr)).StructScan(&log)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
// We don't know vulcID, so compare individual fields instead of complete structures
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
Expect(log.HeaderID).To(Equal(headerID))
|
Expect(log.HeaderID).To(Equal(headerID))
|
||||||
@@ -191,12 +168,12 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
res := test_helpers.BalanceOf{}
|
res := test_helpers.BalanceOf{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0x1062a747393198f70F71ec65A582423Dba7E5Ab3' AND block = '6791669'", tusdAddr)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x1062a747393198f70F71ec65A582423Dba7E5Ab3' AND block = '6791669'", tusdAddr)).StructScan(&res)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(res.Balance).To(Equal("55849938025000000000000"))
|
Expect(res.Balance).To(Equal("55849938025000000000000"))
|
||||||
Expect(res.TokenName).To(Equal("TrueUSD"))
|
Expect(res.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6791669'", tusdAddr)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6791669'", tusdAddr)).StructScan(&res)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
||||||
})
|
})
|
||||||
@@ -231,8 +208,8 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(t.Start).To(Equal(int64(6885698)))
|
Expect(t.Start).To(Equal(int64(6885698)))
|
||||||
|
|
||||||
log := test_helpers.HeaderSyncNewOwnerLog{}
|
log := test_helpers.LightNewOwnerLog{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.newowner_event", ensAddr)).StructScan(&log)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&log)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
// We don't know vulcID, so compare individual fields instead of complete structures
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
Expect(log.HeaderID).To(Equal(headerID))
|
Expect(log.HeaderID).To(Equal(headerID))
|
||||||
@@ -283,17 +260,17 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
res := test_helpers.Owner{}
|
res := test_helpers.Owner{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(res.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
Expect(res.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
Expect(res.TokenName).To(Equal(""))
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(res.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
Expect(res.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
||||||
Expect(res.TokenName).To(Equal(""))
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x9THIS110dcc444fIS242510c09bbAbe21aFAKEcacNODE82f7b843HASH61ba391' AND block = '6885696'", ensAddr)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x9THIS110dcc444fIS242510c09bbAbe21aFAKEcacNODE82f7b843HASH61ba391' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
||||||
})
|
})
|
||||||
@@ -310,8 +287,8 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
log := test_helpers.HeaderSyncNewOwnerLog{}
|
log := test_helpers.LightNewOwnerLog{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.newowner_event", ensAddr)).StructScan(&log)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&log)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("does not exist"))
|
Expect(err.Error()).To(ContainSubstring("does not exist"))
|
||||||
})
|
})
|
||||||
@@ -332,12 +309,12 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
res := test_helpers.Owner{}
|
res := test_helpers.Owner{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(res.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
Expect(res.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
Expect(res.TokenName).To(Equal(""))
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&res)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
||||||
})
|
})
|
||||||
@@ -361,16 +338,16 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(t.Start).To(Equal(int64(6885702)))
|
Expect(t.Start).To(Equal(int64(6885702)))
|
||||||
|
|
||||||
newOwnerLog := test_helpers.HeaderSyncNewOwnerLog{}
|
newOwnerLog := test_helpers.LightNewOwnerLog{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.newowner_event", ensAddr)).StructScan(&newOwnerLog)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&newOwnerLog)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
// We don't know vulcID, so compare individual fields instead of complete structures
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
Expect(newOwnerLog.Node).To(Equal("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"))
|
Expect(newOwnerLog.Node).To(Equal("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"))
|
||||||
Expect(newOwnerLog.Label).To(Equal("0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047"))
|
Expect(newOwnerLog.Label).To(Equal("0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047"))
|
||||||
Expect(newOwnerLog.Owner).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
Expect(newOwnerLog.Owner).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
|
|
||||||
transferLog := test_helpers.HeaderSyncTransferLog{}
|
transferLog := test_helpers.LightTransferLog{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.transfer_event", tusdAddr)).StructScan(&transferLog)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.transfer_event", tusdAddr)).StructScan(&transferLog)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
// We don't know vulcID, so compare individual fields instead of complete structures
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
Expect(transferLog.From).To(Equal("0x8cA465764873E71CEa525F5EB6AE973d650c22C2"))
|
Expect(transferLog.From).To(Equal("0x8cA465764873E71CEa525F5EB6AE973d650c22C2"))
|
||||||
@@ -433,27 +410,27 @@ var _ = Describe("contractWatcher headerSync transformer", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
owner := test_helpers.Owner{}
|
owner := test_helpers.Owner{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(owner.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
Expect(owner.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
Expect(owner.TokenName).To(Equal(""))
|
Expect(owner.TokenName).To(Equal(""))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(owner.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
Expect(owner.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
||||||
Expect(owner.TokenName).To(Equal(""))
|
Expect(owner.TokenName).To(Equal(""))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ceMADEUPaaf4HASHc186badTHItransformers.8IS625bFAKE' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ceMADEUPaaf4HASHc186badTHItransformers.8IS625bFAKE' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
||||||
|
|
||||||
bal := test_helpers.BalanceOf{}
|
bal := test_helpers.BalanceOf{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0x8cA465764873E71CEa525F5EB6AE973d650c22C2' AND block = '6885701'", tusdAddr)).StructScan(&bal)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x8cA465764873E71CEa525F5EB6AE973d650c22C2' AND block = '6885701'", tusdAddr)).StructScan(&bal)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal.Balance).To(Equal("1954436000000000000000"))
|
Expect(bal.Balance).To(Equal("1954436000000000000000"))
|
||||||
Expect(bal.TokenName).To(Equal("TrueUSD"))
|
Expect(bal.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6885701'", tusdAddr)).StructScan(&bal)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6885701'", tusdAddr)).StructScan(&bal)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
Expect(err.Error()).To(ContainSubstring("no rows in result set"))
|
||||||
})
|
})
|
||||||
@@ -130,10 +130,10 @@ var _ = Describe("Poller", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("Header sync mode", func() {
|
Describe("Light sync mode", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
db, bc = test_helpers.SetupDBandBC()
|
db, bc = test_helpers.SetupDBandBC()
|
||||||
contractPoller = poller.NewPoller(bc, db, types.HeaderSync)
|
contractPoller = poller.NewPoller(bc, db, types.LightSync)
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("PollContract", func() {
|
Describe("PollContract", func() {
|
||||||
@@ -148,22 +148,22 @@ var _ = Describe("Poller", func() {
|
|||||||
|
|
||||||
scanStruct := test_helpers.BalanceOf{}
|
scanStruct := test_helpers.BalanceOf{}
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0xfE9e8709d3215310075d67E3ed32A380CCf451C8' AND block = '6707322'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0xfE9e8709d3215310075d67E3ed32A380CCf451C8' AND block = '6707322'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(scanStruct.Balance).To(Equal("66386309548896882859581786"))
|
Expect(scanStruct.Balance).To(Equal("66386309548896882859581786"))
|
||||||
Expect(scanStruct.TokenName).To(Equal("TrueUSD"))
|
Expect(scanStruct.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0xfE9e8709d3215310075d67E3ed32A380CCf451C8' AND block = '6707323'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0xfE9e8709d3215310075d67E3ed32A380CCf451C8' AND block = '6707323'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(scanStruct.Balance).To(Equal("66386309548896882859581786"))
|
Expect(scanStruct.Balance).To(Equal("66386309548896882859581786"))
|
||||||
Expect(scanStruct.TokenName).To(Equal("TrueUSD"))
|
Expect(scanStruct.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE' AND block = '6707322'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE' AND block = '6707322'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(scanStruct.Balance).To(Equal("17982350181394112023885864"))
|
Expect(scanStruct.Balance).To(Equal("17982350181394112023885864"))
|
||||||
Expect(scanStruct.TokenName).To(Equal("TrueUSD"))
|
Expect(scanStruct.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE' AND block = '6707323'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x3f5CE5FBFe3E9af3971dD833D26bA9b5C936f0bE' AND block = '6707323'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(scanStruct.Balance).To(Equal("17982350181394112023885864"))
|
Expect(scanStruct.Balance).To(Equal("17982350181394112023885864"))
|
||||||
Expect(scanStruct.TokenName).To(Equal("TrueUSD"))
|
Expect(scanStruct.TokenName).To(Equal("TrueUSD"))
|
||||||
@@ -180,12 +180,12 @@ var _ = Describe("Poller", func() {
|
|||||||
|
|
||||||
scanStruct := test_helpers.Owner{}
|
scanStruct := test_helpers.Owner{}
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x7e74a86b6e146964fb965db04dc2590516da77f720bb6759337bf5632415fd86' AND block = '6885877'", constants.EnsContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x7e74a86b6e146964fb965db04dc2590516da77f720bb6759337bf5632415fd86' AND block = '6885877'", constants.EnsContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(scanStruct.Address).To(Equal("0x546aA2EaE2514494EeaDb7bbb35243348983C59d"))
|
Expect(scanStruct.Address).To(Equal("0x546aA2EaE2514494EeaDb7bbb35243348983C59d"))
|
||||||
Expect(scanStruct.TokenName).To(Equal("ENS-Registry"))
|
Expect(scanStruct.TokenName).To(Equal("ENS-Registry"))
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885877'", constants.EnsContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885877'", constants.EnsContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(scanStruct.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
Expect(scanStruct.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
Expect(scanStruct.TokenName).To(Equal("ENS-Registry"))
|
Expect(scanStruct.TokenName).To(Equal("ENS-Registry"))
|
||||||
@@ -202,7 +202,7 @@ var _ = Describe("Poller", func() {
|
|||||||
|
|
||||||
scanStruct := test_helpers.BalanceOf{}
|
scanStruct := test_helpers.BalanceOf{}
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.balanceof_method WHERE who_ = '0xfE9e8709d3215310075d67E3ed32A380CCf451C8' AND block = '6707322'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0xfE9e8709d3215310075d67E3ed32A380CCf451C8' AND block = '6707322'", constants.TusdContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ var _ = Describe("Poller", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
scanStruct := test_helpers.Resolver{}
|
scanStruct := test_helpers.Resolver{}
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.resolver_method WHERE node_ = '0x495b6e6efdedb750aa519919b5cf282bdaa86067b82a2293a3ff5723527141e8' AND block = '6921967'", constants.EnsContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.resolver_method WHERE node_ = '0x495b6e6efdedb750aa519919b5cf282bdaa86067b82a2293a3ff5723527141e8' AND block = '6921967'", constants.EnsContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(scanStruct.Address).To(Equal("0x5FfC014343cd971B7eb70732021E26C35B744cc4"))
|
Expect(scanStruct.Address).To(Equal("0x5FfC014343cd971B7eb70732021E26C35B744cc4"))
|
||||||
Expect(scanStruct.TokenName).To(Equal("ENS-Registry"))
|
Expect(scanStruct.TokenName).To(Equal("ENS-Registry"))
|
||||||
@@ -225,13 +225,13 @@ var _ = Describe("Poller", func() {
|
|||||||
|
|
||||||
test_helpers.TearDown(db)
|
test_helpers.TearDown(db)
|
||||||
db, bc = test_helpers.SetupDBandBC()
|
db, bc = test_helpers.SetupDBandBC()
|
||||||
contractPoller = poller.NewPoller(bc, db, types.HeaderSync)
|
contractPoller = poller.NewPoller(bc, db, types.LightSync)
|
||||||
|
|
||||||
con.Piping = true
|
con.Piping = true
|
||||||
err = contractPoller.PollContract(*con, 6921968)
|
err = contractPoller.PollContract(*con, 6921968)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM header_%s.resolver_method WHERE node_ = '0x495b6e6efdedb750aa519919b5cf282bdaa86067b82a2293a3ff5723527141e8' AND block = '6921967'", constants.EnsContractAddress)).StructScan(&scanStruct)
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.resolver_method WHERE node_ = '0x495b6e6efdedb750aa519919b5cf282bdaa86067b82a2293a3ff5723527141e8' AND block = '6921967'", constants.EnsContractAddress)).StructScan(&scanStruct)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(scanStruct.Address).To(Equal("0x5FfC014343cd971B7eb70732021E26C35B744cc4"))
|
Expect(scanStruct.Address).To(Equal("0x5FfC014343cd971B7eb70732021E26C35B744cc4"))
|
||||||
Expect(scanStruct.TokenName).To(Equal("ENS-Registry"))
|
Expect(scanStruct.TokenName).To(Equal("ENS-Registry"))
|
||||||
|
|||||||
@@ -17,15 +17,17 @@
|
|||||||
package chunker
|
package chunker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
|
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Chunker interface {
|
type Chunker interface {
|
||||||
AddConfig(transformerConfig transformer.EventTransformerConfig)
|
AddConfigs(transformerConfigs []shared_t.EventTransformerConfig)
|
||||||
ChunkLogs(logs []core.HeaderSyncLog) map[string][]core.HeaderSyncLog
|
ChunkLogs(logs []types.Log) map[string][]types.Log
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogChunker struct {
|
type LogChunker struct {
|
||||||
@@ -42,25 +44,27 @@ func NewLogChunker() *LogChunker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configures the chunker by adding one config with more addresses and topics to consider.
|
// Configures the chunker by adding more addreses and topics to consider.
|
||||||
func (chunker *LogChunker) AddConfig(transformerConfig transformer.EventTransformerConfig) {
|
func (chunker *LogChunker) AddConfigs(transformerConfigs []shared_t.EventTransformerConfig) {
|
||||||
for _, address := range transformerConfig.ContractAddresses {
|
for _, config := range transformerConfigs {
|
||||||
var lowerCaseAddress = strings.ToLower(address)
|
for _, address := range config.ContractAddresses {
|
||||||
chunker.AddressToNames[lowerCaseAddress] = append(chunker.AddressToNames[lowerCaseAddress], transformerConfig.TransformerName)
|
var lowerCaseAddress = strings.ToLower(address)
|
||||||
chunker.NameToTopic0[transformerConfig.TransformerName] = common.HexToHash(transformerConfig.Topic)
|
chunker.AddressToNames[lowerCaseAddress] = append(chunker.AddressToNames[lowerCaseAddress], config.TransformerName)
|
||||||
|
chunker.NameToTopic0[config.TransformerName] = common.HexToHash(config.Topic)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Goes through a slice of logs, associating relevant logs (matching addresses and topic) with transformers
|
// Goes through an array of logs, associating relevant logs (matching addresses and topic) with transformers
|
||||||
func (chunker *LogChunker) ChunkLogs(logs []core.HeaderSyncLog) map[string][]core.HeaderSyncLog {
|
func (chunker *LogChunker) ChunkLogs(logs []types.Log) map[string][]types.Log {
|
||||||
chunks := map[string][]core.HeaderSyncLog{}
|
chunks := map[string][]types.Log{}
|
||||||
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.Log.Address.Hex())]
|
relevantTransformers := chunker.AddressToNames[strings.ToLower(log.Address.String())]
|
||||||
|
|
||||||
for _, t := range relevantTransformers {
|
for _, transformer := range relevantTransformers {
|
||||||
if chunker.NameToTopic0[t] == log.Log.Topics[0] {
|
if chunker.NameToTopic0[transformer] == log.Topics[0] {
|
||||||
chunks[t] = append(chunks[t], log)
|
chunks[transformer] = append(chunks[transformer], log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,39 +21,38 @@ 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"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
shared_t "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() {
|
||||||
chunker = chunk.NewLogChunker()
|
configA := shared_t.EventTransformerConfig{
|
||||||
|
|
||||||
configA := transformer.EventTransformerConfig{
|
|
||||||
TransformerName: "TransformerA",
|
TransformerName: "TransformerA",
|
||||||
ContractAddresses: []string{"0x00000000000000000000000000000000000000A1", "0x00000000000000000000000000000000000000A2"},
|
ContractAddresses: []string{"0x00000000000000000000000000000000000000A1", "0x00000000000000000000000000000000000000A2"},
|
||||||
Topic: "0xA",
|
Topic: "0xA",
|
||||||
}
|
}
|
||||||
chunker.AddConfig(configA)
|
configB := shared_t.EventTransformerConfig{
|
||||||
|
|
||||||
configB := transformer.EventTransformerConfig{
|
|
||||||
TransformerName: "TransformerB",
|
TransformerName: "TransformerB",
|
||||||
ContractAddresses: []string{"0x00000000000000000000000000000000000000B1"},
|
ContractAddresses: []string{"0x00000000000000000000000000000000000000B1"},
|
||||||
Topic: "0xB",
|
Topic: "0xB",
|
||||||
}
|
}
|
||||||
chunker.AddConfig(configB)
|
|
||||||
|
|
||||||
configC := transformer.EventTransformerConfig{
|
configC := shared_t.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() {
|
||||||
@@ -72,26 +71,26 @@ var _ = Describe("Log chunker", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("AddConfig", func() {
|
Describe("AddConfigs", func() {
|
||||||
It("can add more configs later", func() {
|
It("can add more configs later", func() {
|
||||||
configD := transformer.EventTransformerConfig{
|
configD := shared_t.EventTransformerConfig{
|
||||||
TransformerName: "TransformerD",
|
TransformerName: "TransformerD",
|
||||||
ContractAddresses: []string{"0x000000000000000000000000000000000000000D"},
|
ContractAddresses: []string{"0x000000000000000000000000000000000000000D"},
|
||||||
Topic: "0xD",
|
Topic: "0xD",
|
||||||
}
|
}
|
||||||
chunker.AddConfig(configD)
|
chunker.AddConfigs([]shared_t.EventTransformerConfig{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 := transformer.EventTransformerConfig{
|
configD := shared_t.EventTransformerConfig{
|
||||||
TransformerName: "TransformerD",
|
TransformerName: "TransformerD",
|
||||||
ContractAddresses: []string{"0x000000000000000000000000000000000000000D"},
|
ContractAddresses: []string{"0x000000000000000000000000000000000000000D"},
|
||||||
Topic: "0xD",
|
Topic: "0xD",
|
||||||
}
|
}
|
||||||
chunker.AddConfig(configD)
|
chunker.AddConfigs([]shared_t.EventTransformerConfig{configD})
|
||||||
|
|
||||||
Expect(chunker.AddressToNames["0x000000000000000000000000000000000000000d"]).To(Equal([]string{"TransformerD"}))
|
Expect(chunker.AddressToNames["0x000000000000000000000000000000000000000d"]).To(Equal([]string{"TransformerD"}))
|
||||||
})
|
})
|
||||||
@@ -99,7 +98,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 := []core.HeaderSyncLog{log1, log2, log3, log4, log5}
|
logs := []types.Log{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)))
|
||||||
@@ -111,53 +110,43 @@ var _ = Describe("Log chunker", func() {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// Match TransformerA
|
// Match TransformerA
|
||||||
log1 = core.HeaderSyncLog{
|
log1 = types.Log{
|
||||||
Log: types.Log{
|
Address: common.HexToAddress("0xA1"),
|
||||||
Address: common.HexToAddress("0xA1"),
|
Topics: []common.Hash{
|
||||||
Topics: []common.Hash{
|
common.HexToHash("0xA"),
|
||||||
common.HexToHash("0xA"),
|
common.HexToHash("0xLogTopic1"),
|
||||||
common.HexToHash("0xLogTopic1"),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Match TransformerA address, but not topic0
|
// Match TransformerA address, but not topic0
|
||||||
log2 = core.HeaderSyncLog{
|
log2 = types.Log{
|
||||||
Log: types.Log{
|
Address: common.HexToAddress("0xA1"),
|
||||||
Address: common.HexToAddress("0xA1"),
|
Topics: []common.Hash{
|
||||||
Topics: []common.Hash{
|
common.HexToHash("0xB"),
|
||||||
common.HexToHash("0xB"),
|
common.HexToHash("0xLogTopic2"),
|
||||||
common.HexToHash("0xLogTopic2"),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Match TransformerA topic, but TransformerB address
|
// Match TransformerA topic, but TransformerB address
|
||||||
log3 = core.HeaderSyncLog{
|
log3 = types.Log{
|
||||||
Log: types.Log{
|
Address: common.HexToAddress("0xB1"),
|
||||||
Address: common.HexToAddress("0xB1"),
|
Topics: []common.Hash{
|
||||||
Topics: []common.Hash{
|
common.HexToHash("0xA"),
|
||||||
common.HexToHash("0xA"),
|
common.HexToHash("0xLogTopic3"),
|
||||||
common.HexToHash("0xLogTopic3"),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Match TransformerA, with the other address
|
// Match TransformerA, with the other address
|
||||||
log4 = core.HeaderSyncLog{
|
log4 = types.Log{
|
||||||
Log: types.Log{
|
Address: common.HexToAddress("0xA2"),
|
||||||
Address: common.HexToAddress("0xA2"),
|
Topics: []common.Hash{
|
||||||
Topics: []common.Hash{
|
common.HexToHash("0xA"),
|
||||||
common.HexToHash("0xA"),
|
common.HexToHash("0xLogTopic4"),
|
||||||
common.HexToHash("0xLogTopic4"),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Match TransformerC, which shares address with TransformerA
|
// Match TransformerC, which shares address with TransformerA
|
||||||
log5 = core.HeaderSyncLog{
|
log5 = types.Log{
|
||||||
Log: types.Log{
|
Address: common.HexToAddress("0xA2"),
|
||||||
Address: common.HexToAddress("0xA2"),
|
Topics: []common.Hash{
|
||||||
Topics: []common.Hash{
|
common.HexToHash("0xC"),
|
||||||
common.HexToHash("0xC"),
|
common.HexToHash("0xLogTopic5"),
|
||||||
common.HexToHash("0xLogTopic5"),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ type TransformerExecution bool
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
HeaderRecheck TransformerExecution = true
|
HeaderRecheck TransformerExecution = true
|
||||||
HeaderUnchecked TransformerExecution = false
|
HeaderMissing TransformerExecution = false
|
||||||
RecheckHeaderCap = int64(5)
|
RecheckHeaderCap = "4"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
One approach VulcanizeDB takes to caching and indexing smart contracts is to watch contract events emitted in receipt logs.
|
One approach VulcanizeDB takes to caching and indexing smart contracts is to watch contract events emitted in receipt logs.
|
||||||
|
|
||||||
With a header synced vDB we can watch events by iterating over headers retrieved from the synced `headers` table and using these headers to
|
With a light synced vDB we can watch events by iterating over headers retrieved from the synced `headers` table and using these headers to
|
||||||
fetch and verify relevant event logs from a full Ethereum node, keeping track of which headers we have checked for which events
|
fetch and verify relevant event logs from a full Ethereum node, keeping track of which headers we have checked for which events
|
||||||
with our `checked_headers` table.
|
with our `checked_headers` table.
|
||||||
|
|
||||||
## Assumptions
|
## Assumptions
|
||||||
|
|
||||||
This approach assumes you are running a vDB header sync which is run against a light Ethereum node;
|
This approach assumes you are running a vDB light sync which is itself run against a light Ethereum node,
|
||||||
this approach also assumes there is a full node available.
|
this approach also assumes there is a full node available.
|
||||||
|
|
||||||
Looking forward, we will be building fetchers that enable sourcing data from IPFS instead of an ETH node.
|
Looking forward, we will be building fetchers that enable sourcing data from IPFS instead of an ETH node.
|
||||||
@@ -17,7 +17,7 @@ Looking forward, we will be building fetchers that enable sourcing data from IPF
|
|||||||
|
|
||||||
VulcanizeDB has shared code built out for building and plugging in event transformers
|
VulcanizeDB has shared code built out for building and plugging in event transformers
|
||||||
|
|
||||||
### [Event Watcher (header sync)](../staging/libraries/shared/watcher/event_watcher.go)
|
### [Event Watcher (light sync)](../staging/libraries/shared/watcher/event_watcher.go)
|
||||||
|
|
||||||
The event watcher is responsible for continuously fetching and delegating chunks of logs and their associated header to the appropriate transformers.
|
The event watcher is responsible for continuously fetching and delegating chunks of logs and their associated header to the appropriate transformers.
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
package event
|
package event
|
||||||
|
|
||||||
import "github.com/vulcanize/vulcanizedb/pkg/core"
|
import "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
type Converter interface {
|
type Converter interface {
|
||||||
ToEntities(contractAbi string, ethLog []core.HeaderSyncLog) ([]interface{}, error)
|
ToEntities(contractAbi string, ethLog []types.Log) ([]interface{}, error)
|
||||||
ToModels([]interface{}) ([]interface{}, error)
|
ToModels([]interface{}) ([]interface{}, error)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-16
@@ -14,22 +14,10 @@
|
|||||||
// 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 logs_test
|
package event
|
||||||
|
|
||||||
import (
|
import "github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"io/ioutil"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
type LogNoteConverter interface {
|
||||||
. "github.com/onsi/gomega"
|
ToModels(ethLog []types.Log) ([]interface{}, error)
|
||||||
)
|
|
||||||
|
|
||||||
func TestLogs(t *testing.T) {
|
|
||||||
RegisterFailHandler(Fail)
|
|
||||||
RunSpecs(t, "Logs Suite")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = BeforeSuite(func() {
|
|
||||||
logrus.SetOutput(ioutil.Discard)
|
|
||||||
})
|
|
||||||
@@ -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 event
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LogNoteTransformer struct {
|
||||||
|
Config transformer.EventTransformerConfig
|
||||||
|
Converter LogNoteConverter
|
||||||
|
Repository Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr LogNoteTransformer) NewLogNoteTransformer(db *postgres.DB) transformer.EventTransformer {
|
||||||
|
tr.Repository.SetDB(db)
|
||||||
|
return tr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr LogNoteTransformer) Execute(logs []types.Log, header core.Header, recheckedHeader constants.TransformerExecution) error {
|
||||||
|
transformerName := tr.Config.TransformerName
|
||||||
|
|
||||||
|
// No matching logs, mark the header as checked for this type of logs
|
||||||
|
if len(logs) < 1 {
|
||||||
|
err := tr.Repository.MarkHeaderChecked(header.Id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error marking header as checked in %v: %v", transformerName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
models, err := tr.Converter.ToModels(logs)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error converting logs in %v: %v", transformerName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tr.Repository.Create(header.Id, models)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error persisting %v record: %v", transformerName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr LogNoteTransformer) GetName() string {
|
||||||
|
return tr.Config.TransformerName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr LogNoteTransformer) GetConfig() transformer.EventTransformerConfig {
|
||||||
|
return tr.Config
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
// 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 (
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"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/factories/event"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/mocks"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/test_data"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("LogNoteTransformer", func() {
|
||||||
|
var (
|
||||||
|
repository mocks.MockRepository
|
||||||
|
converter mocks.MockLogNoteConverter
|
||||||
|
headerOne core.Header
|
||||||
|
t transformer.EventTransformer
|
||||||
|
model test_data.GenericModel
|
||||||
|
config = test_data.GenericTestConfig
|
||||||
|
logs = test_data.GenericTestLogs
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
repository = mocks.MockRepository{}
|
||||||
|
converter = mocks.MockLogNoteConverter{}
|
||||||
|
t = event.LogNoteTransformer{
|
||||||
|
Config: config,
|
||||||
|
Converter: &converter,
|
||||||
|
Repository: &repository,
|
||||||
|
}.NewLogNoteTransformer(nil)
|
||||||
|
|
||||||
|
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("sets the database", func() {
|
||||||
|
Expect(repository.SetDbCalled).To(BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("marks header checked if no logs are provided", func() {
|
||||||
|
err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("doesn't attempt to convert or persist an empty collection when there are no logs", func() {
|
||||||
|
err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(converter.ToModelsCalledCounter).To(Equal(0))
|
||||||
|
Expect(repository.CreateCalledCounter).To(Equal(0))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("does not call repository.MarkCheckedHeader when there are logs", func() {
|
||||||
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
repository.AssertMarkHeaderCheckedNotCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if marking header checked returns err", func() {
|
||||||
|
repository.SetMarkHeaderCheckedError(fakes.FakeError)
|
||||||
|
|
||||||
|
err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("converts matching logs to models", func() {
|
||||||
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(converter.PassedLogs).To(Equal(logs))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if converter returns error", func() {
|
||||||
|
converter.SetConverterError(fakes.FakeError)
|
||||||
|
|
||||||
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("persists the model", func() {
|
||||||
|
converter.SetReturnModels([]interface{}{model})
|
||||||
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(repository.PassedHeaderID).To(Equal(headerOne.Id))
|
||||||
|
Expect(repository.PassedModels).To(Equal([]interface{}{model}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if repository returns error for create", func() {
|
||||||
|
repository.SetCreateError(fakes.FakeError)
|
||||||
|
|
||||||
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -16,9 +16,15 @@
|
|||||||
|
|
||||||
package event
|
package event
|
||||||
|
|
||||||
import "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
Create(models []interface{}) error
|
Create(headerID int64, models []interface{}) error
|
||||||
|
MarkHeaderChecked(headerID int64) error
|
||||||
|
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
|
||||||
|
RecheckHeaders(startingBlockNumber, endingBlockNUmber int64) ([]core.Header, error)
|
||||||
SetDB(db *postgres.DB)
|
SetDB(db *postgres.DB)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,10 @@
|
|||||||
package event
|
package event
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
"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"
|
||||||
@@ -34,29 +37,34 @@ func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.Event
|
|||||||
return transformer
|
return transformer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer Transformer) Execute(logs []core.HeaderSyncLog) error {
|
func (transformer Transformer) Execute(logs []types.Log, header core.Header, recheckHeaders constants.TransformerExecution) error {
|
||||||
transformerName := transformer.Config.TransformerName
|
transformerName := transformer.Config.TransformerName
|
||||||
config := transformer.Config
|
config := transformer.Config
|
||||||
|
|
||||||
if len(logs) < 1 {
|
if len(logs) < 1 {
|
||||||
|
err := transformer.Repository.MarkHeaderChecked(header.Id)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error marking header as checked in %v: %v", transformerName, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
entities, err := transformer.Converter.ToEntities(config.ContractAbi, logs)
|
entities, err := transformer.Converter.ToEntities(config.ContractAbi, logs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("error converting logs to entities in %v: %v", transformerName, err)
|
log.Printf("Error converting logs to entities in %v: %v", transformerName, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
models, err := transformer.Converter.ToModels(entities)
|
models, err := transformer.Converter.ToModels(entities)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("error converting entities to models in %v: %v", transformerName, err)
|
log.Printf("Error converting entities to models in %v: %v", transformerName, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = transformer.Repository.Create(models)
|
err = transformer.Repository.Create(header.Id, models)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("error persisting %v record: %v", transformerName, err)
|
log.Printf("Error persisting %v record: %v", transformerName, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,29 +17,33 @@
|
|||||||
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/constants"
|
||||||
"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.MockEventRepository
|
repository mocks.MockRepository
|
||||||
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 []core.HeaderSyncLog
|
logs = test_data.GenericTestLogs
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
repository = mocks.MockEventRepository{}
|
repository = mocks.MockRepository{}
|
||||||
converter = mocks.MockConverter{}
|
converter = mocks.MockConverter{}
|
||||||
|
|
||||||
t = event.Transformer{
|
t = event.Transformer{
|
||||||
@@ -49,21 +53,21 @@ var _ = Describe("Transformer", func() {
|
|||||||
}.NewTransformer(nil)
|
}.NewTransformer(nil)
|
||||||
|
|
||||||
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
|
headerOne = core.Header{Id: rand.Int63(), BlockNumber: rand.Int63()}
|
||||||
|
|
||||||
logs = []core.HeaderSyncLog{{
|
|
||||||
ID: 0,
|
|
||||||
HeaderID: headerOne.Id,
|
|
||||||
Log: test_data.GenericTestLog(),
|
|
||||||
Transformed: false,
|
|
||||||
}}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("sets the db", func() {
|
It("sets the db", func() {
|
||||||
Expect(repository.SetDbCalled).To(BeTrue())
|
Expect(repository.SetDbCalled).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("marks header checked if no logs returned", func() {
|
||||||
|
err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
repository.AssertMarkHeaderCheckedCalledWith(headerOne.Id)
|
||||||
|
})
|
||||||
|
|
||||||
It("doesn't attempt to convert or persist an empty collection when there are no logs", func() {
|
It("doesn't attempt to convert or persist an empty collection when there are no logs", func() {
|
||||||
err := t.Execute([]core.HeaderSyncLog{})
|
err := t.Execute([]types.Log{}, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(converter.ToEntitiesCalledCounter).To(Equal(0))
|
Expect(converter.ToEntitiesCalledCounter).To(Equal(0))
|
||||||
@@ -71,8 +75,24 @@ var _ = Describe("Transformer", func() {
|
|||||||
Expect(repository.CreateCalledCounter).To(Equal(0))
|
Expect(repository.CreateCalledCounter).To(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("does not call repository.MarkCheckedHeader when there are logs", func() {
|
||||||
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
|
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, constants.HeaderMissing)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
It("converts an eth log to an entity", func() {
|
It("converts an eth log to an entity", func() {
|
||||||
err := t.Execute(logs)
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(converter.ContractAbi).To(Equal(config.ContractAbi))
|
Expect(converter.ContractAbi).To(Equal(config.ContractAbi))
|
||||||
@@ -82,7 +102,7 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("returns an error if converter fails", func() {
|
It("returns an error if converter fails", func() {
|
||||||
converter.ToEntitiesError = fakes.FakeError
|
converter.ToEntitiesError = fakes.FakeError
|
||||||
|
|
||||||
err := t.Execute(logs)
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
@@ -91,7 +111,7 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("converts an entity to a model", func() {
|
It("converts an entity to a model", func() {
|
||||||
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
||||||
|
|
||||||
err := t.Execute(logs)
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(converter.EntitiesToConvert[0]).To(Equal(test_data.GenericEntity{}))
|
Expect(converter.EntitiesToConvert[0]).To(Equal(test_data.GenericEntity{}))
|
||||||
@@ -101,7 +121,7 @@ var _ = Describe("Transformer", func() {
|
|||||||
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
converter.EntitiesToReturn = []interface{}{test_data.GenericEntity{}}
|
||||||
converter.ToModelsError = fakes.FakeError
|
converter.ToModelsError = fakes.FakeError
|
||||||
|
|
||||||
err := t.Execute(logs)
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
@@ -110,15 +130,16 @@ var _ = Describe("Transformer", func() {
|
|||||||
It("persists the record", func() {
|
It("persists the record", func() {
|
||||||
converter.ModelsToReturn = []interface{}{test_data.GenericModel{}}
|
converter.ModelsToReturn = []interface{}{test_data.GenericModel{}}
|
||||||
|
|
||||||
err := t.Execute(logs)
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
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)
|
err := t.Execute(logs, headerOne, constants.HeaderMissing)
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ type Repository interface {
|
|||||||
A contract-specific implementation of the repository interface enables the transformer to write the decoded storage value to the appropriate table in postgres.
|
A contract-specific implementation of the repository interface enables the transformer to write the decoded storage value to the appropriate table in postgres.
|
||||||
|
|
||||||
The `Create` function is expected to recognize and persist a given storage value by the variable's name, as indicated on the row's metadata.
|
The `Create` function is expected to recognize and persist a given storage value by the variable's name, as indicated on the row's metadata.
|
||||||
Note: we advise silently discarding duplicates in `Create` - as it's possible that you may read the same diff several times, and an error will trigger the storage watcher to queue that diff for later processing.
|
|
||||||
|
|
||||||
The `SetDB` function is required for the repository to connect to the database.
|
The `SetDB` function is required for the repository to connect to the database.
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package storage
|
|||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
"github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
@@ -28,7 +29,7 @@ import (
|
|||||||
type Transformer struct {
|
type Transformer struct {
|
||||||
Address common.Address
|
Address common.Address
|
||||||
Mappings storage.Mappings
|
Mappings storage.Mappings
|
||||||
Repository Repository
|
Repository repository.StorageRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.StorageTransformer {
|
func (transformer Transformer) NewTransformer(db *postgres.DB) transformer.StorageTransformer {
|
||||||
|
|||||||
@@ -100,54 +100,4 @@ var _ = Describe("Storage transformer", func() {
|
|||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("when a storage row contains more than one item packed in storage", func() {
|
|
||||||
var (
|
|
||||||
rawValue = common.HexToAddress("000000000000000000000000000000000000000000000002a300000000002a30")
|
|
||||||
fakeBlockNumber = 123
|
|
||||||
fakeBlockHash = "0x67890"
|
|
||||||
packedTypes = make(map[int]utils.ValueType)
|
|
||||||
)
|
|
||||||
packedTypes[0] = utils.Uint48
|
|
||||||
packedTypes[1] = utils.Uint48
|
|
||||||
|
|
||||||
var fakeMetadata = utils.StorageValueMetadata{
|
|
||||||
Name: "",
|
|
||||||
Keys: nil,
|
|
||||||
Type: utils.PackedSlot,
|
|
||||||
PackedTypes: packedTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
It("passes the decoded data items to the repository", func() {
|
|
||||||
mappings.Metadata = fakeMetadata
|
|
||||||
fakeRow := utils.StorageDiffRow{
|
|
||||||
Contract: common.Address{},
|
|
||||||
BlockHash: common.HexToHash(fakeBlockHash),
|
|
||||||
BlockHeight: fakeBlockNumber,
|
|
||||||
StorageKey: common.Hash{},
|
|
||||||
StorageValue: rawValue.Hash(),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := t.Execute(fakeRow)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(repository.PassedBlockNumber).To(Equal(fakeBlockNumber))
|
|
||||||
Expect(repository.PassedBlockHash).To(Equal(common.HexToHash(fakeBlockHash).Hex()))
|
|
||||||
Expect(repository.PassedMetadata).To(Equal(fakeMetadata))
|
|
||||||
expectedPassedValue := make(map[int]string)
|
|
||||||
expectedPassedValue[0] = "10800"
|
|
||||||
expectedPassedValue[1] = "172800"
|
|
||||||
Expect(repository.PassedValue.(map[int]string)).To(Equal(expectedPassedValue))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("returns error if creating a row fails", func() {
|
|
||||||
mappings.Metadata = fakeMetadata
|
|
||||||
repository.CreateErr = fakes.FakeError
|
|
||||||
|
|
||||||
err := t.Execute(utils.StorageDiffRow{StorageValue: rawValue.Hash()})
|
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -24,23 +24,22 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ILogFetcher interface {
|
type LogFetcher 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 Fetcher struct {
|
||||||
blockChain core.BlockChain
|
blockChain core.BlockChain
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogFetcher(blockchain core.BlockChain) *LogFetcher {
|
func NewFetcher(blockchain core.BlockChain) *Fetcher {
|
||||||
return &LogFetcher{
|
return &Fetcher{
|
||||||
blockChain: blockchain,
|
blockChain: blockchain,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks all topic0s, on all addresses, fetching matching logs for the given header
|
// Checks all topic0s, on all addresses, fetching matching logs for the given header
|
||||||
func (logFetcher LogFetcher) FetchLogs(addresses []common.Address, topic0s []common.Hash, header core.Header) ([]types.Log, error) {
|
func (fetcher Fetcher) FetchLogs(addresses []common.Address, topic0s []common.Hash, header core.Header) ([]types.Log, error) {
|
||||||
blockHash := common.HexToHash(header.Hash)
|
blockHash := common.HexToHash(header.Hash)
|
||||||
query := ethereum.FilterQuery{
|
query := ethereum.FilterQuery{
|
||||||
BlockHash: &blockHash,
|
BlockHash: &blockHash,
|
||||||
@@ -49,7 +48,7 @@ func (logFetcher LogFetcher) FetchLogs(addresses []common.Address, topic0s []com
|
|||||||
Topics: [][]common.Hash{topic0s},
|
Topics: [][]common.Hash{topic0s},
|
||||||
}
|
}
|
||||||
|
|
||||||
logs, err := logFetcher.blockChain.GetEthLogsWithCustomQuery(query)
|
logs, err := fetcher.blockChain.GetEthLogsWithCustomQuery(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO review aggregate fetching error handling
|
// TODO review aggregate fetching error handling
|
||||||
return []types.Log{}, err
|
return []types.Log{}, err
|
||||||
|
|||||||
@@ -22,16 +22,16 @@ import (
|
|||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
fetch "github.com/vulcanize/vulcanizedb/libraries/shared/fetcher"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("LogFetcher", func() {
|
var _ = Describe("Fetcher", func() {
|
||||||
Describe("FetchLogs", func() {
|
Describe("FetchLogs", func() {
|
||||||
It("fetches logs based on the given query", func() {
|
It("fetches logs based on the given query", func() {
|
||||||
blockChain := fakes.NewMockBlockChain()
|
blockChain := fakes.NewMockBlockChain()
|
||||||
logFetcher := fetcher.NewLogFetcher(blockChain)
|
fetcher := fetch.NewFetcher(blockChain)
|
||||||
header := fakes.FakeHeader
|
header := fakes.FakeHeader
|
||||||
|
|
||||||
addresses := []common.Address{
|
addresses := []common.Address{
|
||||||
@@ -41,7 +41,7 @@ var _ = Describe("LogFetcher", func() {
|
|||||||
|
|
||||||
topicZeros := []common.Hash{common.BytesToHash([]byte{1, 2, 3, 4, 5})}
|
topicZeros := []common.Hash{common.BytesToHash([]byte{1, 2, 3, 4, 5})}
|
||||||
|
|
||||||
_, err := logFetcher.FetchLogs(addresses, topicZeros, header)
|
_, err := fetcher.FetchLogs(addresses, topicZeros, header)
|
||||||
|
|
||||||
address1 := common.HexToAddress("0xfakeAddress")
|
address1 := common.HexToAddress("0xfakeAddress")
|
||||||
address2 := common.HexToAddress("0xanotherFakeAddress")
|
address2 := common.HexToAddress("0xanotherFakeAddress")
|
||||||
@@ -59,9 +59,9 @@ var _ = Describe("LogFetcher", func() {
|
|||||||
It("returns an error if fetching the logs fails", func() {
|
It("returns an error if fetching the logs fails", func() {
|
||||||
blockChain := fakes.NewMockBlockChain()
|
blockChain := fakes.NewMockBlockChain()
|
||||||
blockChain.SetGetEthLogsWithCustomQueryErr(fakes.FakeError)
|
blockChain.SetGetEthLogsWithCustomQueryErr(fakes.FakeError)
|
||||||
logFetcher := fetcher.NewLogFetcher(blockChain)
|
fetcher := fetch.NewFetcher(blockChain)
|
||||||
|
|
||||||
_, err := logFetcher.FetchLogs([]common.Address{}, []common.Hash{}, core.Header{})
|
_, err := fetcher.FetchLogs([]common.Address{}, []common.Hash{}, core.Header{})
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
|||||||
@@ -1,54 +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 fetcher
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/storage/utils"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fs"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IStorageFetcher interface {
|
|
||||||
FetchStorageDiffs(chan<- utils.StorageDiffRow, chan<- error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type CsvTailStorageFetcher struct {
|
|
||||||
tailer fs.Tailer
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCsvTailStorageFetcher(tailer fs.Tailer) CsvTailStorageFetcher {
|
|
||||||
return CsvTailStorageFetcher{tailer: tailer}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (storageFetcher CsvTailStorageFetcher) FetchStorageDiffs(out chan<- utils.StorageDiffRow, errs chan<- error) {
|
|
||||||
t, tailErr := storageFetcher.tailer.Tail()
|
|
||||||
if tailErr != nil {
|
|
||||||
errs <- tailErr
|
|
||||||
}
|
|
||||||
log.Debug("fetching storage diffs...")
|
|
||||||
for line := range t.Lines {
|
|
||||||
row, parseErr := utils.FromStrings(strings.Split(line.Text, ","))
|
|
||||||
if parseErr != nil {
|
|
||||||
errs <- parseErr
|
|
||||||
} else {
|
|
||||||
out <- row
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +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 fetcher_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/hpcloud/tail"
|
|
||||||
. "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/pkg/fakes"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Describe("Csv Tail Storage Fetcher", func() {
|
|
||||||
var (
|
|
||||||
errorsChannel chan error
|
|
||||||
mockTailer *fakes.MockTailer
|
|
||||||
rowsChannel chan utils.StorageDiffRow
|
|
||||||
storageFetcher fetcher.CsvTailStorageFetcher
|
|
||||||
)
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
|
||||||
errorsChannel = make(chan error)
|
|
||||||
rowsChannel = make(chan utils.StorageDiffRow)
|
|
||||||
mockTailer = fakes.NewMockTailer()
|
|
||||||
storageFetcher = fetcher.NewCsvTailStorageFetcher(mockTailer)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("adds error to errors channel if tailing file fails", func(done Done) {
|
|
||||||
mockTailer.TailErr = fakes.FakeError
|
|
||||||
|
|
||||||
go storageFetcher.FetchStorageDiffs(rowsChannel, errorsChannel)
|
|
||||||
|
|
||||||
Expect(<-errorsChannel).To(MatchError(fakes.FakeError))
|
|
||||||
close(done)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("adds parsed csv row to rows channel for storage diff", func(done Done) {
|
|
||||||
line := getFakeLine()
|
|
||||||
|
|
||||||
go storageFetcher.FetchStorageDiffs(rowsChannel, errorsChannel)
|
|
||||||
mockTailer.Lines <- line
|
|
||||||
|
|
||||||
expectedRow, err := utils.FromStrings(strings.Split(line.Text, ","))
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(<-rowsChannel).To(Equal(expectedRow))
|
|
||||||
close(done)
|
|
||||||
})
|
|
||||||
|
|
||||||
It("adds error to errors channel if parsing csv fails", func(done Done) {
|
|
||||||
line := &tail.Line{Text: "invalid"}
|
|
||||||
|
|
||||||
go storageFetcher.FetchStorageDiffs(rowsChannel, errorsChannel)
|
|
||||||
mockTailer.Lines <- line
|
|
||||||
|
|
||||||
Expect(<-errorsChannel).To(HaveOccurred())
|
|
||||||
select {
|
|
||||||
case <-rowsChannel:
|
|
||||||
Fail("value passed to rows channel on error")
|
|
||||||
default:
|
|
||||||
Succeed()
|
|
||||||
}
|
|
||||||
close(done)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
func getFakeLine() *tail.Line {
|
|
||||||
address := common.HexToAddress("0x1234567890abcdef")
|
|
||||||
blockHash := []byte{4, 5, 6}
|
|
||||||
blockHeight := int64(789)
|
|
||||||
storageKey := []byte{9, 8, 7}
|
|
||||||
storageValue := []byte{6, 5, 4}
|
|
||||||
return &tail.Line{
|
|
||||||
Text: fmt.Sprintf("%s,%s,%d,%s,%s", common.Bytes2Hex(address.Bytes()), common.Bytes2Hex(blockHash),
|
|
||||||
blockHeight, common.Bytes2Hex(storageKey), common.Bytes2Hex(storageValue)),
|
|
||||||
Time: time.Time{},
|
|
||||||
Err: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +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 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
|
|
||||||
}
|
|
||||||
@@ -1,165 +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 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +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 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
|
|
||||||
}
|
|
||||||
@@ -1,414 +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 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import "github.com/vulcanize/vulcanizedb/pkg/core"
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
type MockConverter struct {
|
type MockConverter struct {
|
||||||
ToEntitiesError error
|
ToEntitiesError error
|
||||||
@@ -25,7 +27,7 @@ type MockConverter struct {
|
|||||||
entityConverterError error
|
entityConverterError error
|
||||||
modelConverterError error
|
modelConverterError error
|
||||||
ContractAbi string
|
ContractAbi string
|
||||||
LogsToConvert []core.HeaderSyncLog
|
LogsToConvert []types.Log
|
||||||
EntitiesToConvert []interface{}
|
EntitiesToConvert []interface{}
|
||||||
EntitiesToReturn []interface{}
|
EntitiesToReturn []interface{}
|
||||||
ModelsToReturn []interface{}
|
ModelsToReturn []interface{}
|
||||||
@@ -33,9 +35,9 @@ type MockConverter struct {
|
|||||||
ToModelsCalledCounter int
|
ToModelsCalledCounter int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (converter *MockConverter) ToEntities(contractAbi string, ethLogs []core.HeaderSyncLog) ([]interface{}, error) {
|
func (converter *MockConverter) ToEntities(contractAbi string, ethLogs []types.Log) ([]interface{}, error) {
|
||||||
for _, log := range ethLogs {
|
for _, log := range ethLogs {
|
||||||
converter.PassedContractAddresses = append(converter.PassedContractAddresses, log.Log.Address.Hex())
|
converter.PassedContractAddresses = append(converter.PassedContractAddresses, log.Address.Hex())
|
||||||
}
|
}
|
||||||
converter.ContractAbi = contractAbi
|
converter.ContractAbi = contractAbi
|
||||||
converter.LogsToConvert = ethLogs
|
converter.LogsToConvert = ethLogs
|
||||||
@@ -51,6 +53,6 @@ func (converter *MockConverter) SetToEntityConverterError(err error) {
|
|||||||
converter.entityConverterError = err
|
converter.entityConverterError = err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (converter *MockConverter) SetToModelConverterError(err error) {
|
func (c *MockConverter) SetToModelConverterError(err error) {
|
||||||
converter.modelConverterError = err
|
c.modelConverterError = err
|
||||||
}
|
}
|
||||||
@@ -1,43 +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/datastore/postgres"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockEventRepository struct {
|
|
||||||
createError error
|
|
||||||
PassedModels []interface{}
|
|
||||||
SetDbCalled bool
|
|
||||||
CreateCalledCounter int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockEventRepository) Create(models []interface{}) error {
|
|
||||||
repository.PassedModels = models
|
|
||||||
repository.CreateCalledCounter++
|
|
||||||
|
|
||||||
return repository.createError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockEventRepository) SetDB(db *postgres.DB) {
|
|
||||||
repository.SetDbCalled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repository *MockEventRepository) SetCreateError(e error) {
|
|
||||||
repository.createError = e
|
|
||||||
}
|
|
||||||
@@ -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/vulcanize/vulcanizedb/libraries/shared/transformer"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MockEventTransformer struct {
|
|
||||||
ExecuteWasCalled bool
|
|
||||||
ExecuteError error
|
|
||||||
PassedLogs []core.HeaderSyncLog
|
|
||||||
config transformer.EventTransformerConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *MockEventTransformer) Execute(logs []core.HeaderSyncLog) error {
|
|
||||||
if t.ExecuteError != nil {
|
|
||||||
return t.ExecuteError
|
|
||||||
}
|
|
||||||
t.ExecuteWasCalled = true
|
|
||||||
t.PassedLogs = logs
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *MockEventTransformer) GetConfig() transformer.EventTransformerConfig {
|
|
||||||
return t.config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *MockEventTransformer) SetTransformerConfig(config transformer.EventTransformerConfig) {
|
|
||||||
t.config = config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *MockEventTransformer) FakeTransformerInitializer(db *postgres.DB) transformer.EventTransformer {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
var FakeTransformerConfig = transformer.EventTransformerConfig{
|
|
||||||
TransformerName: "FakeTransformer",
|
|
||||||
ContractAddresses: []string{fakes.FakeAddress.Hex()},
|
|
||||||
Topic: fakes.FakeHash.Hex(),
|
|
||||||
}
|
|
||||||
@@ -1,45 +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/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
|
|
||||||
}
|
|
||||||
@@ -1,48 +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/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
|
|
||||||
}
|
|
||||||
+17
-15
@@ -17,24 +17,26 @@
|
|||||||
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 MockLogFetcher struct {
|
type MockLogNoteConverter struct {
|
||||||
ContractAddresses []common.Address
|
err error
|
||||||
FetchCalled bool
|
returnModels []interface{}
|
||||||
MissingHeader core.Header
|
PassedLogs []types.Log
|
||||||
ReturnError error
|
ToModelsCalledCounter int
|
||||||
ReturnLogs []types.Log
|
|
||||||
Topics []common.Hash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fetcher *MockLogFetcher) FetchLogs(contractAddresses []common.Address, topics []common.Hash, missingHeader core.Header) ([]types.Log, error) {
|
func (converter *MockLogNoteConverter) ToModels(ethLogs []types.Log) ([]interface{}, error) {
|
||||||
fetcher.FetchCalled = true
|
converter.PassedLogs = ethLogs
|
||||||
fetcher.ContractAddresses = contractAddresses
|
converter.ToModelsCalledCounter++
|
||||||
fetcher.Topics = topics
|
return converter.returnModels, converter.err
|
||||||
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
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// 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,98 @@
|
|||||||
|
// 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))
|
||||||
|
}
|
||||||
@@ -1,39 +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/libraries/shared/storage/utils"
|
|
||||||
|
|
||||||
type MockStorageFetcher struct {
|
|
||||||
RowsToReturn []utils.StorageDiffRow
|
|
||||||
ErrsToReturn []error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMockStorageFetcher() *MockStorageFetcher {
|
|
||||||
return &MockStorageFetcher{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fetcher *MockStorageFetcher) FetchStorageDiffs(out chan<- utils.StorageDiffRow, errs chan<- error) {
|
|
||||||
defer close(out)
|
|
||||||
defer close(errs)
|
|
||||||
for _, err := range fetcher.ErrsToReturn {
|
|
||||||
errs <- err
|
|
||||||
}
|
|
||||||
for _, row := range fetcher.RowsToReturn {
|
|
||||||
out <- row
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,26 +21,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type MockStorageQueue struct {
|
type MockStorageQueue struct {
|
||||||
AddCalled bool
|
AddCalled bool
|
||||||
AddError error
|
AddError error
|
||||||
AddPassedRow utils.StorageDiffRow
|
|
||||||
DeleteErr error
|
|
||||||
DeletePassedId int
|
|
||||||
GetAllErr error
|
|
||||||
RowsToReturn []utils.StorageDiffRow
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (queue *MockStorageQueue) Add(row utils.StorageDiffRow) error {
|
func (queue *MockStorageQueue) Add(row utils.StorageDiffRow) error {
|
||||||
queue.AddCalled = true
|
queue.AddCalled = true
|
||||||
queue.AddPassedRow = row
|
|
||||||
return queue.AddError
|
return queue.AddError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (queue *MockStorageQueue) Delete(id int) error {
|
|
||||||
queue.DeletePassedId = id
|
|
||||||
return queue.DeleteErr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (queue *MockStorageQueue) GetAll() ([]utils.StorageDiffRow, error) {
|
|
||||||
return queue.RowsToReturn, queue.GetAllErr
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
|
shared_t "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockTransformer struct {
|
||||||
|
ExecuteWasCalled bool
|
||||||
|
ExecuteError error
|
||||||
|
PassedLogs []types.Log
|
||||||
|
PassedHeader core.Header
|
||||||
|
config shared_t.EventTransformerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mh *MockTransformer) Execute(logs []types.Log, header core.Header, recheckHeaders constants.TransformerExecution) error {
|
||||||
|
if mh.ExecuteError != nil {
|
||||||
|
return mh.ExecuteError
|
||||||
|
}
|
||||||
|
mh.ExecuteWasCalled = true
|
||||||
|
mh.PassedLogs = logs
|
||||||
|
mh.PassedHeader = header
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mh *MockTransformer) GetConfig() shared_t.EventTransformerConfig {
|
||||||
|
return mh.config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mh *MockTransformer) SetTransformerConfig(config shared_t.EventTransformerConfig) {
|
||||||
|
mh.config = config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mh *MockTransformer) FakeTransformerInitializer(db *postgres.DB) shared_t.EventTransformer {
|
||||||
|
return mh
|
||||||
|
}
|
||||||
|
|
||||||
|
var FakeTransformerConfig = shared_t.EventTransformerConfig{
|
||||||
|
TransformerName: "FakeTransformer",
|
||||||
|
ContractAddresses: []string{"FakeAddress"},
|
||||||
|
Topic: "FakeTopic",
|
||||||
|
}
|
||||||
@@ -16,12 +16,142 @@
|
|||||||
|
|
||||||
package repository
|
package repository
|
||||||
|
|
||||||
import "github.com/jmoiron/sqlx"
|
import (
|
||||||
|
"bytes"
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
func MarkContractWatcherHeaderCheckedInTransaction(headerID int64, tx *sqlx.Tx, checkedHeadersColumn string) error {
|
"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+`)
|
_, err := tx.Exec(`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`)
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2)
|
||||||
ON CONFLICT (header_id) DO
|
ON CONFLICT (header_id) DO
|
||||||
UPDATE SET `+checkedHeadersColumn+` = checked_headers.`+checkedHeadersColumn+` + 1`, headerID, 1)
|
UPDATE SET `+checkedHeadersColumn+` = checked_headers.`+checkedHeadersColumn+` + 1`, headerID, 1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Treats a header as missing if it's not in the headers table, or not checked for some log type
|
||||||
|
func MissingHeaders(startingBlockNumber, endingBlockNumber int64, db *postgres.DB, notCheckedSQL string) ([]core.Header, error) {
|
||||||
|
var result []core.Header
|
||||||
|
var query string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if endingBlockNumber == -1 {
|
||||||
|
query = `SELECT headers.id, headers.block_number, headers.hash FROM headers
|
||||||
|
LEFT JOIN checked_headers on headers.id = header_id
|
||||||
|
WHERE (header_id ISNULL OR ` + notCheckedSQL + `)
|
||||||
|
AND headers.block_number >= $1
|
||||||
|
AND headers.eth_node_fingerprint = $2`
|
||||||
|
err = db.Select(&result, query, startingBlockNumber, db.Node.ID)
|
||||||
|
} else {
|
||||||
|
query = `SELECT headers.id, headers.block_number, headers.hash FROM headers
|
||||||
|
LEFT JOIN checked_headers on headers.id = header_id
|
||||||
|
WHERE (header_id ISNULL OR ` + notCheckedSQL + `)
|
||||||
|
AND headers.block_number >= $1
|
||||||
|
AND headers.block_number <= $2
|
||||||
|
AND headers.eth_node_fingerprint = $3`
|
||||||
|
err = db.Select(&result, query, startingBlockNumber, endingBlockNumber, db.Node.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecheckHeaders(startingBlockNumber, endingBlockNumber int64, db *postgres.DB, checkedHeadersColumn 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 ` + checkedHeadersColumn + ` between 1 and ` + constants.RecheckHeaderCap + `
|
||||||
|
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 ` + checkedHeadersColumn + ` between 1 and ` + constants.RecheckHeaderCap + `
|
||||||
|
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 ~ '_checked';`
|
||||||
|
|
||||||
|
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 value is 0, given the column names.
|
||||||
|
// Defaults to FALSE when no columns are provided.
|
||||||
|
// Ex: ["columnA", "columnB"] => "NOT (columnA!=0 AND columnB!=0)"
|
||||||
|
// [] => "FALSE"
|
||||||
|
func CreateNotCheckedSQL(boolColumns []string, recheckHeaders constants.TransformerExecution) string {
|
||||||
|
|
||||||
|
var result bytes.Buffer
|
||||||
|
|
||||||
|
if len(boolColumns) == 0 {
|
||||||
|
return "FALSE"
|
||||||
|
}
|
||||||
|
|
||||||
|
result.WriteString("NOT (")
|
||||||
|
|
||||||
|
// Loop excluding last column name
|
||||||
|
for _, column := range boolColumns[:len(boolColumns)-1] {
|
||||||
|
|
||||||
|
if recheckHeaders {
|
||||||
|
result.WriteString(fmt.Sprintf("%v>=%s AND ", column, constants.RecheckHeaderCap))
|
||||||
|
} else {
|
||||||
|
result.WriteString(fmt.Sprintf("%v!=0 AND ", column))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No trailing "OR" for the last column name
|
||||||
|
if recheckHeaders {
|
||||||
|
result.WriteString(fmt.Sprintf("%v>=%s)", boolColumns[len(boolColumns)-1], constants.RecheckHeaderCap))
|
||||||
|
} else {
|
||||||
|
result.WriteString(fmt.Sprintf("%v!=0)", boolColumns[len(boolColumns)-1]))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.String()
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,17 +17,26 @@
|
|||||||
package repository_test
|
package repository_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared/constants"
|
||||||
|
shared "github.com/vulcanize/vulcanizedb/libraries/shared/repository"
|
||||||
|
r2 "github.com/vulcanize/vulcanizedb/pkg/contract_watcher/light/repository"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
"github.com/vulcanize/vulcanizedb/test_config"
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("", func() {
|
var _ = Describe("Repository", func() {
|
||||||
Describe("MarkContractWatcherHeaderCheckedInTransaction", func() {
|
Describe("MarkHeaderChecked", func() {
|
||||||
var (
|
var (
|
||||||
checkedHeadersColumn string
|
checkedHeadersColumn string
|
||||||
db *postgres.DB
|
db *postgres.DB
|
||||||
@@ -36,6 +45,7 @@ var _ = Describe("", func() {
|
|||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
db = test_config.NewTestDB(test_config.NewTestNode())
|
db = test_config.NewTestDB(test_config.NewTestNode())
|
||||||
test_config.CleanTestDB(db)
|
test_config.CleanTestDB(db)
|
||||||
|
|
||||||
checkedHeadersColumn = "test_column_checked"
|
checkedHeadersColumn = "test_column_checked"
|
||||||
_, migrateErr := db.Exec(`ALTER TABLE public.checked_headers
|
_, migrateErr := db.Exec(`ALTER TABLE public.checked_headers
|
||||||
ADD COLUMN ` + checkedHeadersColumn + ` integer`)
|
ADD COLUMN ` + checkedHeadersColumn + ` integer`)
|
||||||
@@ -47,21 +57,269 @@ var _ = Describe("", func() {
|
|||||||
Expect(cleanupMigrateErr).NotTo(HaveOccurred())
|
Expect(cleanupMigrateErr).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("marks passed header as checked within a passed transaction", func() {
|
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() {
|
||||||
|
var (
|
||||||
|
checkedHeadersColumn string
|
||||||
|
db *postgres.DB
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
db = test_config.NewTestDB(test_config.NewTestNode())
|
||||||
|
test_config.CleanTestDB(db)
|
||||||
|
|
||||||
|
checkedHeadersColumn = "test_column_checked"
|
||||||
|
_, migrateErr := db.Exec(`ALTER TABLE public.checked_headers
|
||||||
|
ADD COLUMN ` + checkedHeadersColumn + ` integer`)
|
||||||
|
Expect(migrateErr).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
_, cleanupMigrateErr := db.Exec(`ALTER TABLE public.checked_headers DROP COLUMN ` + checkedHeadersColumn)
|
||||||
|
Expect(cleanupMigrateErr).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("marks passed column as checked for passed header within a passed transaction", func() {
|
||||||
headerRepository := repositories.NewHeaderRepository(db)
|
headerRepository := repositories.NewHeaderRepository(db)
|
||||||
headerID, headerErr := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
|
headerID, headerErr := headerRepository.CreateOrUpdateHeader(fakes.FakeHeader)
|
||||||
Expect(headerErr).NotTo(HaveOccurred())
|
Expect(headerErr).NotTo(HaveOccurred())
|
||||||
tx, txErr := db.Beginx()
|
tx, txErr := db.Beginx()
|
||||||
Expect(txErr).NotTo(HaveOccurred())
|
Expect(txErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
err := repository.MarkContractWatcherHeaderCheckedInTransaction(headerID, tx, checkedHeadersColumn)
|
err := shared.MarkHeaderCheckedInTransaction(headerID, tx, checkedHeadersColumn)
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
commitErr := tx.Commit()
|
commitErr := tx.Commit()
|
||||||
Expect(commitErr).NotTo(HaveOccurred())
|
Expect(commitErr).NotTo(HaveOccurred())
|
||||||
var checkedCount int
|
var checkedCount int
|
||||||
fetchErr := db.Get(&checkedCount, `SELECT COUNT(*) FROM public.checked_headers WHERE header_id = $1`, headerID)
|
fetchErr := db.Get(&checkedCount, `SELECT `+checkedHeadersColumn+` FROM public.checked_headers LIMIT 1`)
|
||||||
Expect(fetchErr).NotTo(HaveOccurred())
|
Expect(fetchErr).NotTo(HaveOccurred())
|
||||||
Expect(checkedCount).To(Equal(1))
|
Expect(checkedCount).To(Equal(1))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Describe("MissingHeaders", func() {
|
||||||
|
var (
|
||||||
|
db *postgres.DB
|
||||||
|
headerRepository datastore.HeaderRepository
|
||||||
|
startingBlockNumber int64
|
||||||
|
endingBlockNumber int64
|
||||||
|
eventSpecificBlockNumber int64
|
||||||
|
blockNumbers []int64
|
||||||
|
headerIDs []int64
|
||||||
|
notCheckedSQL string
|
||||||
|
err error
|
||||||
|
hr r2.HeaderRepository
|
||||||
|
)
|
||||||
|
|
||||||
|
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.CreateNotCheckedSQL(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() {
|
||||||
|
_, 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)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("RecheckHeaders", func() {
|
||||||
|
var (
|
||||||
|
checkedHeadersColumn string
|
||||||
|
db *postgres.DB
|
||||||
|
headerOneID, headerTwoID, headerThreeID, headerFourID int64
|
||||||
|
headerOneErr, headerTwoErr, headerThreeErr, headerFourErr error
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
db = test_config.NewTestDB(test_config.NewTestNode())
|
||||||
|
test_config.CleanTestDB(db)
|
||||||
|
|
||||||
|
// create header checked column
|
||||||
|
checkedHeadersColumn = "test_column_checked"
|
||||||
|
_, migrateErr := db.Exec(`ALTER TABLE public.checked_headers ADD COLUMN ` + checkedHeadersColumn + ` integer`)
|
||||||
|
Expect(migrateErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// create headers
|
||||||
|
headerRepository := repositories.NewHeaderRepository(db)
|
||||||
|
headerOneID, headerOneErr = headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(1))
|
||||||
|
Expect(headerOneErr).NotTo(HaveOccurred())
|
||||||
|
headerTwoID, headerTwoErr = headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(2))
|
||||||
|
Expect(headerTwoErr).NotTo(HaveOccurred())
|
||||||
|
headerThreeID, headerThreeErr = headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(3))
|
||||||
|
Expect(headerThreeErr).NotTo(HaveOccurred())
|
||||||
|
headerFourID, headerFourErr = headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(4))
|
||||||
|
Expect(headerFourErr).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
// mark every header checked at least once, with one fully rechecked (headerThree)
|
||||||
|
maxCheckCount, intConversionErr := strconv.Atoi(constants.RecheckHeaderCap)
|
||||||
|
Expect(intConversionErr).NotTo(HaveOccurred())
|
||||||
|
_, markHeaderOneCheckedErr := db.Exec(
|
||||||
|
`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) VALUES ($1, $2)`,
|
||||||
|
headerOneID, maxCheckCount)
|
||||||
|
Expect(markHeaderOneCheckedErr).NotTo(HaveOccurred())
|
||||||
|
_, markHeaderTwoCheckedErr := db.Exec(
|
||||||
|
`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) VALUES ($1, $2)`,
|
||||||
|
headerTwoID, maxCheckCount)
|
||||||
|
Expect(markHeaderTwoCheckedErr).NotTo(HaveOccurred())
|
||||||
|
_, markHeaderThreeCheckedErr := db.Exec(
|
||||||
|
`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) VALUES ($1, $2)`,
|
||||||
|
headerThreeID, maxCheckCount+1)
|
||||||
|
Expect(markHeaderThreeCheckedErr).NotTo(HaveOccurred())
|
||||||
|
_, markHeaderFourCheckedErr := db.Exec(
|
||||||
|
`INSERT INTO public.checked_headers (header_id, `+checkedHeadersColumn+`) VALUES ($1, $2)`,
|
||||||
|
headerFourID, maxCheckCount)
|
||||||
|
Expect(markHeaderFourCheckedErr).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
_, cleanupMigrateErr := db.Exec(`ALTER TABLE public.checked_headers DROP COLUMN ` + checkedHeadersColumn)
|
||||||
|
Expect(cleanupMigrateErr).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when no ending block number (ending block number == -1)", func() {
|
||||||
|
It("returns all headers since starting block where checked count is less than cap", func() {
|
||||||
|
headers, err := shared.RecheckHeaders(1, -1, db, checkedHeadersColumn)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(len(headers)).To(Equal(3))
|
||||||
|
Expect(headers[0].Id).To(Or(Equal(headerOneID), Equal(headerTwoID), Equal(headerFourID)))
|
||||||
|
Expect(headers[1].Id).To(Or(Equal(headerOneID), Equal(headerTwoID), Equal(headerFourID)))
|
||||||
|
Expect(headers[2].Id).To(Or(Equal(headerOneID), Equal(headerTwoID), Equal(headerFourID)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("when ending block number specified", func() {
|
||||||
|
It("returns headers between starting and ending block where checked count is less than cap", func() {
|
||||||
|
headers, err := shared.RecheckHeaders(1, 3, db, checkedHeadersColumn)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(len(headers)).To(Equal(2))
|
||||||
|
Expect(headers[0].Id).To(Or(Equal(headerOneID), Equal(headerTwoID)))
|
||||||
|
Expect(headers[1].Id).To(Or(Equal(headerOneID), Equal(headerTwoID)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
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("CreateNotCheckedSQL", func() {
|
||||||
|
It("generates a correct SQL string for one column", func() {
|
||||||
|
columns := []string{"columnA"}
|
||||||
|
expected := "NOT (columnA!=0)"
|
||||||
|
actual := shared.CreateNotCheckedSQL(columns, constants.HeaderMissing)
|
||||||
|
Expect(actual).To(Equal(expected))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("generates a correct SQL string for several columns", func() {
|
||||||
|
columns := []string{"columnA", "columnB"}
|
||||||
|
expected := "NOT (columnA!=0 AND columnB!=0)"
|
||||||
|
actual := shared.CreateNotCheckedSQL(columns, constants.HeaderMissing)
|
||||||
|
Expect(actual).To(Equal(expected))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("defaults to FALSE when there are no columns", func() {
|
||||||
|
expected := "FALSE"
|
||||||
|
actual := shared.CreateNotCheckedSQL([]string{}, constants.HeaderMissing)
|
||||||
|
Expect(actual).To(Equal(expected))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("generates a correct SQL string for rechecking headers", func() {
|
||||||
|
columns := []string{"columnA", "columnB"}
|
||||||
|
expected := fmt.Sprintf("NOT (columnA>=%s AND columnB>=%s)", constants.RecheckHeaderCap, constants.RecheckHeaderCap)
|
||||||
|
actual := shared.CreateNotCheckedSQL(columns, constants.HeaderRecheck)
|
||||||
|
Expect(actual).To(Equal(expected))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func getExpectedColumnNames() []string {
|
||||||
|
return []string{
|
||||||
|
"column_1_checked",
|
||||||
|
"column_2_checked",
|
||||||
|
"column_3_checked",
|
||||||
|
"column_4_checked",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+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 storage
|
package repository
|
||||||
|
|
||||||
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 Repository interface {
|
type StorageRepository 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)
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func GetMapping(indexOnContract, key string) common.Hash {
|
func GetMapping(indexOnContract, key string) common.Hash {
|
||||||
keyBytes := common.FromHex(key + indexOnContract)
|
keyBytes := common.FromHex("0x" + key + indexOnContract)
|
||||||
encoded := crypto.Keccak256(keyBytes)
|
encoded := crypto.Keccak256(keyBytes)
|
||||||
return common.BytesToHash(encoded)
|
return common.BytesToHash(encoded)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,16 +21,6 @@ var _ = Describe("Mappings", func() {
|
|||||||
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() {
|
|
||||||
indexOfMappingOnContract := storage.IndexZero
|
|
||||||
keyForDesiredValueInMapping := "0x1234567890abcdef"
|
|
||||||
|
|
||||||
storageKey := storage.GetMapping(indexOfMappingOnContract, keyForDesiredValueInMapping)
|
|
||||||
|
|
||||||
expectedStorageKey := common.HexToHash("0xee0c1b59a3856bafbfb8730e7694c4badc271eb5f01ce4a8d7a53d8a6499676f")
|
|
||||||
Expect(storageKey).To(Equal(expectedStorageKey))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("GetNestedMapping", func() {
|
Describe("GetNestedMapping", func() {
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import (
|
|||||||
|
|
||||||
type IStorageQueue interface {
|
type IStorageQueue interface {
|
||||||
Add(row utils.StorageDiffRow) error
|
Add(row utils.StorageDiffRow) error
|
||||||
Delete(id int) error
|
|
||||||
GetAll() ([]utils.StorageDiffRow, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageQueue struct {
|
type StorageQueue struct {
|
||||||
@@ -38,18 +36,7 @@ func NewStorageQueue(db *postgres.DB) StorageQueue {
|
|||||||
func (queue StorageQueue) Add(row utils.StorageDiffRow) error {
|
func (queue StorageQueue) Add(row utils.StorageDiffRow) 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)`, row.Contract.Bytes(), row.BlockHash.Bytes(),
|
||||||
row.BlockHeight, row.StorageKey.Bytes(), row.StorageValue.Bytes())
|
row.BlockHeight, row.StorageKey.Bytes(), row.StorageValue.Bytes())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (queue StorageQueue) Delete(id int) error {
|
|
||||||
_, err := queue.db.Exec(`DELETE FROM public.queued_storage WHERE id = $1`, id)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (queue StorageQueue) GetAll() ([]utils.StorageDiffRow, error) {
|
|
||||||
var result []utils.StorageDiffRow
|
|
||||||
err := queue.db.Select(&result, `SELECT * FROM public.queued_storage`)
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,19 +1,3 @@
|
|||||||
// 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
|
package storage_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -23,90 +7,27 @@ import (
|
|||||||
|
|
||||||
"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/test_config"
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Storage queue", func() {
|
var _ = Describe("Storage queue", func() {
|
||||||
var (
|
It("adds a storage row to the db", func() {
|
||||||
db *postgres.DB
|
row := utils.StorageDiffRow{
|
||||||
row utils.StorageDiffRow
|
|
||||||
queue storage.IStorageQueue
|
|
||||||
)
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
|
||||||
row = utils.StorageDiffRow{
|
|
||||||
Contract: common.HexToAddress("0x123456"),
|
Contract: common.HexToAddress("0x123456"),
|
||||||
BlockHash: common.HexToHash("0x678901"),
|
BlockHash: common.HexToHash("0x678901"),
|
||||||
BlockHeight: 987,
|
BlockHeight: 987,
|
||||||
StorageKey: common.HexToHash("0x654321"),
|
StorageKey: common.HexToHash("0x654321"),
|
||||||
StorageValue: common.HexToHash("0x198765"),
|
StorageValue: common.HexToHash("0x198765"),
|
||||||
}
|
}
|
||||||
db = test_config.NewTestDB(test_config.NewTestNode())
|
db := test_config.NewTestDB(test_config.NewTestNode())
|
||||||
test_config.CleanTestDB(db)
|
queue := storage.NewStorageQueue(db)
|
||||||
queue = storage.NewStorageQueue(db)
|
|
||||||
addErr := queue.Add(row)
|
addErr := queue.Add(row)
|
||||||
|
|
||||||
Expect(addErr).NotTo(HaveOccurred())
|
Expect(addErr).NotTo(HaveOccurred())
|
||||||
})
|
var result utils.StorageDiffRow
|
||||||
|
getErr := db.Get(&result, `SELECT contract, block_hash, block_height, storage_key, storage_value FROM public.queued_storage`)
|
||||||
Describe("Add", func() {
|
|
||||||
It("adds a storage row to the db", func() {
|
|
||||||
var result utils.StorageDiffRow
|
|
||||||
getErr := db.Get(&result, `SELECT contract, block_hash, block_height, storage_key, storage_value FROM public.queued_storage`)
|
|
||||||
Expect(getErr).NotTo(HaveOccurred())
|
|
||||||
Expect(result).To(Equal(row))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("does not duplicate storage rows", func() {
|
|
||||||
addErr := queue.Add(row)
|
|
||||||
Expect(addErr).NotTo(HaveOccurred())
|
|
||||||
var count int
|
|
||||||
getErr := db.Get(&count, `SELECT count(*) FROM public.queued_storage`)
|
|
||||||
Expect(getErr).NotTo(HaveOccurred())
|
|
||||||
Expect(count).To(Equal(1))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
It("deletes storage row from db", func() {
|
|
||||||
rows, getErr := queue.GetAll()
|
|
||||||
Expect(getErr).NotTo(HaveOccurred())
|
Expect(getErr).NotTo(HaveOccurred())
|
||||||
Expect(len(rows)).To(Equal(1))
|
Expect(result).To(Equal(row))
|
||||||
|
|
||||||
err := queue.Delete(rows[0].Id)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
remainingRows, secondGetErr := queue.GetAll()
|
|
||||||
Expect(secondGetErr).NotTo(HaveOccurred())
|
|
||||||
Expect(len(remainingRows)).To(BeZero())
|
|
||||||
})
|
|
||||||
|
|
||||||
It("gets all storage rows from db", func() {
|
|
||||||
rowTwo := utils.StorageDiffRow{
|
|
||||||
Contract: common.HexToAddress("0x123456"),
|
|
||||||
BlockHash: common.HexToHash("0x678902"),
|
|
||||||
BlockHeight: 988,
|
|
||||||
StorageKey: common.HexToHash("0x654322"),
|
|
||||||
StorageValue: common.HexToHash("0x198766"),
|
|
||||||
}
|
|
||||||
addErr := queue.Add(rowTwo)
|
|
||||||
Expect(addErr).NotTo(HaveOccurred())
|
|
||||||
|
|
||||||
rows, err := queue.GetAll()
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(len(rows)).To(Equal(2))
|
|
||||||
Expect(rows[0]).NotTo(Equal(rows[1]))
|
|
||||||
Expect(rows[0].Id).NotTo(BeZero())
|
|
||||||
Expect(rows[0].Contract).To(Or(Equal(row.Contract), Equal(rowTwo.Contract)))
|
|
||||||
Expect(rows[0].BlockHash).To(Or(Equal(row.BlockHash), Equal(rowTwo.BlockHash)))
|
|
||||||
Expect(rows[0].BlockHeight).To(Or(Equal(row.BlockHeight), Equal(rowTwo.BlockHeight)))
|
|
||||||
Expect(rows[0].StorageKey).To(Or(Equal(row.StorageKey), Equal(rowTwo.StorageKey)))
|
|
||||||
Expect(rows[0].StorageValue).To(Or(Equal(row.StorageValue), Equal(rowTwo.StorageValue)))
|
|
||||||
Expect(rows[1].Id).NotTo(BeZero())
|
|
||||||
Expect(rows[1].Contract).To(Or(Equal(row.Contract), Equal(rowTwo.Contract)))
|
|
||||||
Expect(rows[1].BlockHash).To(Or(Equal(row.BlockHash), Equal(rowTwo.BlockHash)))
|
|
||||||
Expect(rows[1].BlockHeight).To(Or(Equal(row.BlockHeight), Equal(rowTwo.BlockHeight)))
|
|
||||||
Expect(rows[1].StorageKey).To(Or(Equal(row.StorageKey), Equal(rowTwo.StorageKey)))
|
|
||||||
Expect(rows[1].StorageValue).To(Or(Equal(row.StorageValue), Equal(rowTwo.StorageValue)))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,30 +23,27 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
bitsPerByte = 8
|
|
||||||
)
|
|
||||||
|
|
||||||
func Decode(row StorageDiffRow, metadata StorageValueMetadata) (interface{}, error) {
|
func Decode(row StorageDiffRow, metadata StorageValueMetadata) (interface{}, error) {
|
||||||
switch metadata.Type {
|
switch metadata.Type {
|
||||||
case Uint256:
|
case Uint256:
|
||||||
return decodeInteger(row.StorageValue.Bytes()), nil
|
return decodeUint256(row.StorageValue.Bytes()), nil
|
||||||
case Uint48:
|
case Uint48:
|
||||||
return decodeInteger(row.StorageValue.Bytes()), nil
|
return decodeUint48(row.StorageValue.Bytes()), nil
|
||||||
case Uint128:
|
|
||||||
return decodeInteger(row.StorageValue.Bytes()), nil
|
|
||||||
case Address:
|
case Address:
|
||||||
return decodeAddress(row.StorageValue.Bytes()), nil
|
return decodeAddress(row.StorageValue.Bytes()), nil
|
||||||
case Bytes32:
|
case Bytes32:
|
||||||
return row.StorageValue.Hex(), nil
|
return row.StorageValue.Hex(), nil
|
||||||
case PackedSlot:
|
|
||||||
return decodePackedSlot(row.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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeInteger(raw []byte) string {
|
func decodeUint256(raw []byte) string {
|
||||||
|
n := big.NewInt(0).SetBytes(raw)
|
||||||
|
return n.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeUint48(raw []byte) string {
|
||||||
n := big.NewInt(0).SetBytes(raw)
|
n := big.NewInt(0).SetBytes(raw)
|
||||||
return n.String()
|
return n.String()
|
||||||
}
|
}
|
||||||
@@ -54,53 +51,3 @@ func decodeInteger(raw []byte) string {
|
|||||||
func decodeAddress(raw []byte) string {
|
func decodeAddress(raw []byte) string {
|
||||||
return common.BytesToAddress(raw).Hex()
|
return common.BytesToAddress(raw).Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodePackedSlot(raw []byte, packedTypes map[int]ValueType) map[int]string {
|
|
||||||
storageSlotData := raw
|
|
||||||
decodedStorageSlotItems := map[int]string{}
|
|
||||||
numberOfTypes := len(packedTypes)
|
|
||||||
|
|
||||||
for position := 0; position < numberOfTypes; position++ {
|
|
||||||
//get length of remaining storage date
|
|
||||||
lengthOfStorageData := len(storageSlotData)
|
|
||||||
|
|
||||||
//get item details (type, length, starting index, value bytes)
|
|
||||||
itemType := packedTypes[position]
|
|
||||||
lengthOfItem := getNumberOfBytes(itemType)
|
|
||||||
itemStartingIndex := lengthOfStorageData - lengthOfItem
|
|
||||||
itemValueBytes := storageSlotData[itemStartingIndex:]
|
|
||||||
|
|
||||||
//decode item's bytes and set in results map
|
|
||||||
decodedValue := decodeIndividualItem(itemValueBytes, itemType)
|
|
||||||
decodedStorageSlotItems[position] = decodedValue
|
|
||||||
|
|
||||||
//pop last item off raw slot data before moving on
|
|
||||||
storageSlotData = storageSlotData[0:itemStartingIndex]
|
|
||||||
}
|
|
||||||
|
|
||||||
return decodedStorageSlotItems
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeIndividualItem(itemBytes []byte, valueType ValueType) string {
|
|
||||||
switch valueType {
|
|
||||||
case Uint48, Uint128:
|
|
||||||
return decodeInteger(itemBytes)
|
|
||||||
case Address:
|
|
||||||
return decodeAddress(itemBytes)
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("can't decode unknown type: %d", valueType))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNumberOfBytes(valueType ValueType) int {
|
|
||||||
switch valueType {
|
|
||||||
case Uint48:
|
|
||||||
return 48 / bitsPerByte
|
|
||||||
case Uint128:
|
|
||||||
return 128 / bitsPerByte
|
|
||||||
case Address:
|
|
||||||
return 20
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("ValueType %d not recognized", valueType))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -38,17 +38,6 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("decodes uint128", func() {
|
|
||||||
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000011123")
|
|
||||||
row := utils.StorageDiffRow{StorageValue: fakeInt}
|
|
||||||
metadata := utils.StorageValueMetadata{Type: utils.Uint128}
|
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("decodes uint48", func() {
|
It("decodes uint48", func() {
|
||||||
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000123")
|
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000123")
|
||||||
row := utils.StorageDiffRow{StorageValue: fakeInt}
|
row := utils.StorageDiffRow{StorageValue: fakeInt}
|
||||||
@@ -70,105 +59,4 @@ var _ = Describe("Storage decoder", func() {
|
|||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(result).To(Equal(fakeAddress.Hex()))
|
Expect(result).To(Equal(fakeAddress.Hex()))
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("when there are multiple items packed in the storage slot", func() {
|
|
||||||
It("decodes uint48 items", func() {
|
|
||||||
//this is a real storage data example
|
|
||||||
packedStorage := common.HexToHash("000000000000000000000000000000000000000000000002a300000000002a30")
|
|
||||||
row := utils.StorageDiffRow{StorageValue: packedStorage}
|
|
||||||
packedTypes := map[int]utils.ValueType{}
|
|
||||||
packedTypes[0] = utils.Uint48
|
|
||||||
packedTypes[1] = utils.Uint48
|
|
||||||
|
|
||||||
metadata := utils.StorageValueMetadata{
|
|
||||||
Type: utils.PackedSlot,
|
|
||||||
PackedTypes: packedTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
|
||||||
decodedValues := result.(map[int]string)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(decodedValues[0]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("2a30").Bytes()).String()))
|
|
||||||
Expect(decodedValues[1]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("2a300").Bytes()).String()))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("decodes 5 uint48 items", func() {
|
|
||||||
//TODO: this packedStorageHex was generated by hand, it would be nice to test this against
|
|
||||||
//real storage data that has several items packed into it
|
|
||||||
packedStorageHex := "0000000A5D1AFFFFFFFFFFFE00000009F3C600000002A300000000002A30"
|
|
||||||
|
|
||||||
packedStorage := common.HexToHash(packedStorageHex)
|
|
||||||
row := utils.StorageDiffRow{StorageValue: packedStorage}
|
|
||||||
packedTypes := map[int]utils.ValueType{}
|
|
||||||
packedTypes[0] = utils.Uint48
|
|
||||||
packedTypes[1] = utils.Uint48
|
|
||||||
packedTypes[2] = utils.Uint48
|
|
||||||
packedTypes[3] = utils.Uint48
|
|
||||||
packedTypes[4] = utils.Uint48
|
|
||||||
|
|
||||||
metadata := utils.StorageValueMetadata{
|
|
||||||
Type: utils.PackedSlot,
|
|
||||||
PackedTypes: packedTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
|
||||||
decodedValues := result.(map[int]string)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(decodedValues[0]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("2a30").Bytes()).String()))
|
|
||||||
Expect(decodedValues[1]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("2a300").Bytes()).String()))
|
|
||||||
Expect(decodedValues[2]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("9F3C6").Bytes()).String()))
|
|
||||||
Expect(decodedValues[3]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("FFFFFFFFFFFE").Bytes()).String()))
|
|
||||||
Expect(decodedValues[4]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("A5D1A").Bytes()).String()))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("decodes 2 uint128 items", func() {
|
|
||||||
//TODO: this packedStorageHex was generated by hand, it would be nice to test this against
|
|
||||||
//real storage data that has several items packed into it
|
|
||||||
packedStorageHex := "000000038D7EA4C67FF8E502B6730000" +
|
|
||||||
"0000000000000000AB54A98CEB1F0AD2"
|
|
||||||
packedStorage := common.HexToHash(packedStorageHex)
|
|
||||||
row := utils.StorageDiffRow{StorageValue: packedStorage}
|
|
||||||
packedTypes := map[int]utils.ValueType{}
|
|
||||||
packedTypes[0] = utils.Uint128
|
|
||||||
packedTypes[1] = utils.Uint128
|
|
||||||
|
|
||||||
metadata := utils.StorageValueMetadata{
|
|
||||||
Type: utils.PackedSlot,
|
|
||||||
PackedTypes: packedTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
|
||||||
decodedValues := result.(map[int]string)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(decodedValues[0]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("AB54A98CEB1F0AD2").Bytes()).String()))
|
|
||||||
Expect(decodedValues[1]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("38D7EA4C67FF8E502B6730000").Bytes()).String()))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("decodes address + 2 uint48s", func() {
|
|
||||||
//TODO: replace with real data when available
|
|
||||||
addressHex := "0000000000000000000000000000000000012345"
|
|
||||||
packedStorage := common.HexToHash("00000002a300" + "000000002a30" + addressHex)
|
|
||||||
row := utils.StorageDiffRow{StorageValue: packedStorage}
|
|
||||||
packedTypes := map[int]utils.ValueType{}
|
|
||||||
packedTypes[0] = utils.Address
|
|
||||||
packedTypes[1] = utils.Uint48
|
|
||||||
packedTypes[2] = utils.Uint48
|
|
||||||
|
|
||||||
metadata := utils.StorageValueMetadata{
|
|
||||||
Type: utils.PackedSlot,
|
|
||||||
PackedTypes: packedTypes,
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := utils.Decode(row, metadata)
|
|
||||||
decodedValues := result.(map[int]string)
|
|
||||||
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(decodedValues[0]).To(Equal("0x" + addressHex))
|
|
||||||
Expect(decodedValues[1]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("2a30").Bytes()).String()))
|
|
||||||
Expect(decodedValues[2]).To(Equal(big.NewInt(0).SetBytes(common.HexToHash("2a300").Bytes()).String()))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import (
|
|||||||
const ExpectedRowLength = 5
|
const ExpectedRowLength = 5
|
||||||
|
|
||||||
type StorageDiffRow struct {
|
type StorageDiffRow struct {
|
||||||
Id int
|
|
||||||
Contract common.Address
|
Contract common.Address
|
||||||
BlockHash common.Hash `db:"block_hash"`
|
BlockHash common.Hash `db:"block_hash"`
|
||||||
BlockHeight int `db:"block_height"`
|
BlockHeight int `db:"block_height"`
|
||||||
|
|||||||
@@ -16,54 +16,27 @@
|
|||||||
|
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type ValueType int
|
type ValueType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Uint256 ValueType = iota
|
Uint256 ValueType = iota
|
||||||
Uint48
|
Uint48
|
||||||
Uint128
|
|
||||||
Bytes32
|
Bytes32
|
||||||
Address
|
Address
|
||||||
PackedSlot
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Key string
|
type Key string
|
||||||
|
|
||||||
type StorageValueMetadata struct {
|
type StorageValueMetadata struct {
|
||||||
Name string
|
Name string
|
||||||
Keys map[Key]string
|
Keys map[Key]string
|
||||||
Type ValueType
|
Type ValueType
|
||||||
PackedNames map[int]string //zero indexed position in map => name of packed item
|
|
||||||
PackedTypes map[int]ValueType //zero indexed position in map => type of packed item
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStorageValueMetadata(name string, keys map[Key]string, valueType ValueType) StorageValueMetadata {
|
func GetStorageValueMetadata(name string, keys map[Key]string, t ValueType) StorageValueMetadata {
|
||||||
return getMetadata(name, keys, valueType, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetStorageValueMetadataForPackedSlot(name string, keys map[Key]string, valueType ValueType, packedNames map[int]string, packedTypes map[int]ValueType) StorageValueMetadata {
|
|
||||||
return getMetadata(name, keys, valueType, packedNames, packedTypes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMetadata(name string, keys map[Key]string, valueType ValueType, packedNames map[int]string, packedTypes map[int]ValueType) StorageValueMetadata {
|
|
||||||
assertPackedSlotArgs(valueType, packedNames, packedTypes)
|
|
||||||
|
|
||||||
return StorageValueMetadata{
|
return StorageValueMetadata{
|
||||||
Name: name,
|
Name: name,
|
||||||
Keys: keys,
|
Keys: keys,
|
||||||
Type: valueType,
|
Type: t,
|
||||||
PackedNames: packedNames,
|
|
||||||
PackedTypes: packedTypes,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertPackedSlotArgs(valueType ValueType, packedNames map[int]string, packedTypes map[int]ValueType) {
|
|
||||||
if valueType == PackedSlot && (packedTypes == nil || packedNames == nil) {
|
|
||||||
panic(fmt.Sprintf("ValueType is PackedSlot. Expected PackedNames and PackedTypes to not be nil, but got PackedNames = %v and PackedTypes = %v", packedNames, packedTypes))
|
|
||||||
} else if (packedNames != nil && packedTypes != nil) && valueType != PackedSlot {
|
|
||||||
panic(fmt.Sprintf("PackedNames and PackedTypes passed in. Expected ValueType to equal PackedSlot (%v), but got %v.", PackedSlot, valueType))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user