diff --git a/go.mod b/go.mod index 34406d05..2be8d2c0 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/ipfs/go-ipfs-ds-help v1.0.0 github.com/jmoiron/sqlx v1.3.5 github.com/joho/godotenv v1.4.0 - github.com/lib/pq v1.10.5 + github.com/lib/pq v1.10.6 github.com/machinebox/graphql v0.2.2 github.com/mailgun/groupcache/v2 v2.3.0 github.com/multiformats/go-multihash v0.1.0 @@ -24,10 +24,13 @@ require ( github.com/vulcanize/eth-ipfs-state-validator/v4 v4.0.1-alpha github.com/vulcanize/gap-filler v0.3.1 github.com/vulcanize/ipfs-ethdb/v4 v4.0.1-alpha + gorm.io/driver/postgres v1.3.7 + gorm.io/gorm v1.23.5 ) require ( bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect + github.com/ClickHouse/clickhouse-go v1.5.4 // indirect github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/Stebalien/go-bitfield v0.0.1 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect @@ -40,6 +43,7 @@ require ( github.com/cenkalti/backoff/v4 v4.1.1 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/cheekybits/genny v1.0.0 // indirect + github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect github.com/cskr/pubsub v1.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -47,6 +51,7 @@ require ( github.com/deckarep/golang-set v1.8.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect + github.com/denisenkom/go-mssqldb v0.12.2 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect @@ -57,10 +62,13 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/georgysavva/scany v0.2.9 // indirect github.com/go-ole/go-ole v1.2.1 // indirect + github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.3.0 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect @@ -123,18 +131,20 @@ require ( github.com/ipld/go-codec-dagpb v1.3.0 // indirect github.com/ipld/go-ipld-prime v0.12.2 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.10.0 // indirect + github.com/jackc/pgconn v1.12.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.1.1 // indirect + github.com/jackc/pgproto3/v2 v2.3.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.8.1 // indirect - github.com/jackc/pgx/v4 v4.13.0 // indirect - github.com/jackc/puddle v1.1.3 // indirect + github.com/jackc/pgtype v1.11.0 // indirect + github.com/jackc/pgx/v4 v4.16.1 // indirect + github.com/jackc/puddle v1.2.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/jinzhu/copier v0.2.4 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.4 // indirect github.com/klauspost/compress v1.11.7 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/koron/go-ssdp v0.0.2 // indirect @@ -195,6 +205,7 @@ require ( github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/miekg/dns v1.1.43 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect @@ -224,6 +235,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect + github.com/pressly/goose v2.7.0+incompatible // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.30.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect @@ -255,6 +267,7 @@ require ( github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 // indirect github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect + github.com/ziutek/mymysql v1.5.4 // indirect go.opencensus.io v0.23.0 // indirect go.opentelemetry.io/otel v0.20.0 // indirect go.opentelemetry.io/otel/metric v0.20.0 // indirect @@ -265,7 +278,7 @@ require ( go.uber.org/multierr v1.7.0 // indirect go.uber.org/zap v1.19.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect - golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect diff --git a/go.sum b/go.sum index e1501396..7bf5cf19 100644 --- a/go.sum +++ b/go.sum @@ -57,7 +57,10 @@ github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIo github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= @@ -73,9 +76,12 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0= +github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= @@ -135,6 +141,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= @@ -192,6 +199,8 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg= +github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -251,6 +260,8 @@ github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denisenkom/go-mssqldb v0.12.2 h1:1OcPn5GBIobjWNd+8yjfHNIaFX14B1pWI3F9HZy5KXw= +github.com/denisenkom/go-mssqldb v0.12.2/go.mod h1:lnIw1mZukFRZDJYQ0Pb833QS2IaC3l5HkEfra2LJ+sk= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= @@ -381,6 +392,10 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -788,8 +803,9 @@ github.com/jackc/pgconn v1.7.0/go.mod h1:sF/lPpNEMEOp+IYhyQGdAvrG20gWf6A1tKlr0v7 github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.10.0 h1:4EYhlDVEMsJ30nNj0mmgwIUXoq7e9sMJrVC2ED6QlCU= github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8= +github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -807,8 +823,9 @@ github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.5/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y= +github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= @@ -821,8 +838,9 @@ github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkAL github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= github.com/jackc/pgtype v1.4.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.8.1 h1:9k0IXtdJXHJbyAWQgbWr1lU+MEhPXZz6RIXxfR5oxXs= github.com/jackc/pgtype v1.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs= +github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= @@ -833,15 +851,17 @@ github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6 github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= github.com/jackc/pgx/v4 v4.8.1/go.mod h1:4HOLxrl8wToZJReD04/yB20GDwf4KBYETvlHciCnwW0= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.13.0 h1:JCjhT5vmhMAf/YwBHLvrBn4OGdIQBiFG6ym8Zmdx570= github.com/jackc/pgx/v4 v4.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0= +github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= +github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3 h1:JnPg/5Q9xVJGfjsO5CPUOjnJps1JaRUm8I9FXVCFK94= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= +github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= @@ -866,8 +886,11 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jinzhu/copier v0.2.4 h1:dT3tI+8GzU8DjJFCj9mLYtjfRtUmK7edauduQdcZCpI= github.com/jinzhu/copier v0.2.4/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= @@ -948,6 +971,8 @@ github.com/lib/pq v1.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ= github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= github.com/libp2p/go-addr-util v0.1.0 h1:acKsntI33w2bTU7tC9a0SaPimJGfSI0bFKC18ChxeVI= @@ -1343,6 +1368,8 @@ github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= +github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1536,6 +1563,7 @@ github.com/pganalyze/pg_query_go/v2 v2.1.0/go.mod h1:XAxmVqz1tEGqizcQ3YSdN90vCOH github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -1551,6 +1579,8 @@ github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXx github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls= github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pressly/goose v2.7.0+incompatible h1:PWejVEv07LCerQEzMMeAtjuyCKbyprZ/LBa6K5P0OCQ= +github.com/pressly/goose v2.7.0+incompatible/go.mod h1:m+QHWCqxR3k8D9l7qfzuC/djtlfzxr34mozWDYEu1z8= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= @@ -1815,6 +1845,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= @@ -1908,6 +1940,7 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1922,6 +1955,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2423,6 +2458,11 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.3.7 h1:FKF6sIMDHDEvvMF/XJvbnCl0nu6KSKUaPXevJ4r+VYQ= +gorm.io/driver/postgres v1.3.7/go.mod h1:f02ympjIcgtHEGFMZvdgTxODZ9snAHDb4hXfigBVuNI= +gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM= +gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/eth/cid_retriever.go b/pkg/eth/cid_retriever.go index c7968594..7e5edfe4 100644 --- a/pkg/eth/cid_retriever.go +++ b/pkg/eth/cid_retriever.go @@ -27,6 +27,8 @@ import ( "github.com/jmoiron/sqlx" "github.com/lib/pq" log "github.com/sirupsen/logrus" + "gorm.io/driver/postgres" + "gorm.io/gorm" "github.com/vulcanize/ipld-eth-server/v4/pkg/shared" ) @@ -40,13 +42,75 @@ type Retriever interface { // CIDRetriever satisfies the CIDRetriever interface for ethereum type CIDRetriever struct { - db *sqlx.DB + db *sqlx.DB + gormDB *gorm.DB +} + +type IPLDModelRecord struct { + models.IPLDModel +} + +// TableName overrides the table name used by IPLD +func (IPLDModelRecord) TableName() string { + return "public.blocks" +} + +type HeaderCIDRecord struct { + CID string `gorm:"column:cid"` + BlockHash string `gorm:"primaryKey"` + BlockNumber string `gorm:"primaryKey"` + ParentHash string + Timestamp uint64 + StateRoot string + TotalDifficulty string `gorm:"column:td"` + TxRoot string + RctRoot string `gorm:"column:receipt_root"` + UncleRoot string + Bloom []byte + MhKey string + + // gorm doesn't check if foreign key exists in database. + // It is required to eager load relations using preload. + TransactionCIDs []TransactionCIDRecord `gorm:"foreignKey:HeaderID,BlockNumber;references:BlockHash,BlockNumber"` + IPLD IPLDModelRecord `gorm:"foreignKey:MhKey,BlockNumber;references:Key,BlockNumber"` +} + +// TableName overrides the table name used by HeaderCIDRecord +func (HeaderCIDRecord) TableName() string { + return "eth.header_cids" +} + +type TransactionCIDRecord struct { + CID string `gorm:"column:cid"` + TxHash string `gorm:"primaryKey"` + BlockNumber string `gorm:"primaryKey"` + HeaderID string `gorm:"column:header_id"` + Index int64 + Src string + Dst string + MhKey string + IPLD IPLDModelRecord `gorm:"foreignKey:MhKey,BlockNumber;references:Key,BlockNumber"` +} + +// TableName overrides the table name used by TransactionCIDRecord +func (TransactionCIDRecord) TableName() string { + return "eth.transaction_cids" } // NewCIDRetriever returns a pointer to a new CIDRetriever which supports the CIDRetriever interface func NewCIDRetriever(db *sqlx.DB) *CIDRetriever { + gormDB, err := gorm.Open(postgres.New(postgres.Config{ + Conn: db, + }), &gorm.Config{}) + + if err != nil { + log.Error(err) + return nil + } + return &CIDRetriever{ - db: db, + db: db, + gormDB: gormDB, } } @@ -169,7 +233,7 @@ func (ecr *CIDRetriever) RetrieveHeaderCIDs(tx *sqlx.Tx, blockNumber int64) ([]m log.Debug("retrieving header cids for block ", blockNumber) headers := make([]models.HeaderModel, 0) pgStr := `SELECT CAST(block_number as Text), block_hash, parent_hash, cid, mh_key, CAST(td as Text), node_id, - CAST(reward as Text), state_root, uncle_root,tx_root, receipt_root,bloom, timestamp, times_validated, coinbase + CAST(reward as Text), state_root, uncle_root,tx_root, receipt_root, bloom, timestamp, times_validated, coinbase FROM eth.header_cids WHERE block_number = $1` return headers, tx.Select(&headers, pgStr, blockNumber) @@ -313,8 +377,8 @@ func (ecr *CIDRetriever) RetrieveRctCIDsByHeaderID(tx *sqlx.Tx, rctFilter Receip pgStr, args = receiptFilterConditions(&id, pgStr, args, rctFilter, trxHashes) pgStr += ` ORDER BY transaction_cids.index` - receiptCids := make([]models.ReceiptModel, 0) - return receiptCids, tx.Select(&receiptCids, pgStr, args...) + receiptCIDs := make([]models.ReceiptModel, 0) + return receiptCIDs, tx.Select(&receiptCIDs, pgStr, args...) } // RetrieveFilteredGQLLogs retrieves and returns all the log CIDs provided blockHash that conform to the provided @@ -419,8 +483,8 @@ func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, b pgStr, args = receiptFilterConditions(&id, pgStr, args, rctFilter, txHashes) pgStr += ` ORDER BY transaction_cids.index` - receiptCids := make([]models.ReceiptModel, 0) - return receiptCids, tx.Select(&receiptCids, pgStr, args...) + receiptCIDs := make([]models.ReceiptModel, 0) + return receiptCIDs, tx.Select(&receiptCIDs, pgStr, args...) } func hasTopics(topics [][]string) bool { @@ -608,7 +672,8 @@ func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (models.Header // RetrieveHeaderCIDByHash returns the header for the given block hash func (ecr *CIDRetriever) RetrieveHeaderCIDByHash(tx *sqlx.Tx, blockHash common.Hash) (models.HeaderModel, error) { log.Debug("retrieving header cids for block hash ", blockHash.String()) - pgStr := `SELECT block_hash, CAST(block_number as Text), cid, mh_key FROM eth.header_cids + pgStr := `SELECT block_hash, CAST(block_number as Text), parent_hash, cid, mh_key, CAST(td as Text), + state_root, uncle_root, tx_root, receipt_root, bloom, timestamp FROM eth.header_cids WHERE block_hash = $1` var headerCID models.HeaderModel return headerCID, tx.Get(&headerCID, pgStr, blockHash.String()) @@ -639,3 +704,58 @@ func (ecr *CIDRetriever) RetrieveReceiptCIDsByTxIDs(tx *sqlx.Tx, txHashes []stri var rctCIDs []models.ReceiptModel return rctCIDs, tx.Select(&rctCIDs, pgStr, pq.Array(txHashes)) } + +// RetrieveHeaderAndTxCIDsByBlockNumber retrieves header CIDs and their associated tx CIDs by block number +func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockNumber(blockNumber int64) ([]HeaderCIDRecord, error) { + log.Debug("retrieving header cids and tx cids for block number ", blockNumber) + + var headerCIDs []HeaderCIDRecord + + // https://github.com/go-gorm/gorm/issues/4083#issuecomment-778883283 + // Will use join for TransactionCIDs once preload for 1:N is supported. + err := ecr.gormDB.Preload("TransactionCIDs", func(tx *gorm.DB) *gorm.DB { + return tx.Select("cid", "tx_hash", "index", "src", "dst", "header_id", "block_number") + }).Joins("IPLD").Find(&headerCIDs, "header_cids.block_number = ?", blockNumber).Error + + if err != nil { + log.Error("header cid retrieval error") + return nil, err + } + + return headerCIDs, nil +} + +// RetrieveHeaderAndTxCIDsByBlockHash retrieves header CID and their associated tx CIDs by block hash +func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockHash(blockHash common.Hash) (HeaderCIDRecord, error) { + log.Debug("retrieving header cid and tx cids for block hash ", blockHash.String()) + + var headerCID HeaderCIDRecord + + // https://github.com/go-gorm/gorm/issues/4083#issuecomment-778883283 + // Will use join for TransactionCIDs once preload for 1:N is supported. + err := ecr.gormDB.Preload("TransactionCIDs", func(tx *gorm.DB) *gorm.DB { + return tx.Select("cid", "tx_hash", "index", "src", "dst", "header_id", "block_number") + }).Joins("IPLD").First(&headerCID, "block_hash = ?", blockHash.String()).Error + + if err != nil { + log.Error("header cid retrieval error") + return headerCID, err + } + + return headerCID, nil +} + +// RetrieveTxCIDByHash returns the tx for the given tx hash +func (ecr *CIDRetriever) RetrieveTxCIDByHash(txHash string) (TransactionCIDRecord, error) { + log.Debug("retrieving tx cid for tx hash ", txHash) + + var txCID TransactionCIDRecord + + err := ecr.gormDB.Joins("IPLD").First(&txCID, "tx_hash = ?", txHash).Error + if err != nil { + log.Error("header cid retrieval error") + return txCID, err + } + + return txCID, nil +} diff --git a/pkg/eth/ipld_fetcher.go b/pkg/eth/ipld_fetcher.go index e8b459d5..ea435b63 100644 --- a/pkg/eth/ipld_fetcher.go +++ b/pkg/eth/ipld_fetcher.go @@ -100,7 +100,7 @@ func (f *IPLDFetcher) Fetch(cids CIDWrapper) (*IPLDs, error) { return iplds, err } -// FetchHeaders fetches headers +// FetchHeader fetches header func (f *IPLDFetcher) FetchHeader(tx *sqlx.Tx, c models.HeaderModel) (models.IPLDModel, error) { log.Debug("fetching header ipld") blockNumber, err := strconv.ParseUint(c.BlockNumber, 10, 64) diff --git a/pkg/graphql/client.go b/pkg/graphql/client.go index 1040b1bc..096b7a06 100644 --- a/pkg/graphql/client.go +++ b/pkg/graphql/client.go @@ -11,7 +11,7 @@ import ( ) type StorageResponse struct { - Cid string `json:"cid"` + CID string `json:"cid"` Value common.Hash `json:"value"` IpldBlock hexutil.Bytes `json:"ipldBlock"` } @@ -21,14 +21,14 @@ type GetStorageAt struct { } type LogResponse struct { - Topics []common.Hash `json:"topics"` - Data hexutil.Bytes `json:"data"` - Transaction TransactionResp `json:"transaction"` - ReceiptCID string `json:"receiptCID"` - Status int32 `json:"status"` + Topics []common.Hash `json:"topics"` + Data hexutil.Bytes `json:"data"` + Transaction TransactionResponse `json:"transaction"` + ReceiptCID string `json:"receiptCID"` + Status int32 `json:"status"` } -type TransactionResp struct { +type TransactionResponse struct { Hash common.Hash `json:"hash"` } @@ -36,6 +36,52 @@ type GetLogs struct { Responses []LogResponse `json:"getLogs"` } +type IPFSBlockResponse struct { + Key string `json:"key"` + Data string `json:"data"` +} + +type EthTransactionCIDResponse struct { + CID string `json:"cid"` + TxHash string `json:"txHash"` + Index int32 `json:"index"` + Src string `json:"src"` + Dst string `json:"dst"` + BlockByMhKey IPFSBlockResponse `json:"blockByMhKey"` +} + +type EthTransactionCIDByTxHash struct { + Response EthTransactionCIDResponse `json:"ethTransactionCidByTxHash"` +} + +type EthTransactionCIDsByHeaderIdResponse struct { + Nodes []EthTransactionCIDResponse `json:"nodes"` +} + +type EthHeaderCIDResponse struct { + CID string `json:"cid"` + BlockNumber BigInt `json:"blockNumber"` + BlockHash string `json:"blockHash"` + ParentHash string `json:"parentHash"` + Timestamp BigInt `json:"timestamp"` + StateRoot string `json:"stateRoot"` + Td BigInt `json:"td"` + TxRoot string `json:"txRoot"` + ReceiptRoot string `json:"receiptRoot"` + UncleRoot string `json:"uncleRoot"` + Bloom string `json:"bloom"` + EthTransactionCIDsByHeaderId EthTransactionCIDsByHeaderIdResponse `json:"ethTransactionCidsByHeaderId"` + BlockByMhKey IPFSBlockResponse `json:"blockByMhKey"` +} + +type AllEthHeaderCIDsResponse struct { + Nodes []EthHeaderCIDResponse `json:"nodes"` +} + +type AllEthHeaderCIDs struct { + Response AllEthHeaderCIDsResponse `json:"allEthHeaderCids"` +} + type Client struct { client *gqlclient.Client } @@ -117,3 +163,105 @@ func (c *Client) GetStorageAt(ctx context.Context, hash common.Hash, address com } return &storageAt.Response, nil } + +func (c *Client) AllEthHeaderCIDs(ctx context.Context, condition EthHeaderCIDCondition) (*AllEthHeaderCIDsResponse, error) { + var params string + if condition.BlockHash != nil { + params = fmt.Sprintf(`blockHash: "%s"`, *condition.BlockHash) + } + if condition.BlockNumber != nil { + params += fmt.Sprintf(`blockNumber: "%s"`, condition.BlockNumber.String()) + } + + getHeadersQuery := fmt.Sprintf(` + query{ + allEthHeaderCids(condition: { %s }) { + nodes { + cid + blockNumber + blockHash + parentHash + timestamp + stateRoot + td + txRoot + receiptRoot + uncleRoot + bloom + blockByMhKey { + key + data + } + ethTransactionCidsByHeaderId { + nodes { + cid + txHash + index + src + dst + } + } + } + } + } + `, params) + + req := gqlclient.NewRequest(getHeadersQuery) + req.Header.Set("Cache-Control", "no-cache") + + var respData map[string]interface{} + err := c.client.Run(ctx, req, &respData) + if err != nil { + return nil, err + } + + jsonStr, err := json.Marshal(respData) + if err != nil { + return nil, err + } + + var allEthHeaderCIDs AllEthHeaderCIDs + err = json.Unmarshal(jsonStr, &allEthHeaderCIDs) + if err != nil { + return nil, err + } + return &allEthHeaderCIDs.Response, nil +} + +func (c *Client) EthTransactionCIDByTxHash(ctx context.Context, txHash string) (*EthTransactionCIDResponse, error) { + getTxQuery := fmt.Sprintf(` + query{ + ethTransactionCidByTxHash(txHash: "%s") { + cid + txHash + index + src + dst + blockByMhKey { + data + } + } + } + `, txHash) + + req := gqlclient.NewRequest(getTxQuery) + req.Header.Set("Cache-Control", "no-cache") + + var respData map[string]interface{} + err := c.client.Run(ctx, req, &respData) + if err != nil { + return nil, err + } + + jsonStr, err := json.Marshal(respData) + if err != nil { + return nil, err + } + + var ethTxCID EthTransactionCIDByTxHash + err = json.Unmarshal(jsonStr, ðTxCID) + if err != nil { + return nil, err + } + return ðTxCID.Response, nil +} diff --git a/pkg/graphql/graphql.go b/pkg/graphql/graphql.go index 9c8431e4..c414e9a9 100644 --- a/pkg/graphql/graphql.go +++ b/pkg/graphql/graphql.go @@ -22,6 +22,7 @@ import ( "context" "database/sql" "errors" + "fmt" "time" "github.com/ethereum/go-ethereum/common" @@ -34,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/vulcanize/ipld-eth-server/v4/pkg/eth" + "github.com/vulcanize/ipld-eth-server/v4/pkg/shared" ) var ( @@ -1017,7 +1019,7 @@ func (r *Resolver) GetStorageAt(ctx context.Context, args struct { return nil, err } - if bytes.Compare(rlpValue, eth.EmptyNodeValue) == 0 { + if bytes.Equal(rlpValue, eth.EmptyNodeValue) { return &StorageResult{value: eth.EmptyNodeValue, cid: cid, ipldBlock: ipldBlock}, nil } @@ -1122,3 +1124,244 @@ func decomposeGQLLogs(logCIDs []eth.LogResult) []logsCID { return logs } + +type EthTransactionCID struct { + cid string + txHash string + index int32 + src string + dst string + ipfsBlock IPFSBlock +} + +func (t EthTransactionCID) Cid(ctx context.Context) string { + return t.cid +} + +func (t EthTransactionCID) TxHash(ctx context.Context) string { + return t.txHash +} + +func (t EthTransactionCID) Index(ctx context.Context) int32 { + return t.index +} + +func (t EthTransactionCID) Src(ctx context.Context) string { + return t.src +} + +func (t EthTransactionCID) Dst(ctx context.Context) string { + return t.dst +} + +func (t EthTransactionCID) BlockByMhKey(ctx context.Context) IPFSBlock { + return t.ipfsBlock +} + +type EthTransactionCIDsConnection struct { + nodes []*EthTransactionCID +} + +func (transactionCIDResult EthTransactionCIDsConnection) Nodes(ctx context.Context) []*EthTransactionCID { + return transactionCIDResult.nodes +} + +type IPFSBlock struct { + key string + data string +} + +func (b IPFSBlock) Key(ctx context.Context) string { + return b.key +} + +func (b IPFSBlock) Data(ctx context.Context) string { + return b.data +} + +type EthHeaderCID struct { + cid string + blockNumber BigInt + blockHash string + parentHash string + timestamp BigInt + stateRoot string + td BigInt + txRoot string + receiptRoot string + uncleRoot string + bloom string + transactions []*EthTransactionCID + ipfsBlock IPFSBlock +} + +func (h EthHeaderCID) Cid(ctx context.Context) string { + return h.cid +} + +func (h EthHeaderCID) BlockNumber(ctx context.Context) BigInt { + return h.blockNumber +} + +func (h EthHeaderCID) BlockHash(ctx context.Context) string { + return h.blockHash +} + +func (h EthHeaderCID) ParentHash(ctx context.Context) string { + return h.parentHash +} + +func (h EthHeaderCID) Timestamp(ctx context.Context) BigInt { + return h.timestamp +} + +func (h EthHeaderCID) StateRoot(ctx context.Context) string { + return h.stateRoot +} + +func (h EthHeaderCID) Td(ctx context.Context) BigInt { + return h.td +} + +func (h EthHeaderCID) TxRoot(ctx context.Context) string { + return h.txRoot +} + +func (h EthHeaderCID) ReceiptRoot(ctx context.Context) string { + return h.receiptRoot +} + +func (h EthHeaderCID) UncleRoot(ctx context.Context) string { + return h.uncleRoot +} + +func (h EthHeaderCID) Bloom(ctx context.Context) string { + return h.bloom +} + +func (h EthHeaderCID) EthTransactionCidsByHeaderId(ctx context.Context) EthTransactionCIDsConnection { + return EthTransactionCIDsConnection{nodes: h.transactions} +} + +func (h EthHeaderCID) BlockByMhKey(ctx context.Context) IPFSBlock { + return h.ipfsBlock +} + +type EthHeaderCIDsConnection struct { + nodes []*EthHeaderCID +} + +func (headerCIDResult EthHeaderCIDsConnection) Nodes(ctx context.Context) []*EthHeaderCID { + return headerCIDResult.nodes +} + +type EthHeaderCIDCondition struct { + BlockNumber *BigInt + BlockHash *string +} + +func (r *Resolver) AllEthHeaderCids(ctx context.Context, args struct { + Condition *EthHeaderCIDCondition +}) (*EthHeaderCIDsConnection, error) { + var headerCIDs []eth.HeaderCIDRecord + var err error + if args.Condition.BlockHash != nil { + headerCID, err := r.backend.Retriever.RetrieveHeaderAndTxCIDsByBlockHash(common.HexToHash(*args.Condition.BlockHash)) + if err != nil { + return nil, err + } + + headerCIDs = append(headerCIDs, headerCID) + } else if args.Condition.BlockNumber != nil { + headerCIDs, err = r.backend.Retriever.RetrieveHeaderAndTxCIDsByBlockNumber(args.Condition.BlockNumber.ToInt().Int64()) + if err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("provide block number or block hash") + } + + // Begin tx + tx, err := r.backend.DB.Beginx() + if err != nil { + return nil, err + } + defer func() { + if p := recover(); p != nil { + shared.Rollback(tx) + panic(p) + } else if err != nil { + shared.Rollback(tx) + } else { + err = tx.Commit() + } + }() + + var resultNodes []*EthHeaderCID + for _, headerCID := range headerCIDs { + var blockNumber BigInt + blockNumber.UnmarshalText([]byte(headerCID.BlockNumber)) + + var timestamp BigInt + timestamp.SetUint64(headerCID.Timestamp) + + var td BigInt + td.UnmarshalText([]byte(headerCID.TotalDifficulty)) + + ethHeaderCIDNode := EthHeaderCID{ + cid: headerCID.CID, + blockNumber: blockNumber, + blockHash: headerCID.BlockHash, + parentHash: headerCID.ParentHash, + timestamp: timestamp, + stateRoot: headerCID.StateRoot, + td: td, + txRoot: headerCID.TxRoot, + receiptRoot: headerCID.RctRoot, + uncleRoot: headerCID.UncleRoot, + bloom: Bytes(headerCID.Bloom).String(), + ipfsBlock: IPFSBlock{ + key: headerCID.IPLD.Key, + data: Bytes(headerCID.IPLD.Data).String(), + }, + } + + for _, txCID := range headerCID.TransactionCIDs { + ethHeaderCIDNode.transactions = append(ethHeaderCIDNode.transactions, &EthTransactionCID{ + cid: txCID.CID, + txHash: txCID.TxHash, + index: int32(txCID.Index), + src: txCID.Src, + dst: txCID.Dst, + }) + } + + resultNodes = append(resultNodes, ðHeaderCIDNode) + } + + return &EthHeaderCIDsConnection{ + nodes: resultNodes, + }, nil +} + +func (r *Resolver) EthTransactionCidByTxHash(ctx context.Context, args struct { + TxHash string +}) (*EthTransactionCID, error) { + txCID, err := r.backend.Retriever.RetrieveTxCIDByHash(args.TxHash) + + if err != nil { + return nil, err + } + + return &EthTransactionCID{ + cid: txCID.CID, + txHash: txCID.TxHash, + index: int32(txCID.Index), + src: txCID.Src, + dst: txCID.Dst, + ipfsBlock: IPFSBlock{ + key: txCID.IPLD.Key, + data: Bytes(txCID.IPLD.Data).String(), + }, + }, nil +} diff --git a/pkg/graphql/graphql_test.go b/pkg/graphql/graphql_test.go index 535c84f5..7c90b3e6 100644 --- a/pkg/graphql/graphql_test.go +++ b/pkg/graphql/graphql_test.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "math/big" + "strconv" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -180,7 +181,7 @@ var _ = Describe("GraphQL", func() { { Topics: test_helpers.MockLog1.Topics, Data: hexutil.Bytes(test_helpers.MockLog1.Data), - Transaction: graphql.TransactionResp{Hash: test_helpers.MockTransactions[0].Hash()}, + Transaction: graphql.TransactionResponse{Hash: test_helpers.MockTransactions[0].Hash()}, ReceiptCID: test_helpers.Rct1CID.String(), Status: int32(test_helpers.MockReceipts[0].Status), }, @@ -197,7 +198,7 @@ var _ = Describe("GraphQL", func() { { Topics: test_helpers.MockLog6.Topics, Data: hexutil.Bytes(test_helpers.MockLog6.Data), - Transaction: graphql.TransactionResp{Hash: test_helpers.MockTransactions[3].Hash()}, + Transaction: graphql.TransactionResponse{Hash: test_helpers.MockTransactions[3].Hash()}, ReceiptCID: test_helpers.Rct4CID.String(), Status: int32(test_helpers.MockReceipts[3].Status), }, @@ -250,4 +251,84 @@ var _ = Describe("GraphQL", func() { Expect(storageRes.Value).To(Equal(common.Hash{})) }) }) + + Describe("allEthHeaderCids", func() { + It("Retrieves header_cids that matches the provided blockNumber", func() { + allEthHeaderCIDsResp, err := client.AllEthHeaderCIDs(ctx, graphql.EthHeaderCIDCondition{BlockNumber: new(graphql.BigInt).SetUint64(2)}) + Expect(err).ToNot(HaveOccurred()) + + headerCIDs, err := backend.Retriever.RetrieveHeaderAndTxCIDsByBlockNumber(2) + Expect(err).ToNot(HaveOccurred()) + + for idx, headerCID := range headerCIDs { + ethHeaderCID := allEthHeaderCIDsResp.Nodes[idx] + + compareEthHeaderCID(ethHeaderCID, headerCID) + } + }) + + It("Retrieves header_cids that matches the provided blockHash", func() { + blockHash := blocks[1].Hash().String() + allEthHeaderCIDsResp, err := client.AllEthHeaderCIDs(ctx, graphql.EthHeaderCIDCondition{BlockHash: &blockHash}) + Expect(err).ToNot(HaveOccurred()) + + headerCID, err := backend.Retriever.RetrieveHeaderAndTxCIDsByBlockHash(blocks[1].Hash()) + Expect(err).ToNot(HaveOccurred()) + + Expect(len(allEthHeaderCIDsResp.Nodes)).To(Equal(1)) + ethHeaderCID := allEthHeaderCIDsResp.Nodes[0] + compareEthHeaderCID(ethHeaderCID, headerCID) + }) + }) + + Describe("ethTransactionCidByTxHash", func() { + It("Retrieves tx_cid that matches the provided txHash", func() { + txHash := blocks[2].Transactions()[0].Hash().String() + ethTransactionCIDResp, err := client.EthTransactionCIDByTxHash(ctx, txHash) + Expect(err).ToNot(HaveOccurred()) + + txCID, err := backend.Retriever.RetrieveTxCIDByHash(txHash) + Expect(err).ToNot(HaveOccurred()) + + compareEthTxCID(*ethTransactionCIDResp, txCID) + + Expect(ethTransactionCIDResp.BlockByMhKey.Data).To(Equal(graphql.Bytes(txCID.IPLD.Data).String())) + }) + }) }) + +func compareEthHeaderCID(ethHeaderCID graphql.EthHeaderCIDResponse, headerCID eth.HeaderCIDRecord) { + blockNumber, err := strconv.ParseInt(headerCID.BlockNumber, 10, 64) + Expect(err).ToNot(HaveOccurred()) + + td, err := strconv.ParseInt(headerCID.TotalDifficulty, 10, 64) + Expect(err).ToNot(HaveOccurred()) + + Expect(ethHeaderCID.CID).To(Equal(headerCID.CID)) + Expect(ethHeaderCID.BlockNumber).To(Equal(*new(graphql.BigInt).SetUint64(uint64(blockNumber)))) + Expect(ethHeaderCID.BlockHash).To(Equal(headerCID.BlockHash)) + Expect(ethHeaderCID.ParentHash).To(Equal(headerCID.ParentHash)) + Expect(ethHeaderCID.Timestamp).To(Equal(*new(graphql.BigInt).SetUint64(headerCID.Timestamp))) + Expect(ethHeaderCID.StateRoot).To(Equal(headerCID.StateRoot)) + Expect(ethHeaderCID.Td).To(Equal(*new(graphql.BigInt).SetUint64(uint64(td)))) + Expect(ethHeaderCID.TxRoot).To(Equal(headerCID.TxRoot)) + Expect(ethHeaderCID.ReceiptRoot).To(Equal(headerCID.RctRoot)) + Expect(ethHeaderCID.UncleRoot).To(Equal(headerCID.UncleRoot)) + Expect(ethHeaderCID.Bloom).To(Equal(graphql.Bytes(headerCID.Bloom).String())) + + for tIdx, txCID := range headerCID.TransactionCIDs { + ethTxCID := ethHeaderCID.EthTransactionCIDsByHeaderId.Nodes[tIdx] + compareEthTxCID(ethTxCID, txCID) + } + + Expect(ethHeaderCID.BlockByMhKey.Data).To(Equal(graphql.Bytes(headerCID.IPLD.Data).String())) + Expect(ethHeaderCID.BlockByMhKey.Key).To(Equal(headerCID.IPLD.Key)) +} + +func compareEthTxCID(ethTxCID graphql.EthTransactionCIDResponse, txCID eth.TransactionCIDRecord) { + Expect(ethTxCID.CID).To(Equal(txCID.CID)) + Expect(ethTxCID.TxHash).To(Equal(txCID.TxHash)) + Expect(ethTxCID.Index).To(Equal(int32(txCID.Index))) + Expect(ethTxCID.Src).To(Equal(txCID.Src)) + Expect(ethTxCID.Dst).To(Equal(txCID.Dst)) +} diff --git a/pkg/graphql/schema.go b/pkg/graphql/schema.go index b70765ac..eb0d89fc 100644 --- a/pkg/graphql/schema.go +++ b/pkg/graphql/schema.go @@ -25,8 +25,7 @@ const schema string = ` # An empty byte string is represented as '0x'. Byte strings must have an even number of hexadecimal nybbles. scalar Bytes # BigInt is a large integer. Input is accepted as either a JSON number or as a string. - # Strings may be either decimal or 0x-prefixed hexadecimal. Output values are all - # 0x-prefixed hexadecimal. + # Input and output strings may be either decimal or 0x-prefixed hexadecimal depending upon the resolver implementation. scalar BigInt # Long is a 64 bit unsigned integer. scalar Long @@ -138,16 +137,16 @@ const schema string = ` # empty, results will not be filtered by address. addresses: [Address!] # Topics list restricts matches to particular event topics. Each event has a list - # of topics. Topics matches a prefix of that list. An empty element array matches any - # topic. Non-empty elements represent an alternative that matches any of the - # contained topics. - # - # Examples: - # - [] or nil matches any topic list - # - [[A]] matches topic A in first position - # - [[], [B]] matches any topic in first position, B in second position - # - [[A], [B]] matches topic A in first position, B in second position - # - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position + # of topics. Topics matches a prefix of that list. An empty element array matches any + # topic. Non-empty elements represent an alternative that matches any of the + # contained topics. + # + # Examples: + # - [] or nil matches any topic list + # - [[A]] matches topic A in first position + # - [[], [B]] matches any topic in first position, B in second position + # - [[A], [B]] matches topic A in first position, B in second position + # - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position topics: [[Bytes32!]!] } @@ -258,16 +257,16 @@ const schema string = ` # empty, results will not be filtered by address. addresses: [Address!] # Topics list restricts matches to particular event topics. Each event has a list - # of topics. Topics matches a prefix of that list. An empty element array matches any - # topic. Non-empty elements represent an alternative that matches any of the - # contained topics. - # - # Examples: - # - [] or nil matches any topic list - # - [[A]] matches topic A in first position - # - [[], [B]] matches any topic in first position, B in second position - # - [[A], [B]] matches topic A in first position, B in second position - # - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position + # of topics. Topics matches a prefix of that list. An empty element array matches any + # topic. Non-empty elements represent an alternative that matches any of the + # contained topics. + # + # Examples: + # - [] or nil matches any topic list + # - [[A]] matches topic A in first position + # - [[], [B]] matches any topic in first position, B in second position + # - [[A], [B]] matches topic A in first position, B in second position + # - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position topics: [[Bytes32!]!] } @@ -282,6 +281,49 @@ const schema string = ` ipldBlock: Bytes! } + input EthHeaderCidCondition { + blockNumber: BigInt + blockHash: String + } + + type EthTransactionCid { + cid: String! + txHash: String! + index: Int! + src: String! + dst: String! + blockByMhKey: IPFSBlock! + } + + type EthTransactionCidsConnection { + nodes: [EthTransactionCid]! + } + + type IPFSBlock { + key: String! + data: String! + } + + type EthHeaderCid { + cid: String! + blockNumber: BigInt! + blockHash: String! + parentHash: String! + timestamp: BigInt! + stateRoot: String! + td: BigInt! + txRoot: String! + receiptRoot: String! + uncleRoot: String! + bloom: String! + ethTransactionCidsByHeaderId: EthTransactionCidsConnection! + blockByMhKey: IPFSBlock! + } + + type EthHeaderCidsConnection { + nodes: [EthHeaderCid]! + } + type Query { # Block fetches an Ethereum block by number or by hash. If neither is # supplied, the most recent known block is returned. @@ -302,5 +344,11 @@ const schema string = ` # Get contract logs by block hash and contract address. getLogs(blockHash: Bytes32!, contract: Address): [Log!] + + # PostGraphile alternative to get headers with transactions using block number or block hash. + allEthHeaderCids(condition: EthHeaderCidCondition): EthHeaderCidsConnection + + # PostGraphile alternative to get transactions using transaction hash. + ethTransactionCidByTxHash(txHash: String!): EthTransactionCid } ` diff --git a/pkg/graphql/types.go b/pkg/graphql/types.go new file mode 100644 index 00000000..7213cecc --- /dev/null +++ b/pkg/graphql/types.go @@ -0,0 +1,122 @@ +// VulcanizeDB +// Copyright © 2022 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 . + +package graphql + +import ( + "encoding/hex" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// Bytes marshals as a JSON string with \x prefix. +// The empty slice marshals as "\x". +type Bytes []byte + +// MarshalText implements encoding.TextMarshaler +func (b Bytes) MarshalText() ([]byte, error) { + result := make([]byte, len(b)*2+2) + copy(result, `\x`) + hex.Encode(result[2:], b) + return result, nil +} + +// String returns the hex encoding of b. +func (b Bytes) String() string { + return b.encode() +} + +// Encode encodes b as a hex string with "\x" prefix. +// This is to make the output to be the same as given by postgraphile. +// graphql-go prepends another "\" to the output resulting in prefix "\\x". +func (b Bytes) encode() string { + result := make([]byte, len(b)*2+2) + copy(result, `\x`) + hex.Encode(result[2:], b) + return string(result) +} + +type BigInt big.Int + +// ToInt converts b to a big.Int. +func (b *BigInt) ToInt() *big.Int { + return (*big.Int)(b) +} + +// String returns value of b as a decimal string. +func (b *BigInt) String() string { + return b.ToInt().String() +} + +// SetUint64 sets b to x and returns x. +func (b *BigInt) SetUint64(x uint64) *BigInt { + var val big.Int + val.SetUint64(x) + *b = (BigInt)(val) + return b +} + +// MarshalText implements encoding.TextMarshaler +func (b BigInt) MarshalText() ([]byte, error) { + return []byte(b.String()), nil +} + +// UnmarshalText implements encoding.TextUnmarshaler +func (b *BigInt) UnmarshalText(input []byte) error { + raw, err := checkNumberText(input) + if err != nil { + return err + } + if len(raw) > 64 { + return hexutil.ErrBig256Range + } + + var val big.Int + val.SetString(string(input[:]), 10) + *b = (BigInt)(val) + return nil +} + +// ImplementsGraphQLType returns true if BigInt implements the provided GraphQL type. +func (b BigInt) ImplementsGraphQLType(name string) bool { return name == "BigInt" } + +// UnmarshalGraphQL unmarshals the provided GraphQL query data. +func (b *BigInt) UnmarshalGraphQL(input interface{}) error { + var err error + switch input := input.(type) { + case string: + return b.UnmarshalText([]byte(input)) + case int32: + var num big.Int + num.SetInt64(int64(input)) + *b = BigInt(num) + default: + err = fmt.Errorf("unexpected type %T for BigInt", input) + } + return err +} + +func checkNumberText(input []byte) (raw []byte, err error) { + if len(input) == 0 { + return nil, nil // empty strings are allowed + } + if len(input) > 1 && input[0] == '0' { + return nil, hexutil.ErrLeadingZero + } + return input, nil +}