From cfc4f45d5929c006692bc11d0e749cd7de28d2a7 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 14 Feb 2024 12:34:55 +0100 Subject: [PATCH 01/13] Added primary indexes and GraphQL interface: - Added graphQL API using 99designs/gqlgen. Really easy to use interface throught GraphQL playground, with a ton of extra documentation explaining all the Query functions and filter parameters. - Store Transactions by block height and index, making them queriable - Added a ton of special encoders on storage/encode.go. They are intended to be used as a fast, sortable way to encode/decode keys on any key/value store. That allows us to use advanced features when iterating keys, like adding upper and lower keys as limiters, or in the future adding secondary indexes. - BREAKING CHANGE: I had to change prefixes on pebble keys to make them queriable, so previous db states are invalid. - Added BlockIterator and TxIterator to Reader storage interface. Signed-off-by: Antonio Navarro Perez --- cmd/start.go | 16 +- go.mod | 40 +- go.sum | 440 +-- gqlgen.yml | 88 + internal/mock/storage.go | 18 +- serve/graph/generated.go | 4595 ++++++++++++++++++++++++++++++ serve/graph/model/block.go | 42 + serve/graph/model/models_gen.go | 48 + serve/graph/model/transaction.go | 39 + serve/graph/resolver.go | 40 + serve/graph/schema.graphql | 200 ++ serve/graph/schema.resolvers.go | 145 + serve/graph/setup.go | 21 + serve/handler_test.go | 7 +- serve/handlers/tx/mocks_test.go | 6 +- serve/handlers/tx/tx.go | 17 +- serve/handlers/tx/tx_test.go | 42 +- serve/handlers/tx/types.go | 2 +- serve/jsonrpc.go | 70 +- serve/options.go | 8 - serve/server.go | 70 + storage/encode.go | 350 ++- storage/keys.go | 13 - storage/pebble.go | 196 +- storage/pebble_test.go | 83 +- storage/types.go | 17 +- tools.go | 8 + 27 files changed, 6074 insertions(+), 547 deletions(-) create mode 100644 gqlgen.yml create mode 100644 serve/graph/generated.go create mode 100644 serve/graph/model/block.go create mode 100644 serve/graph/model/models_gen.go create mode 100644 serve/graph/model/transaction.go create mode 100644 serve/graph/resolver.go create mode 100644 serve/graph/schema.graphql create mode 100644 serve/graph/schema.resolvers.go create mode 100644 serve/graph/setup.go create mode 100644 serve/server.go delete mode 100644 storage/keys.go create mode 100644 tools.go diff --git a/cmd/start.go b/cmd/start.go index ff8da971..278e502b 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -6,6 +6,7 @@ import ( "flag" "fmt" + "github.com/go-chi/chi/v5" "github.com/peterbourgon/ff/v3/ffcli" "go.uber.org/zap" @@ -13,6 +14,7 @@ import ( "github.com/gnolang/tx-indexer/events" "github.com/gnolang/tx-indexer/fetch" "github.com/gnolang/tx-indexer/serve" + "github.com/gnolang/tx-indexer/serve/graph" "github.com/gnolang/tx-indexer/storage" ) @@ -141,12 +143,18 @@ func (c *startCfg) exec(ctx context.Context) error { // Create the JSON-RPC service j := setupJSONRPC( - c.listenAddress, db, em, logger, ) + mux := chi.NewMux() + mux = j.SetupRoutes(mux) + mux = graph.Setup(db, mux) + + // Create the HTTP server + hs := serve.NewHTTPServer(mux, c.listenAddress, logger.Named("http-server")) + // Create a new waiter w := newWaiter(ctx) @@ -154,7 +162,7 @@ func (c *startCfg) exec(ctx context.Context) error { w.add(f.FetchChainData) // Add the JSON-RPC service - w.add(j.Serve) + w.add(hs.Serve) // Wait for the services to stop return errors.Join( @@ -165,7 +173,6 @@ func (c *startCfg) exec(ctx context.Context) error { // setupJSONRPC sets up the JSONRPC instance func setupJSONRPC( - listenAddress string, db *storage.Pebble, em *events.Manager, logger *zap.Logger, @@ -175,9 +182,6 @@ func setupJSONRPC( serve.WithLogger( logger.Named("json-rpc"), ), - serve.WithListenAddress( - listenAddress, - ), ) // Transaction handlers diff --git a/go.mod b/go.mod index a30c39ff..8098720b 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/gnolang/tx-indexer go 1.21 require ( + github.com/99designs/gqlgen v0.17.43 github.com/cockroachdb/pebble v1.1.0 github.com/go-chi/chi/v5 v5.0.12 github.com/google/uuid v1.6.0 @@ -10,12 +11,15 @@ require ( github.com/olahol/melody v1.1.4 github.com/peterbourgon/ff/v3 v3.4.0 github.com/stretchr/testify v1.9.0 + github.com/vektah/gqlparser/v2 v2.5.11 + go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/sync v0.6.0 ) require ( - github.com/DataDog/zstd v1.4.5 // indirect + github.com/DataDog/zstd v1.5.5 // indirect + github.com/agnivade/levenshtein v1.1.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -23,11 +27,12 @@ require ( github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/badger/v3 v3.2103.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/getsentry/sentry-go v0.18.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect github.com/gnolang/goleveldb v0.0.9 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect @@ -36,31 +41,36 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/flatbuffers v1.12.1 // indirect github.com/gorilla/websocket v1.5.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/klauspost/compress v1.15.15 // indirect + github.com/klauspost/compress v1.17.6 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/linxGnu/grocksdb v1.8.5 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.12.0 // indirect - github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect - github.com/prometheus/common v0.32.1 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.46.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rs/cors v1.10.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sosodev/duration v1.1.0 // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + github.com/urfave/cli/v2 v2.25.5 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.etcd.io/bbolt v1.3.8 // indirect go.opencensus.io v0.22.5 // indirect - go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect + golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.17.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -70,6 +80,6 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/gnolang/gno v0.0.0-20231215125729-9262c1a8f949 github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect - golang.org/x/crypto v0.15.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect ) diff --git a/go.sum b/go.sum index 23ad17a0..b8eee739 100644 --- a/go.sum +++ b/go.sum @@ -1,51 +1,23 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/99designs/gqlgen v0.17.43 h1:I4SYg6ahjowErAQcHFVKy5EcWuwJ3+Xw9z2fLpuFCPo= +github.com/99designs/gqlgen v0.17.43/go.mod h1:lO0Zjy8MkZgBdv4T1U91x09r0e0WFOdhVUutlQs1Rsc= 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/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= +github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= +github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= +github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= 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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= @@ -73,18 +45,12 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= @@ -101,6 +67,8 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc 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/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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= @@ -119,12 +87,10 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= @@ -136,8 +102,8 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= -github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/gnolang/gno v0.0.0-20231215125729-9262c1a8f949 h1:SSGQQALkDP3E0cMTuOw8/EH0HupmSl/TOTLt1BK8hFE= github.com/gnolang/gno v0.0.0-20231215125729-9262c1a8f949/go.mod h1:qkXjIwBdGdIxxgP16m9jcYwNabj7luBNLGT42EaF2DY= github.com/gnolang/goleveldb v0.0.9 h1:Q7rGko9oXMKtQA+Apeeed5a3sjba/mcDhzJGoTVLCKE= @@ -148,92 +114,47 @@ github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru/v2 v2.0.3 h1:kmRrRLlInXvng0SmLxmQpQkpbYAvcXm7NPDrgxJa9mE= +github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jaekwon/testify v1.6.1 h1:4AtAJcR9GzXN5W4DdY7ie74iCPiJV1JJUJL90t2ZUyw= github.com/jaekwon/testify v1.6.1/go.mod h1:Oun0RXIHI7osufabQ60i4Lqkj0GXLbqI1I7kgzBNm1U= @@ -241,25 +162,13 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= -github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -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.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= +github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -274,18 +183,10 @@ github.com/linxGnu/grocksdb v1.8.5/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkV github.com/madz-lab/insertion-queue v0.0.0-20230520191346-295d3348f63a h1:KxTVE11SAJzp+PnqaCw0Rzb/of6mQexpTIyZwM/JTJU= github.com/madz-lab/insertion-queue v0.0.0-20230520191346-295d3348f63a/go.mod h1:kWWMMyVnsC79rIkENl7FQUU2EQql12s8ETwjsDBiMtA= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= @@ -309,45 +210,30 @@ github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyX github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -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= github.com/pkg/errors v0.9.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/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_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg= -github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -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/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y= -github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= +github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4= +github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -358,9 +244,7 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 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/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= @@ -369,18 +253,17 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45 github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc= +github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= +github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -390,45 +273,18 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 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/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= +golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= @@ -437,253 +293,86 @@ golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 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/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -691,12 +380,3 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/gqlgen.yml b/gqlgen.yml new file mode 100644 index 00000000..41131de2 --- /dev/null +++ b/gqlgen.yml @@ -0,0 +1,88 @@ +# Where are all the schema files located? globs are supported eg src/**/*.graphql +schema: + - serve/graph/*.graphql + +# Where should the generated server code go? +exec: + filename: serve/graph/generated.go + package: graph + +# Where should any generated models go? +model: + filename: serve/graph/model/models_gen.go + package: model + +# Where should the resolver implementations go? +resolver: + layout: follow-schema + dir: serve/graph + package: graph + filename_template: "{name}.resolvers.go" + # Optional: turn on to not generate template comments above resolvers + # omit_template_comment: false + +# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models +# struct_tag: json + +# Optional: turn on to use []Thing instead of []*Thing +# omit_slice_element_pointers: false + +# Optional: turn on to omit Is() methods to interface and unions +# omit_interface_checks : true + +# Optional: turn on to skip generation of ComplexityRoot struct content and Complexity function +# omit_complexity: false + +# Optional: turn on to not generate any file notice comments in generated files +# omit_gqlgen_file_notice: false + +# Optional: turn on to exclude the gqlgen version in the generated file notice. No effect if `omit_gqlgen_file_notice` is true. +# omit_gqlgen_version_in_file_notice: false + +# Optional: turn off to make struct-type struct fields not use pointers +# e.g. type Thing struct { FieldA OtherThing } instead of { FieldA *OtherThing } +# struct_fields_always_pointers: true + +# Optional: turn off to make resolvers return values instead of pointers for structs +# resolvers_always_return_pointers: true + +# Optional: turn on to return pointers instead of values in unmarshalInput +# return_pointers_in_unmarshalinput: false + +# Optional: wrap nullable input fields with Omittable +# nullable_input_omittable: true + +# Optional: set to speed up generation time by not performing a final validation pass. +# skip_validation: true + +# Optional: set to skip running `go mod tidy` when generating server code +# skip_mod_tidy: true + +# gqlgen will search for any type names in the schema in these go packages +# if they match it will use them, otherwise it will generate them. +autobind: + - "github.com/gnolang/tx-indexer/serve/graph/model" + +# This section declares type mapping between the GraphQL and go type systems +# +# The first line in each type will be used as defaults for resolver arguments and +# modelgen, the others will be allowed when binding to fields. Configure them to +# your liking +models: + ID: + model: + - github.com/99designs/gqlgen/graphql.ID + - github.com/99designs/gqlgen/graphql.Int + - github.com/99designs/gqlgen/graphql.Int64 + - github.com/99designs/gqlgen/graphql.Int32 + Int: + model: + - github.com/99designs/gqlgen/graphql.Int + - github.com/99designs/gqlgen/graphql.Int64 + - github.com/99designs/gqlgen/graphql.Int32 + Block: + model: + - github.com/gnolang/tx-indexer/serve/graph/model.Block + Transaction: + model: + - github.com/gnolang/tx-indexer/serve/graph/model.Transaction \ No newline at end of file diff --git a/internal/mock/storage.go b/internal/mock/storage.go index 083c432a..c5dd1468 100644 --- a/internal/mock/storage.go +++ b/internal/mock/storage.go @@ -12,7 +12,7 @@ type Storage struct { GetLatestSavedHeightFn func() (int64, error) GetWriteBatchFn func() storage.Batch GetBlockFn func(int64) (*types.Block, error) - GetTxFn func([]byte) (*types.TxResult, error) + GetTxFn func(int64, uint32) (*types.TxResult, error) } func (m *Storage) GetLatestHeight() (int64, error) { @@ -32,15 +32,25 @@ func (m *Storage) GetBlock(blockNum int64) (*types.Block, error) { panic("not implemented") } -// GetTx fetches the tx using its hash -func (m *Storage) GetTx(tx []byte) (*types.TxResult, error) { +// GetTx fetches the tx using block height and transaction index +func (m *Storage) GetTx(blockNum int64, index uint32) (*types.TxResult, error) { if m.GetTxFn != nil { - return m.GetTxFn(tx) + return m.GetTxFn(blockNum, index) } panic("not implemented") } +// BlockIterator iterates over Blocks, limiting the results to be between the provided block numbers +func (m *Storage) BlockIterator(fromBlockNum int64, toBlockNum int64) (storage.Iterator[*types.Block], error) { + panic("not implemented") // TODO: Implement +} + +// TxIterator iterates over transactions, limiting the results to be between the provided block numbers and transaction indexes +func (m *Storage) TxIterator(fromBlockNum int64, toBlockNum int64, fromTxIndex uint32, toTxIndex uint32) (storage.Iterator[*types.TxResult], error) { + panic("not implemented") // TODO: Implement +} + // WriteBatch provides a batch intended to do a write action that // can be cancelled or committed all at the same time func (m *Storage) WriteBatch() storage.Batch { diff --git a/serve/graph/generated.go b/serve/graph/generated.go new file mode 100644 index 00000000..62221cba --- /dev/null +++ b/serve/graph/generated.go @@ -0,0 +1,4595 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package graph + +import ( + "bytes" + "context" + "embed" + "errors" + "fmt" + "io" + "strconv" + "sync" + "sync/atomic" + "time" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/introspection" + "github.com/gnolang/tx-indexer/serve/graph/model" + gqlparser "github.com/vektah/gqlparser/v2" + "github.com/vektah/gqlparser/v2/ast" +) + +// region ************************** generated!.gotpl ************************** + +// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. +func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { + return &executableSchema{ + schema: cfg.Schema, + resolvers: cfg.Resolvers, + directives: cfg.Directives, + complexity: cfg.Complexity, + } +} + +type Config struct { + Schema *ast.Schema + Resolvers ResolverRoot + Directives DirectiveRoot + Complexity ComplexityRoot +} + +type ResolverRoot interface { + Query() QueryResolver + Subscription() SubscriptionResolver +} + +type DirectiveRoot struct { +} + +type ComplexityRoot struct { + Block struct { + ChainID func(childComplexity int) int + Height func(childComplexity int) int + ProposerAddressRaw func(childComplexity int) int + Time func(childComplexity int) int + Version func(childComplexity int) int + } + + Query struct { + Blocks func(childComplexity int, filter model.BlockFilter) int + LatestBlockHeight func(childComplexity int) int + Transactions func(childComplexity int, filter model.TransactionFilter) int + } + + Subscription struct { + Blocks func(childComplexity int, filter model.BlockFilter) int + Transactions func(childComplexity int, filter model.TransactionFilter) int + } + + Transaction struct { + BlockHeight func(childComplexity int) int + ContentRaw func(childComplexity int) int + GasUsed func(childComplexity int) int + GasWanted func(childComplexity int) int + Index func(childComplexity int) int + } +} + +type QueryResolver interface { + Transactions(ctx context.Context, filter model.TransactionFilter) ([]*model.Transaction, error) + Blocks(ctx context.Context, filter model.BlockFilter) ([]*model.Block, error) + LatestBlockHeight(ctx context.Context) (int, error) +} +type SubscriptionResolver interface { + Transactions(ctx context.Context, filter model.TransactionFilter) (<-chan *model.Transaction, error) + Blocks(ctx context.Context, filter model.BlockFilter) (<-chan *model.Block, error) +} + +type executableSchema struct { + schema *ast.Schema + resolvers ResolverRoot + directives DirectiveRoot + complexity ComplexityRoot +} + +func (e *executableSchema) Schema() *ast.Schema { + if e.schema != nil { + return e.schema + } + return parsedSchema +} + +func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { + ec := executionContext{nil, e, 0, 0, nil} + _ = ec + switch typeName + "." + field { + + case "Block.chain_id": + if e.complexity.Block.ChainID == nil { + break + } + + return e.complexity.Block.ChainID(childComplexity), true + + case "Block.height": + if e.complexity.Block.Height == nil { + break + } + + return e.complexity.Block.Height(childComplexity), true + + case "Block.proposer_address_raw": + if e.complexity.Block.ProposerAddressRaw == nil { + break + } + + return e.complexity.Block.ProposerAddressRaw(childComplexity), true + + case "Block.time": + if e.complexity.Block.Time == nil { + break + } + + return e.complexity.Block.Time(childComplexity), true + + case "Block.version": + if e.complexity.Block.Version == nil { + break + } + + return e.complexity.Block.Version(childComplexity), true + + case "Query.blocks": + if e.complexity.Query.Blocks == nil { + break + } + + args, err := ec.field_Query_blocks_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Blocks(childComplexity, args["filter"].(model.BlockFilter)), true + + case "Query.latestBlockHeight": + if e.complexity.Query.LatestBlockHeight == nil { + break + } + + return e.complexity.Query.LatestBlockHeight(childComplexity), true + + case "Query.transactions": + if e.complexity.Query.Transactions == nil { + break + } + + args, err := ec.field_Query_transactions_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Transactions(childComplexity, args["filter"].(model.TransactionFilter)), true + + case "Subscription.blocks": + if e.complexity.Subscription.Blocks == nil { + break + } + + args, err := ec.field_Subscription_blocks_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.Blocks(childComplexity, args["filter"].(model.BlockFilter)), true + + case "Subscription.transactions": + if e.complexity.Subscription.Transactions == nil { + break + } + + args, err := ec.field_Subscription_transactions_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.Transactions(childComplexity, args["filter"].(model.TransactionFilter)), true + + case "Transaction.block_height": + if e.complexity.Transaction.BlockHeight == nil { + break + } + + return e.complexity.Transaction.BlockHeight(childComplexity), true + + case "Transaction.content_raw": + if e.complexity.Transaction.ContentRaw == nil { + break + } + + return e.complexity.Transaction.ContentRaw(childComplexity), true + + case "Transaction.gas_used": + if e.complexity.Transaction.GasUsed == nil { + break + } + + return e.complexity.Transaction.GasUsed(childComplexity), true + + case "Transaction.gas_wanted": + if e.complexity.Transaction.GasWanted == nil { + break + } + + return e.complexity.Transaction.GasWanted(childComplexity), true + + case "Transaction.index": + if e.complexity.Transaction.Index == nil { + break + } + + return e.complexity.Transaction.Index(childComplexity), true + + } + return 0, false +} + +func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { + rc := graphql.GetOperationContext(ctx) + ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)} + inputUnmarshalMap := graphql.BuildUnmarshalerMap( + ec.unmarshalInputBlockFilter, + ec.unmarshalInputTransactionFilter, + ) + first := true + + switch rc.Operation.Operation { + case ast.Query: + return func(ctx context.Context) *graphql.Response { + var response graphql.Response + var data graphql.Marshaler + if first { + first = false + ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) + data = ec._Query(ctx, rc.Operation.SelectionSet) + } else { + if atomic.LoadInt32(&ec.pendingDeferred) > 0 { + result := <-ec.deferredResults + atomic.AddInt32(&ec.pendingDeferred, -1) + data = result.Result + response.Path = result.Path + response.Label = result.Label + response.Errors = result.Errors + } else { + return nil + } + } + var buf bytes.Buffer + data.MarshalGQL(&buf) + response.Data = buf.Bytes() + if atomic.LoadInt32(&ec.deferred) > 0 { + hasNext := atomic.LoadInt32(&ec.pendingDeferred) > 0 + response.HasNext = &hasNext + } + + return &response + } + case ast.Subscription: + next := ec._Subscription(ctx, rc.Operation.SelectionSet) + + var buf bytes.Buffer + return func(ctx context.Context) *graphql.Response { + buf.Reset() + data := next(ctx) + + if data == nil { + return nil + } + data.MarshalGQL(&buf) + + return &graphql.Response{ + Data: buf.Bytes(), + } + } + + default: + return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) + } +} + +type executionContext struct { + *graphql.OperationContext + *executableSchema + deferred int32 + pendingDeferred int32 + deferredResults chan graphql.DeferredResult +} + +func (ec *executionContext) processDeferredGroup(dg graphql.DeferredGroup) { + atomic.AddInt32(&ec.pendingDeferred, 1) + go func() { + ctx := graphql.WithFreshResponseContext(dg.Context) + dg.FieldSet.Dispatch(ctx) + ds := graphql.DeferredResult{ + Path: dg.Path, + Label: dg.Label, + Result: dg.FieldSet, + Errors: graphql.GetErrors(ctx), + } + // null fields should bubble up + if dg.FieldSet.Invalids > 0 { + ds.Result = graphql.Null + } + ec.deferredResults <- ds + }() +} + +func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { + if ec.DisableIntrospection { + return nil, errors.New("introspection disabled") + } + return introspection.WrapSchema(ec.Schema()), nil +} + +func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { + if ec.DisableIntrospection { + return nil, errors.New("introspection disabled") + } + return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil +} + +//go:embed "schema.graphql" +var sourcesFS embed.FS + +func sourceData(filename string) string { + data, err := sourcesFS.ReadFile(filename) + if err != nil { + panic(fmt.Sprintf("codegen problem: %s not available", filename)) + } + return string(data) +} + +var sources = []*ast.Source{ + {Name: "schema.graphql", Input: sourceData("schema.graphql"), BuiltIn: false}, +} +var parsedSchema = gqlparser.MustLoadSchema(sources...) + +// endregion ************************** generated!.gotpl ************************** + +// region ***************************** args.gotpl ***************************** + +func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_blocks_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.BlockFilter + if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + arg0, err = ec.unmarshalNBlockFilter2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlockFilter(ctx, tmp) + if err != nil { + return nil, err + } + } + args["filter"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_transactions_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.TransactionFilter + if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + arg0, err = ec.unmarshalNTransactionFilter2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransactionFilter(ctx, tmp) + if err != nil { + return nil, err + } + } + args["filter"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Subscription_blocks_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.BlockFilter + if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + arg0, err = ec.unmarshalNBlockFilter2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlockFilter(ctx, tmp) + if err != nil { + return nil, err + } + } + args["filter"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Subscription_transactions_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.TransactionFilter + if tmp, ok := rawArgs["filter"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) + arg0, err = ec.unmarshalNTransactionFilter2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransactionFilter(ctx, tmp) + if err != nil { + return nil, err + } + } + args["filter"] = arg0 + return args, nil +} + +func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 bool + if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["includeDeprecated"] = arg0 + return args, nil +} + +func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 bool + if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["includeDeprecated"] = arg0 + return args, nil +} + +// endregion ***************************** args.gotpl ***************************** + +// region ************************** directives.gotpl ************************** + +// endregion ************************** directives.gotpl ************************** + +// region **************************** field.gotpl ***************************** + +func (ec *executionContext) _Block_height(ctx context.Context, field graphql.CollectedField, obj *model.Block) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Block_height(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Height(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int64) + fc.Result = res + return ec.marshalNInt2int64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Block_height(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Block", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Block_version(ctx context.Context, field graphql.CollectedField, obj *model.Block) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Block_version(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Version(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Block_version(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Block", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Block_chain_id(ctx context.Context, field graphql.CollectedField, obj *model.Block) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Block_chain_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ChainID(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Block_chain_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Block", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Block_time(ctx context.Context, field graphql.CollectedField, obj *model.Block) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Block_time(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Time(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Block_time(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Block", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Block_proposer_address_raw(ctx context.Context, field graphql.CollectedField, obj *model.Block) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Block_proposer_address_raw(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ProposerAddressRaw(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Block_proposer_address_raw(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Block", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_transactions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_transactions(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Transactions(rctx, fc.Args["filter"].(model.TransactionFilter)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.Transaction) + fc.Result = res + return ec.marshalOTransaction2ᚕᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransactionᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_transactions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "index": + return ec.fieldContext_Transaction_index(ctx, field) + case "block_height": + return ec.fieldContext_Transaction_block_height(ctx, field) + case "gas_wanted": + return ec.fieldContext_Transaction_gas_wanted(ctx, field) + case "gas_used": + return ec.fieldContext_Transaction_gas_used(ctx, field) + case "content_raw": + return ec.fieldContext_Transaction_content_raw(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Transaction", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_transactions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_blocks(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_blocks(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Blocks(rctx, fc.Args["filter"].(model.BlockFilter)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.Block) + fc.Result = res + return ec.marshalOBlock2ᚕᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlockᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_blocks(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "height": + return ec.fieldContext_Block_height(ctx, field) + case "version": + return ec.fieldContext_Block_version(ctx, field) + case "chain_id": + return ec.fieldContext_Block_chain_id(ctx, field) + case "time": + return ec.fieldContext_Block_time(ctx, field) + case "proposer_address_raw": + return ec.fieldContext_Block_proposer_address_raw(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Block", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_blocks_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_latestBlockHeight(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_latestBlockHeight(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().LatestBlockHeight(rctx) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_latestBlockHeight(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query___type(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.introspectType(fc.Args["name"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query___schema(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.introspectSchema() + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Schema) + fc.Result = res + return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "description": + return ec.fieldContext___Schema_description(ctx, field) + case "types": + return ec.fieldContext___Schema_types(ctx, field) + case "queryType": + return ec.fieldContext___Schema_queryType(ctx, field) + case "mutationType": + return ec.fieldContext___Schema_mutationType(ctx, field) + case "subscriptionType": + return ec.fieldContext___Schema_subscriptionType(ctx, field) + case "directives": + return ec.fieldContext___Schema_directives(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Subscription_transactions(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_transactions(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().Transactions(rctx, fc.Args["filter"].(model.TransactionFilter)) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan *model.Transaction): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNTransaction2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransaction(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_transactions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "index": + return ec.fieldContext_Transaction_index(ctx, field) + case "block_height": + return ec.fieldContext_Transaction_block_height(ctx, field) + case "gas_wanted": + return ec.fieldContext_Transaction_gas_wanted(ctx, field) + case "gas_used": + return ec.fieldContext_Transaction_gas_used(ctx, field) + case "content_raw": + return ec.fieldContext_Transaction_content_raw(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Transaction", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Subscription_transactions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Subscription_blocks(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_blocks(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().Blocks(rctx, fc.Args["filter"].(model.BlockFilter)) + }) + if err != nil { + ec.Error(ctx, err) + return nil + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan *model.Block): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNBlock2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlock(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_blocks(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "height": + return ec.fieldContext_Block_height(ctx, field) + case "version": + return ec.fieldContext_Block_version(ctx, field) + case "chain_id": + return ec.fieldContext_Block_chain_id(ctx, field) + case "time": + return ec.fieldContext_Block_time(ctx, field) + case "proposer_address_raw": + return ec.fieldContext_Block_proposer_address_raw(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Block", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Subscription_blocks_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Transaction_index(ctx context.Context, field graphql.CollectedField, obj *model.Transaction) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Transaction_index(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Index(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Transaction_index(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Transaction", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Transaction_block_height(ctx context.Context, field graphql.CollectedField, obj *model.Transaction) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Transaction_block_height(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.BlockHeight(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Transaction_block_height(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Transaction", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Transaction_gas_wanted(ctx context.Context, field graphql.CollectedField, obj *model.Transaction) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Transaction_gas_wanted(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GasWanted(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Transaction_gas_wanted(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Transaction", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Transaction_gas_used(ctx context.Context, field graphql.CollectedField, obj *model.Transaction) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Transaction_gas_used(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GasUsed(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Transaction_gas_used(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Transaction", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Transaction_content_raw(ctx context.Context, field graphql.CollectedField, obj *model.Transaction) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Transaction_content_raw(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ContentRaw(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Transaction_content_raw(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Transaction", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_locations(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Locations, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type __DirectiveLocation does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_args(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Args, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___InputValue_name(ctx, field) + case "description": + return ec.fieldContext___InputValue_description(ctx, field) + case "type": + return ec.fieldContext___InputValue_type(ctx, field) + case "defaultValue": + return ec.fieldContext___InputValue_defaultValue(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsRepeatable, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___EnumValue_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___EnumValue_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___EnumValue_isDeprecated(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsDeprecated(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___EnumValue_deprecationReason(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeprecationReason(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_args(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Args, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___InputValue_name(ctx, field) + case "description": + return ec.fieldContext___InputValue_description(ctx, field) + case "type": + return ec.fieldContext___InputValue_type(ctx, field) + case "defaultValue": + return ec.fieldContext___InputValue_defaultValue(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_type(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Type, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_isDeprecated(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsDeprecated(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_deprecationReason(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeprecationReason(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_type(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Type, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_defaultValue(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DefaultValue, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_types(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Types(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_queryType(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.QueryType(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_mutationType(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.MutationType(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_subscriptionType(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SubscriptionType(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_directives(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Directives(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.Directive) + fc.Result = res + return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___Directive_name(ctx, field) + case "description": + return ec.fieldContext___Directive_description(ctx, field) + case "locations": + return ec.fieldContext___Directive_locations(ctx, field) + case "args": + return ec.fieldContext___Directive_args(ctx, field) + case "isRepeatable": + return ec.fieldContext___Directive_isRepeatable(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_kind(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalN__TypeKind2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type __TypeKind does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_fields(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Field) + fc.Result = res + return ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_fields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___Field_name(ctx, field) + case "description": + return ec.fieldContext___Field_description(ctx, field) + case "args": + return ec.fieldContext___Field_args(ctx, field) + case "type": + return ec.fieldContext___Field_type(ctx, field) + case "isDeprecated": + return ec.fieldContext___Field_isDeprecated(ctx, field) + case "deprecationReason": + return ec.fieldContext___Field_deprecationReason(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Field", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field___Type_fields_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_interfaces(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Interfaces(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_possibleTypes(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PossibleTypes(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_enumValues(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.EnumValue) + fc.Result = res + return ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_enumValues(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___EnumValue_name(ctx, field) + case "description": + return ec.fieldContext___EnumValue_description(ctx, field) + case "isDeprecated": + return ec.fieldContext___EnumValue_isDeprecated(ctx, field) + case "deprecationReason": + return ec.fieldContext___EnumValue_deprecationReason(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __EnumValue", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field___Type_enumValues_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_inputFields(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.InputFields(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___InputValue_name(ctx, field) + case "description": + return ec.fieldContext___InputValue_description(ctx, field) + case "type": + return ec.fieldContext___InputValue_type(ctx, field) + case "defaultValue": + return ec.fieldContext___InputValue_defaultValue(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_ofType(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OfType(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SpecifiedByURL(), nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +// endregion **************************** field.gotpl ***************************** + +// region **************************** input.gotpl ***************************** + +func (ec *executionContext) unmarshalInputBlockFilter(ctx context.Context, obj interface{}) (model.BlockFilter, error) { + var it model.BlockFilter + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"from_height", "to_height", "from_time", "to_time"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "from_height": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("from_height")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.FromHeight = data + case "to_height": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("to_height")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.ToHeight = data + case "from_time": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("from_time")) + data, err := ec.unmarshalOTime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.FromTime = data + case "to_time": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("to_time")) + data, err := ec.unmarshalOTime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.ToTime = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputTransactionFilter(ctx context.Context, obj interface{}) (model.TransactionFilter, error) { + var it model.TransactionFilter + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"from_block_height", "to_block_height", "from_index", "to_index", "from_gas_wanted", "to_gas_wanted", "from_gas_used", "to_gas_used"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "from_block_height": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("from_block_height")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.FromBlockHeight = data + case "to_block_height": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("to_block_height")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.ToBlockHeight = data + case "from_index": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("from_index")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.FromIndex = data + case "to_index": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("to_index")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.ToIndex = data + case "from_gas_wanted": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("from_gas_wanted")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.FromGasWanted = data + case "to_gas_wanted": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("to_gas_wanted")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.ToGasWanted = data + case "from_gas_used": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("from_gas_used")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.FromGasUsed = data + case "to_gas_used": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("to_gas_used")) + data, err := ec.unmarshalOInt2ᚖint(ctx, v) + if err != nil { + return it, err + } + it.ToGasUsed = data + } + } + + return it, nil +} + +// endregion **************************** input.gotpl ***************************** + +// region ************************** interface.gotpl *************************** + +// endregion ************************** interface.gotpl *************************** + +// region **************************** object.gotpl **************************** + +var blockImplementors = []string{"Block"} + +func (ec *executionContext) _Block(ctx context.Context, sel ast.SelectionSet, obj *model.Block) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, blockImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Block") + case "height": + out.Values[i] = ec._Block_height(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "version": + out.Values[i] = ec._Block_version(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "chain_id": + out.Values[i] = ec._Block_chain_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "time": + out.Values[i] = ec._Block_time(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "proposer_address_raw": + out.Values[i] = ec._Block_proposer_address_raw(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var queryImplementors = []string{"Query"} + +func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ + Object: "Query", + }) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ + Object: field.Name, + Field: field, + }) + + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Query") + case "transactions": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_transactions(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "blocks": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_blocks(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "latestBlockHeight": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_latestBlockHeight(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "__type": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___type(ctx, field) + }) + case "__schema": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___schema(ctx, field) + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var subscriptionImplementors = []string{"Subscription"} + +func (ec *executionContext) _Subscription(ctx context.Context, sel ast.SelectionSet) func(ctx context.Context) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, subscriptionImplementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ + Object: "Subscription", + }) + if len(fields) != 1 { + ec.Errorf(ctx, "must subscribe to exactly one stream") + return nil + } + + switch fields[0].Name { + case "transactions": + return ec._Subscription_transactions(ctx, fields[0]) + case "blocks": + return ec._Subscription_blocks(ctx, fields[0]) + default: + panic("unknown field " + strconv.Quote(fields[0].Name)) + } +} + +var transactionImplementors = []string{"Transaction"} + +func (ec *executionContext) _Transaction(ctx context.Context, sel ast.SelectionSet, obj *model.Transaction) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, transactionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Transaction") + case "index": + out.Values[i] = ec._Transaction_index(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "block_height": + out.Values[i] = ec._Transaction_block_height(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "gas_wanted": + out.Values[i] = ec._Transaction_gas_wanted(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "gas_used": + out.Values[i] = ec._Transaction_gas_used(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "content_raw": + out.Values[i] = ec._Transaction_content_raw(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __DirectiveImplementors = []string{"__Directive"} + +func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Directive") + case "name": + out.Values[i] = ec.___Directive_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec.___Directive_description(ctx, field, obj) + case "locations": + out.Values[i] = ec.___Directive_locations(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "args": + out.Values[i] = ec.___Directive_args(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isRepeatable": + out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __EnumValueImplementors = []string{"__EnumValue"} + +func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__EnumValue") + case "name": + out.Values[i] = ec.___EnumValue_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec.___EnumValue_description(ctx, field, obj) + case "isDeprecated": + out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deprecationReason": + out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __FieldImplementors = []string{"__Field"} + +func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Field") + case "name": + out.Values[i] = ec.___Field_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec.___Field_description(ctx, field, obj) + case "args": + out.Values[i] = ec.___Field_args(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "type": + out.Values[i] = ec.___Field_type(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isDeprecated": + out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deprecationReason": + out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __InputValueImplementors = []string{"__InputValue"} + +func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__InputValue") + case "name": + out.Values[i] = ec.___InputValue_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec.___InputValue_description(ctx, field, obj) + case "type": + out.Values[i] = ec.___InputValue_type(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "defaultValue": + out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __SchemaImplementors = []string{"__Schema"} + +func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Schema") + case "description": + out.Values[i] = ec.___Schema_description(ctx, field, obj) + case "types": + out.Values[i] = ec.___Schema_types(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "queryType": + out.Values[i] = ec.___Schema_queryType(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "mutationType": + out.Values[i] = ec.___Schema_mutationType(ctx, field, obj) + case "subscriptionType": + out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj) + case "directives": + out.Values[i] = ec.___Schema_directives(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __TypeImplementors = []string{"__Type"} + +func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Type") + case "kind": + out.Values[i] = ec.___Type_kind(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec.___Type_name(ctx, field, obj) + case "description": + out.Values[i] = ec.___Type_description(ctx, field, obj) + case "fields": + out.Values[i] = ec.___Type_fields(ctx, field, obj) + case "interfaces": + out.Values[i] = ec.___Type_interfaces(ctx, field, obj) + case "possibleTypes": + out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj) + case "enumValues": + out.Values[i] = ec.___Type_enumValues(ctx, field, obj) + case "inputFields": + out.Values[i] = ec.___Type_inputFields(ctx, field, obj) + case "ofType": + out.Values[i] = ec.___Type_ofType(ctx, field, obj) + case "specifiedByURL": + out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +// endregion **************************** object.gotpl **************************** + +// region ***************************** type.gotpl ***************************** + +func (ec *executionContext) marshalNBlock2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlock(ctx context.Context, sel ast.SelectionSet, v model.Block) graphql.Marshaler { + return ec._Block(ctx, sel, &v) +} + +func (ec *executionContext) marshalNBlock2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlock(ctx context.Context, sel ast.SelectionSet, v *model.Block) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Block(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNBlockFilter2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlockFilter(ctx context.Context, v interface{}) (model.BlockFilter, error) { + res, err := ec.unmarshalInputBlockFilter(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { + res, err := graphql.UnmarshalBoolean(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { + res := graphql.MarshalBoolean(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { + res, err := graphql.UnmarshalInt(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { + res := graphql.MarshalInt(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) unmarshalNInt2int64(ctx context.Context, v interface{}) (int64, error) { + res, err := graphql.UnmarshalInt64(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNInt2int64(ctx context.Context, sel ast.SelectionSet, v int64) graphql.Marshaler { + res := graphql.MarshalInt64(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) unmarshalNTime2timeᚐTime(ctx context.Context, v interface{}) (time.Time, error) { + res, err := graphql.UnmarshalTime(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler { + res := graphql.MarshalTime(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) marshalNTransaction2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransaction(ctx context.Context, sel ast.SelectionSet, v model.Transaction) graphql.Marshaler { + return ec._Transaction(ctx, sel, &v) +} + +func (ec *executionContext) marshalNTransaction2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransaction(ctx context.Context, sel ast.SelectionSet, v *model.Transaction) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Transaction(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNTransactionFilter2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransactionFilter(ctx context.Context, v interface{}) (model.TransactionFilter, error) { + res, err := ec.unmarshalInputTransactionFilter(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { + return ec.___Directive(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler { + return ec.___EnumValue(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler { + return ec.___Field(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler { + return ec.___InputValue(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { + return ec.___Type(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec.___Type(ctx, sel, v) +} + +func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) marshalOBlock2ᚕᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlockᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Block) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNBlock2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlock(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { + res, err := graphql.UnmarshalBoolean(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { + res := graphql.MarshalBoolean(v) + return res +} + +func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalBoolean(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalBoolean(*v) + return res +} + +func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalInt(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.SelectionSet, v *int) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalInt(*v) + return res +} + +func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalString(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalString(*v) + return res +} + +func (ec *executionContext) unmarshalOTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalTime(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalTime(*v) + return res +} + +func (ec *executionContext) marshalOTransaction2ᚕᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransactionᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Transaction) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNTransaction2ᚖgithubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransaction(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec.___Schema(ctx, sel, v) +} + +func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec.___Type(ctx, sel, v) +} + +// endregion ***************************** type.gotpl ***************************** diff --git a/serve/graph/model/block.go b/serve/graph/model/block.go new file mode 100644 index 00000000..7dfc2222 --- /dev/null +++ b/serve/graph/model/block.go @@ -0,0 +1,42 @@ +package model + +import ( + "strconv" + "time" + + "github.com/gnolang/gno/tm2/pkg/bft/types" +) + +type Block struct { + b *types.Block +} + +func NewBlock(b *types.Block) *Block { + return &Block{ + b: b, + } +} + +func (b *Block) ID() string { + return strconv.Itoa(int(b.b.Height)) +} + +func (b *Block) Height() int64 { + return b.b.Height +} + +func (b *Block) Version() string { + return b.b.Version +} + +func (b *Block) ChainID() string { + return b.b.ChainID +} + +func (b *Block) Time() time.Time { + return b.b.Time +} + +func (b *Block) ProposerAddressRaw() string { + return b.b.ProposerAddress.String() +} diff --git a/serve/graph/model/models_gen.go b/serve/graph/model/models_gen.go new file mode 100644 index 00000000..92f5a244 --- /dev/null +++ b/serve/graph/model/models_gen.go @@ -0,0 +1,48 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package model + +import ( + "time" +) + +// Filters for querying Blocks within specified criteria related to their attributes. +type BlockFilter struct { + // Minimum block height from which to start fetching Blocks, inclusive. If unspecified, there is no lower bound. + FromHeight *int `json:"from_height,omitempty"` + // Maximum block height up to which Blocks should be fetched, exclusive. If unspecified, there is no upper bound. + ToHeight *int `json:"to_height,omitempty"` + // Minimum timestamp from which to start fetching Blocks, inclusive. Blocks created at or after this time will be included. + FromTime *time.Time `json:"from_time,omitempty"` + // Maximum timestamp up to which to fetch Blocks, exclusive. Only Blocks created before this time are included. + ToTime *time.Time `json:"to_time,omitempty"` +} + +// Root Query type to fetch data about Blocks and Transactions based on filters or retrieve the latest block height. +type Query struct { +} + +// Subscriptions provide a way for clients to receive real-time updates about Transactions and Blocks based on specified filter criteria. +// Subscribers will only receive updates for events occurring after the subscription is established. +type Subscription struct { +} + +// Filters for querying Transactions within specified criteria related to their execution and placement within Blocks. +type TransactionFilter struct { + // Minimum block height from which to start fetching Transactions, inclusive. Aids in scoping the search to recent Transactions. + FromBlockHeight *int `json:"from_block_height,omitempty"` + // Maximum block height up to which Transactions should be fetched, exclusive. Helps in limiting the search to older Transactions. + ToBlockHeight *int `json:"to_block_height,omitempty"` + // Minimum Transaction index from which to start fetching, inclusive. Facilitates ordering in Transaction queries. + FromIndex *int `json:"from_index,omitempty"` + // Maximum Transaction index up to which to fetch, exclusive. Ensures a limit on the ordering range for Transaction queries. + ToIndex *int `json:"to_index,omitempty"` + // Minimum `gas_wanted` value to filter Transactions by, inclusive. Filters Transactions based on the minimum computational effort declared. + FromGasWanted *int `json:"from_gas_wanted,omitempty"` + // Maximum `gas_wanted` value for filtering Transactions, exclusive. Limits Transactions based on the declared computational effort. + ToGasWanted *int `json:"to_gas_wanted,omitempty"` + // Minimum `gas_used` value to filter Transactions by, inclusive. Selects Transactions based on the minimum computational effort actually used. + FromGasUsed *int `json:"from_gas_used,omitempty"` + // Maximum `gas_used` value for filtering Transactions, exclusive. Refines selection based on the computational effort actually consumed. + ToGasUsed *int `json:"to_gas_used,omitempty"` +} diff --git a/serve/graph/model/transaction.go b/serve/graph/model/transaction.go new file mode 100644 index 00000000..f863cd8c --- /dev/null +++ b/serve/graph/model/transaction.go @@ -0,0 +1,39 @@ +package model + +import ( + "fmt" + + "github.com/gnolang/gno/tm2/pkg/bft/types" +) + +type Transaction struct { + t *types.TxResult +} + +func NewTransaction(t *types.TxResult) *Transaction { + return &Transaction{t: t} +} + +func (t *Transaction) ID() string { + return fmt.Sprintf("%d_%d", t.t.Height, t.t.Index) +} + +func (t *Transaction) Index() int { + return int(t.t.Index) +} + +func (t *Transaction) BlockHeight() int { + return int(t.t.Height) +} + +func (t *Transaction) GasWanted() int { + return int(t.t.Response.GasWanted) +} + +func (t *Transaction) GasUsed() int { + return int(t.t.Response.GasUsed) +} + +func (t *Transaction) ContentRaw() string { + return t.t.Tx.String() +} diff --git a/serve/graph/resolver.go b/serve/graph/resolver.go new file mode 100644 index 00000000..3dc7da8e --- /dev/null +++ b/serve/graph/resolver.go @@ -0,0 +1,40 @@ +//go:generate go run github.com/99designs/gqlgen generate + +package graph + +import ( + "time" + + "github.com/gnolang/tx-indexer/storage" +) + +// This file will not be regenerated automatically. +// +// It serves as dependency injection for your app, add any dependencies you require here. + +const maxElementsPerQuery = 10000 + +func dereferenceInt(i *int) int { + if i == nil { + return 0 + } else { + return *i + } +} + +func dereferenceTime(i *time.Time) time.Time { + if i == nil { + var t time.Time + return t + } else { + return *i + } +} + +type Resolver struct { + store storage.Storage +} + +func NewResolver(s storage.Storage) *Resolver { + return &Resolver{store: s} +} diff --git a/serve/graph/schema.graphql b/serve/graph/schema.graphql new file mode 100644 index 00000000..150fa3f5 --- /dev/null +++ b/serve/graph/schema.graphql @@ -0,0 +1,200 @@ +""" +Represents a blockchain block with various attributes detailing its creation and content. +""" +type Block { + + """ + A unique identifier for the Block determined by its position in the blockchain. + This integer is strictly increasing with each new Block. + """ + height: Int! + + """ + The software version of the node that created this Block, indicating the specific + implementation and versioning of the blockchain protocol used. + """ + version: String! + + """ + An identifier for the specific blockchain network this Block belongs to. Helps in + distinguishing between different networks like mainnet, testnet, etc. + """ + chain_id: String! + + """ + The timestamp at which this Block was proposed and finalized in the blockchain. Represented in UTC. + """ + time: Time! + + """ + Encoded data representing the blockchain address of the proposer who submitted this Block. + It is raw and requires decoding to be human-readable. + """ + proposer_address_raw: String! +} + +""" +Defines a transaction within a block, detailing its execution specifics and content. +""" +type Transaction { + + """ + A sequential index representing the order of this Transaction within its Block. Unique within the context of its Block. + """ + index: Int! + + """ + The height of the Block in which this Transaction is included. Links the Transaction to its containing Block. + """ + block_height: Int! + + """ + The declared amount of computational effort the sender is willing to pay for executing this Transaction. + """ + gas_wanted: Int! + + """ + The actual amount of computational effort consumed to execute this Transaction. It could be less or equal to `gas_wanted`. + """ + gas_used: Int! + + """ + The payload of the Transaction in a raw format, typically containing the instructions and any data necessary for execution. + """ + content_raw: String! +} + +""" +Filters for querying Blocks within specified criteria related to their attributes. +""" +input BlockFilter { + + """ + Minimum block height from which to start fetching Blocks, inclusive. If unspecified, there is no lower bound. + """ + from_height: Int + + """ + Maximum block height up to which Blocks should be fetched, exclusive. If unspecified, there is no upper bound. + """ + to_height: Int + + """ + Minimum timestamp from which to start fetching Blocks, inclusive. Blocks created at or after this time will be included. + """ + from_time: Time + + """ + Maximum timestamp up to which to fetch Blocks, exclusive. Only Blocks created before this time are included. + """ + to_time: Time +} + +""" +Filters for querying Transactions within specified criteria related to their execution and placement within Blocks. +""" +input TransactionFilter { + + """ + Minimum block height from which to start fetching Transactions, inclusive. Aids in scoping the search to recent Transactions. + """ + from_block_height: Int + + """ + Maximum block height up to which Transactions should be fetched, exclusive. Helps in limiting the search to older Transactions. + """ + to_block_height: Int + + """ + Minimum Transaction index from which to start fetching, inclusive. Facilitates ordering in Transaction queries. + """ + from_index: Int + + """ + Maximum Transaction index up to which to fetch, exclusive. Ensures a limit on the ordering range for Transaction queries. + """ + to_index: Int + + """ + Minimum `gas_wanted` value to filter Transactions by, inclusive. Filters Transactions based on the minimum computational effort declared. + """ + from_gas_wanted: Int + + """ + Maximum `gas_wanted` value for filtering Transactions, exclusive. Limits Transactions based on the declared computational effort. + """ + to_gas_wanted: Int + + """ + Minimum `gas_used` value to filter Transactions by, inclusive. Selects Transactions based on the minimum computational effort actually used. + """ + from_gas_used: Int + + """ + Maximum `gas_used` value for filtering Transactions, exclusive. Refines selection based on the computational effort actually consumed. + """ + to_gas_used: Int +} + +""" +Root Query type to fetch data about Blocks and Transactions based on filters or retrieve the latest block height. +""" +type Query { + + """ + Retrieves a list of Transactions that match the given filter criteria. If the result is incomplete due to errors, both partial results and errors are returned. + """ + transactions(filter: TransactionFilter!): [Transaction!] + + """ + Fetches Blocks matching the specified filter criteria. Incomplete results due to errors return both the partial Blocks and the associated errors. + """ + blocks(filter: BlockFilter!): [Block!] + + """ + Returns the height of the most recently processed Block by the blockchain indexer, indicating the current length of the blockchain. + """ + latestBlockHeight: Int! +} + +""" +Subscriptions provide a way for clients to receive real-time updates about Transactions and Blocks based on specified filter criteria. +Subscribers will only receive updates for events occurring after the subscription is established. +""" +type Subscription { + + """ + Subscribes to real-time updates of Transactions that match the provided filter criteria. + This subscription starts immediately and only includes Transactions added to the blockchain after the subscription is active. + + This is useful for applications needing to track Transactions in real-time, such as wallets tracking incoming transactions + or analytics platforms monitoring blockchain activity. + + Parameters: + - filter: TransactionFilter - Specifies the criteria used to filter the Transactions for which real-time updates are desired. + + Returns: + - Transaction: Each received update is a Transaction object that matches the filter criteria. + """ + transactions(filter: TransactionFilter!): Transaction! + + """ + Subscribes to real-time updates of Blocks that match the provided filter criteria. Similar to the Transactions subscription, + this subscription is active immediately upon creation and only includes Blocks added after the subscription begins. + + This subscription is ideal for services that need to be notified of new Blocks for processing or analysis, such as block explorers, + data aggregators, or security monitoring tools. + + Parameters: + - filter: BlockFilter - Defines the conditions Blocks must meet to trigger an update to the subscriber. + + Returns: + - Block: Each update consists of a Block object that satisfies the filter criteria, allowing subscribers to process or analyze new Blocks in real time. + """ + blocks(filter: BlockFilter!): Block! +} + +""" +Field representing a point on time. It is following the RFC3339Nano format ("2006-01-02T15:04:05.999999999Z07:00") +""" +scalar Time diff --git a/serve/graph/schema.resolvers.go b/serve/graph/schema.resolvers.go new file mode 100644 index 00000000..efc9ed61 --- /dev/null +++ b/serve/graph/schema.resolvers.go @@ -0,0 +1,145 @@ +package graph + +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.43 + +import ( + "context" + "fmt" + + "github.com/99designs/gqlgen/graphql" + "github.com/vektah/gqlparser/v2/gqlerror" + + "github.com/gnolang/tx-indexer/serve/graph/model" +) + +// Transactions is the resolver for the transactions field. +func (r *queryResolver) Transactions(ctx context.Context, filter model.TransactionFilter) ([]*model.Transaction, error) { + it, err := r. + store. + TxIterator( + int64(dereferenceInt(filter.FromBlockHeight)), + int64(dereferenceInt(filter.ToBlockHeight)), + uint32(dereferenceInt(filter.FromIndex)), + uint32(dereferenceInt(filter.ToIndex)), + ) + if err != nil { + return nil, gqlerror.Wrap(err) + } + defer it.Close() + + fgw := dereferenceInt(filter.FromGasUsed) + tgw := dereferenceInt(filter.ToGasWanted) + fgu := dereferenceInt(filter.FromGasUsed) + tgu := dereferenceInt(filter.ToGasUsed) + + var out []*model.Transaction + i := 0 + for { + if i == maxElementsPerQuery { + graphql.AddErrorf(ctx, "max elements per query reached (%d)", maxElementsPerQuery) + return out, nil + } + + if !it.Next() { + return out, it.Error() + } + + select { + case <-ctx.Done(): + graphql.AddError(ctx, ctx.Err()) + return out, nil + default: + t, err := it.Value() + if err != nil { + graphql.AddError(ctx, err) + return out, nil + } + + if !(t.Response.GasUsed >= int64(fgu) && (tgu == 0 || t.Response.GasUsed <= int64(tgu))) { + continue + } + if !(t.Response.GasWanted >= int64(fgw) && (tgw == 0 || t.Response.GasWanted <= int64(tgw))) { + continue + } + + out = append(out, model.NewTransaction(t)) + i++ + } + } +} + +// Blocks is the resolver for the blocks field. +func (r *queryResolver) Blocks(ctx context.Context, filter model.BlockFilter) ([]*model.Block, error) { + it, err := r. + store. + BlockIterator( + int64(dereferenceInt(filter.FromHeight)), + int64(dereferenceInt(filter.ToHeight)), + ) + if err != nil { + return nil, gqlerror.Wrap(err) + } + defer it.Close() + + dft := dereferenceTime(filter.FromTime) + + var out []*model.Block + + i := 0 + for { + if i == maxElementsPerQuery { + graphql.AddErrorf(ctx, "max elements per query reached (%d)", maxElementsPerQuery) + return out, nil + } + + if !it.Next() { + return out, it.Error() + } + + select { + case <-ctx.Done(): + graphql.AddError(ctx, ctx.Err()) + return out, nil + default: + b, err := it.Value() + if err != nil { + graphql.AddError(ctx, err) + return out, nil + } + + if !((b.Time.After(dft) || b.Time.Equal(dft)) && (filter.ToTime == nil || b.Time.Before(*filter.ToTime))) { + continue + } + + out = append(out, model.NewBlock(b)) + i++ + } + } +} + +// LatestBlockHeight is the resolver for the latestBlockHeight field. +func (r *queryResolver) LatestBlockHeight(ctx context.Context) (int, error) { + h, err := r.store.GetLatestHeight() + return int(h), err +} + +// Transactions is the resolver for the transactions field. +func (r *subscriptionResolver) Transactions(ctx context.Context, filter model.TransactionFilter) (<-chan *model.Transaction, error) { + panic(fmt.Errorf("not implemented: Transactions - transactions")) +} + +// Blocks is the resolver for the blocks field. +func (r *subscriptionResolver) Blocks(ctx context.Context, filter model.BlockFilter) (<-chan *model.Block, error) { + panic(fmt.Errorf("not implemented: Blocks - blocks")) +} + +// Query returns QueryResolver implementation. +func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } + +// Subscription returns SubscriptionResolver implementation. +func (r *Resolver) Subscription() SubscriptionResolver { return &subscriptionResolver{r} } + +type queryResolver struct{ *Resolver } +type subscriptionResolver struct{ *Resolver } diff --git a/serve/graph/setup.go b/serve/graph/setup.go new file mode 100644 index 00000000..8203313b --- /dev/null +++ b/serve/graph/setup.go @@ -0,0 +1,21 @@ +package graph + +import ( + "github.com/99designs/gqlgen/graphql/handler" + "github.com/99designs/gqlgen/graphql/handler/transport" + "github.com/99designs/gqlgen/graphql/playground" + "github.com/go-chi/chi/v5" + + "github.com/gnolang/tx-indexer/storage" +) + +func Setup(s storage.Storage, m *chi.Mux) *chi.Mux { + srv := handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: NewResolver(s)})) + + srv.AddTransport(&transport.Websocket{}) + + m.Handle("/", playground.Handler("GraphQL playground", "/query")) + m.Handle("/query", srv) + + return m +} diff --git a/serve/handler_test.go b/serve/handler_test.go index 9d6a1ce7..bc0b96b2 100644 --- a/serve/handler_test.go +++ b/serve/handler_test.go @@ -9,12 +9,13 @@ import ( "net/http" "testing" - "github.com/gnolang/tx-indexer/serve/metadata" - "github.com/gnolang/tx-indexer/serve/spec" "github.com/go-chi/chi/v5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" + + "github.com/gnolang/tx-indexer/serve/metadata" + "github.com/gnolang/tx-indexer/serve/spec" ) func decodeResponse[T spec.BaseJSONResponse | spec.BaseJSONResponses](t *testing.T, responseBody []byte) *T { @@ -161,7 +162,7 @@ func newWebServer(t *testing.T, callbacks ...func(s *JSONRPC)) *testWebServer { } // Hook up the JSON-RPC server to the mux - mux.Mount("/", s.setupRouter()) + mux.Mount("/", s.SetupRoutes(chi.NewMux())) return webServer } diff --git a/serve/handlers/tx/mocks_test.go b/serve/handlers/tx/mocks_test.go index 1da3687a..260b7a82 100644 --- a/serve/handlers/tx/mocks_test.go +++ b/serve/handlers/tx/mocks_test.go @@ -2,15 +2,15 @@ package tx import "github.com/gnolang/gno/tm2/pkg/bft/types" -type getTxDelegate func([]byte) (*types.TxResult, error) +type getTxDelegate func(int64, uint32) (*types.TxResult, error) type mockStorage struct { getTxFn getTxDelegate } -func (m *mockStorage) GetTx(hash []byte) (*types.TxResult, error) { +func (m *mockStorage) GetTx(bn int64, ti uint32) (*types.TxResult, error) { if m.getTxFn != nil { - return m.getTxFn(hash) + return m.getTxFn(bn, ti) } return nil, nil diff --git a/serve/handlers/tx/tx.go b/serve/handlers/tx/tx.go index 246b89f8..0d3fd410 100644 --- a/serve/handlers/tx/tx.go +++ b/serve/handlers/tx/tx.go @@ -1,10 +1,10 @@ package tx import ( - "encoding/base64" "errors" "github.com/gnolang/gno/tm2/pkg/bft/types" + "github.com/gnolang/tx-indexer/serve/encode" "github.com/gnolang/tx-indexer/serve/metadata" "github.com/gnolang/tx-indexer/serve/spec" @@ -26,24 +26,23 @@ func (h *Handler) GetTxHandler( params []any, ) (any, *spec.BaseJSONError) { // Check the params - if len(params) < 1 { + if len(params) < 2 { return nil, spec.GenerateInvalidParamCountError() } // Extract the params - requestedTx, ok := params[0].(string) + blockNum, ok := params[0].(int64) if !ok { return nil, spec.GenerateInvalidParamError(1) } - // Decode the hash from base64 - decodedHash, err := base64.StdEncoding.DecodeString(requestedTx) - if err != nil { + txIndex, ok := params[1].(uint32) + if !ok { return nil, spec.GenerateInvalidParamError(1) } // Run the handler - response, err := h.getTx(decodedHash) + response, err := h.getTx(blockNum, txIndex) if err != nil { return nil, spec.GenerateResponseError(err) } @@ -61,8 +60,8 @@ func (h *Handler) GetTxHandler( } // getTx fetches the tx from storage, if any -func (h *Handler) getTx(txHash []byte) (*types.TxResult, error) { - tx, err := h.storage.GetTx(txHash) +func (h *Handler) getTx(blockNum int64, txIndex uint32) (*types.TxResult, error) { + tx, err := h.storage.GetTx(blockNum, txIndex) if errors.Is(err, storageErrors.ErrNotFound) { // Wrap the error //nolint:nilnil // This is a special case diff --git a/serve/handlers/tx/tx_test.go b/serve/handlers/tx/tx_test.go index 14c27f6e..2e1c2980 100644 --- a/serve/handlers/tx/tx_test.go +++ b/serve/handlers/tx/tx_test.go @@ -7,10 +7,11 @@ import ( "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" - "github.com/gnolang/tx-indexer/serve/spec" - storageErrors "github.com/gnolang/tx-indexer/storage/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/gnolang/tx-indexer/serve/spec" + storageErrors "github.com/gnolang/tx-indexer/storage/errors" ) func TestGetTx_InvalidParams(t *testing.T) { @@ -26,11 +27,7 @@ func TestGetTx_InvalidParams(t *testing.T) { }, { "invalid param type", - []any{1}, - }, - { - "invalid base64 type", - []any{"totally base64"}, + []any{"totally invalid param type"}, }, } @@ -59,12 +56,13 @@ func TestGetBlock_Handler(t *testing.T) { t.Parallel() var ( - txHash = []byte("random") - txHash64 = base64.StdEncoding.EncodeToString(txHash) + blockNum = int64(42) + txIndex = uint32(42) mockStorage = &mockStorage{ - getTxFn: func(hash []byte) (*types.TxResult, error) { - require.Equal(t, txHash, hash) + getTxFn: func(bn int64, ti uint32) (*types.TxResult, error) { + require.Equal(t, blockNum, bn) + require.Equal(t, txIndex, ti) return nil, storageErrors.ErrNotFound }, @@ -73,7 +71,7 @@ func TestGetBlock_Handler(t *testing.T) { h := NewHandler(mockStorage) - response, err := h.GetTxHandler(nil, []any{txHash64}) + response, err := h.GetTxHandler(nil, []any{blockNum, txIndex}) // This is a special case assert.Nil(t, response) @@ -84,13 +82,13 @@ func TestGetBlock_Handler(t *testing.T) { t.Parallel() var ( - txHash = []byte("random") - txHash64 = base64.StdEncoding.EncodeToString(txHash) + blockNum = int64(42) + txIndex = uint32(42) fetchErr = errors.New("random error") mockStorage = &mockStorage{ - getTxFn: func(_ []byte) (*types.TxResult, error) { + getTxFn: func(_ int64, _ uint32) (*types.TxResult, error) { return nil, fetchErr }, } @@ -98,7 +96,7 @@ func TestGetBlock_Handler(t *testing.T) { h := NewHandler(mockStorage) - response, err := h.GetTxHandler(nil, []any{txHash64}) + response, err := h.GetTxHandler(nil, []any{blockNum, txIndex}) assert.Nil(t, response) // Make sure the error is populated @@ -112,17 +110,17 @@ func TestGetBlock_Handler(t *testing.T) { t.Parallel() var ( - txHash = []byte("random") - txHash64 = base64.StdEncoding.EncodeToString(txHash) + blockNum = int64(42) + txIndex = uint32(42) txResult = &types.TxResult{ Height: 10, } mockStorage = &mockStorage{ - getTxFn: func(hash []byte) (*types.TxResult, error) { - require.Equal(t, txHash, hash) - + getTxFn: func(bn int64, ti uint32) (*types.TxResult, error) { + require.Equal(t, blockNum, bn) + require.Equal(t, txIndex, ti) return txResult, nil }, } @@ -130,7 +128,7 @@ func TestGetBlock_Handler(t *testing.T) { h := NewHandler(mockStorage) - responseRaw, err := h.GetTxHandler(nil, []any{txHash64}) + responseRaw, err := h.GetTxHandler(nil, []any{blockNum, txIndex}) require.Nil(t, err) require.NotNil(t, responseRaw) diff --git a/serve/handlers/tx/types.go b/serve/handlers/tx/types.go index beccbfc0..8e998a07 100644 --- a/serve/handlers/tx/types.go +++ b/serve/handlers/tx/types.go @@ -4,5 +4,5 @@ import "github.com/gnolang/gno/tm2/pkg/bft/types" type Storage interface { // GetTx returns specified tx from permanent storage - GetTx([]byte) (*types.TxResult, error) + GetTx(int64, uint32) (*types.TxResult, error) } diff --git a/serve/jsonrpc.go b/serve/jsonrpc.go index 31a32735..ce1615a4 100644 --- a/serve/jsonrpc.go +++ b/serve/jsonrpc.go @@ -3,18 +3,14 @@ package serve import ( "context" "encoding/json" - "errors" "io" - "net" "net/http" - "time" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/google/uuid" "github.com/olahol/melody" "go.uber.org/zap" - "golang.org/x/sync/errgroup" "github.com/gnolang/tx-indexer/serve/conns" "github.com/gnolang/tx-indexer/serve/conns/wsconn" @@ -36,10 +32,6 @@ const ( wsIDKey = "ws-id" // key used for WS connection metadata ) -const ( - DefaultListenAddress = "0.0.0.0:8545" -) - // maxSizeMiddleware enforces a 1MB size limit on the request body func maxSizeMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -67,19 +59,15 @@ type JSONRPC struct { // ws handles incoming and active WS connections ws *melody.Melody - - // listenAddress is the serve address - listenAddress string } // NewJSONRPC creates a new instance of the JSONRPC server func NewJSONRPC(events Events, opts ...Option) *JSONRPC { j := &JSONRPC{ - logger: zap.NewNop(), - handlers: newHandlers(), - ws: melody.New(), - events: events, - listenAddress: DefaultListenAddress, + logger: zap.NewNop(), + handlers: newHandlers(), + ws: melody.New(), + events: events, } for _, opt := range opts { @@ -95,54 +83,8 @@ func NewJSONRPC(events Events, opts ...Option) *JSONRPC { return j } -// Serve serves the JSON-RPC server -func (j *JSONRPC) Serve(ctx context.Context) error { - faucet := &http.Server{ - Addr: j.listenAddress, - Handler: j.setupRouter(), - ReadHeaderTimeout: 60 * time.Second, - } - - group, gCtx := errgroup.WithContext(ctx) - - group.Go(func() error { - defer j.logger.Info("JSON-RPC server shut down") - - ln, err := net.Listen("tcp", faucet.Addr) - if err != nil { - return err - } - - j.logger.Info( - "JSON-RPC server started", - zap.String("address", ln.Addr().String()), - ) - - if err := faucet.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) { - return err - } - - return nil - }) - - group.Go(func() error { - <-gCtx.Done() - - j.logger.Info("JSON-RPC server to be shut down") - - wsCtx, cancel := context.WithTimeout(context.Background(), time.Second*30) - defer cancel() - - return faucet.Shutdown(wsCtx) - }) - - return group.Wait() -} - -// setupRouter sets up the request router for the indexer service -func (j *JSONRPC) setupRouter() *chi.Mux { - mux := chi.NewRouter() - +// SetupRoutes sets up the request router for the indexer service +func (j *JSONRPC) SetupRoutes(mux *chi.Mux) *chi.Mux { // Set up the middlewares mux.Use(middleware.AllowContentType(jsonMimeType)) mux.Use(maxSizeMiddleware) diff --git a/serve/options.go b/serve/options.go index 9ec437be..043cb3a9 100644 --- a/serve/options.go +++ b/serve/options.go @@ -11,11 +11,3 @@ func WithLogger(logger *zap.Logger) Option { s.logger = logger } } - -// WithListenAddress sets the listen address -// for the JSON-RPC server -func WithListenAddress(address string) Option { - return func(s *JSONRPC) { - s.listenAddress = address - } -} diff --git a/serve/server.go b/serve/server.go new file mode 100644 index 00000000..7bede074 --- /dev/null +++ b/serve/server.go @@ -0,0 +1,70 @@ +package serve + +import ( + "context" + "errors" + "net" + "net/http" + "time" + + "go.uber.org/zap" + "golang.org/x/sync/errgroup" +) + +const ( + DefaultListenAddress = "0.0.0.0:8545" +) + +type HTTPServer struct { + h http.Handler + addr string + logger *zap.Logger +} + +func NewHTTPServer(h http.Handler, addr string, logger *zap.Logger) *HTTPServer { + return &HTTPServer{h: h, addr: addr, logger: logger} +} + +// Serve serves the JSON-RPC server +func (s *HTTPServer) Serve(ctx context.Context) error { + faucet := &http.Server{ + Addr: s.addr, + Handler: s.h, + ReadHeaderTimeout: 60 * time.Second, + } + + group, gCtx := errgroup.WithContext(ctx) + + group.Go(func() error { + defer s.logger.Info("HTTP server shut down") + + ln, err := net.Listen("tcp", faucet.Addr) + if err != nil { + return err + } + + s.logger.Info( + "HTTP server started", + zap.String("address", ln.Addr().String()), + ) + + if err := faucet.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) { + return err + } + + return nil + }) + + group.Go(func() error { + <-gCtx.Done() + + s.logger.Info("HTTP server to be shut down") + + wsCtx, cancel := context.WithTimeout(context.Background(), time.Second*30) + defer cancel() + + return faucet.Shutdown(wsCtx) + }) + + return group.Wait() +} diff --git a/storage/encode.go b/storage/encode.go index 6ccf5357..54948d7c 100644 --- a/storage/encode.go +++ b/storage/encode.go @@ -1,24 +1,358 @@ package storage import ( + "bytes" "encoding/binary" "fmt" + "math" + "unsafe" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" ) -// encodeInt64 encodes an int64 value into little endian -func encodeInt64(value int64) []byte { - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, uint64(value)) +const ( + bytesMarker byte = 0x12 + bytesDescMarker = bytesMarker + 1 - return b + // IntMin is chosen such that the range of int tags does not overlap the + // ascii character set that is frequently used in testing. + IntMin = 0x80 // 128 + intMaxWidth = 8 + intZero = IntMin + intMaxWidth // 136 + intSmall = IntMax - intZero - intMaxWidth // 109 + // IntMax is the maximum int tag value. + IntMax = 0xfd // 253 + + // -> \x00\x01 + // \x00 -> \x00\xff + escape byte = 0x00 + escapedTerm byte = 0x01 + escapedJSONObjectKeyTerm byte = 0x02 + escapedJSONArray byte = 0x03 + escaped00 byte = 0xff + escapedFF byte = 0x00 +) + +type escapes struct { + escape byte + escapedTerm byte + escaped00 byte + escapedFF byte + marker byte +} + +var ( + ascendingBytesEscapes = escapes{escape, escapedTerm, escaped00, escapedFF, bytesMarker} + descendingBytesEscapes = escapes{^escape, ^escapedTerm, ^escaped00, ^escapedFF, bytesDescMarker} +) + +// EncodeUint32Ascending encodes the uint32 value using a big-endian 4 byte +// representation. The bytes are appended to the supplied buffer and +// the final buffer is returned. +func EncodeUint32Ascending(b []byte, v uint32) []byte { + return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) +} + +// EncodeUint32Descending encodes the uint32 value so that it sorts in +// reverse order, from largest to smallest. +func EncodeUint32Descending(b []byte, v uint32) []byte { + return EncodeUint32Ascending(b, ^v) +} + +// DecodeUint32Ascending decodes a uint32 from the input buffer, treating +// the input as a big-endian 4 byte uint32 representation. The remainder +// of the input buffer and the decoded uint32 are returned. +func DecodeUint32Ascending(b []byte) ([]byte, uint32, error) { + if len(b) < 4 { + return nil, 0, fmt.Errorf("insufficient bytes to decode uint32 int value") + } + v := binary.BigEndian.Uint32(b) + return b[4:], v, nil +} + +// DecodeUint32Descending decodes a uint32 value which was encoded +// using EncodeUint32Descending. +func DecodeUint32Descending(b []byte) ([]byte, uint32, error) { + leftover, v, err := DecodeUint32Ascending(b) + return leftover, ^v, err +} + +// EncodeVarintAscending encodes the int64 value using a variable length +// (length-prefixed) representation. The length is encoded as a single +// byte. If the value to be encoded is negative the length is encoded +// as 8-numBytes. If the value is positive it is encoded as +// 8+numBytes. The encoded bytes are appended to the supplied buffer +// and the final buffer is returned. +func EncodeVarintAscending(b []byte, v int64) []byte { + if v < 0 { + switch { + case v >= -0xff: + return append(b, IntMin+7, byte(v)) + case v >= -0xffff: + return append(b, IntMin+6, byte(v>>8), byte(v)) + case v >= -0xffffff: + return append(b, IntMin+5, byte(v>>16), byte(v>>8), byte(v)) + case v >= -0xffffffff: + return append(b, IntMin+4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + case v >= -0xffffffffff: + return append(b, IntMin+3, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), + byte(v)) + case v >= -0xffffffffffff: + return append(b, IntMin+2, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), + byte(v>>8), byte(v)) + case v >= -0xffffffffffffff: + return append(b, IntMin+1, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), + byte(v>>16), byte(v>>8), byte(v)) + default: + return append(b, IntMin, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), + byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + } + } + return EncodeUvarintAscending(b, uint64(v)) +} + +// EncodeVarintDescending encodes the int64 value so that it sorts in reverse +// order, from largest to smallest. +func EncodeVarintDescending(b []byte, v int64) []byte { + return EncodeVarintAscending(b, ^v) +} + +// EncodeUvarintAscending encodes the uint64 value using a variable length +// (length-prefixed) representation. The length is encoded as a single +// byte indicating the number of encoded bytes (-8) to follow. See +// EncodeVarintAscending for rationale. The encoded bytes are appended to the +// supplied buffer and the final buffer is returned. +func EncodeUvarintAscending(b []byte, v uint64) []byte { + switch { + case v <= intSmall: + return append(b, intZero+byte(v)) + case v <= 0xff: + return append(b, IntMax-7, byte(v)) + case v <= 0xffff: + return append(b, IntMax-6, byte(v>>8), byte(v)) + case v <= 0xffffff: + return append(b, IntMax-5, byte(v>>16), byte(v>>8), byte(v)) + case v <= 0xffffffff: + return append(b, IntMax-4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + case v <= 0xffffffffff: + return append(b, IntMax-3, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), + byte(v)) + case v <= 0xffffffffffff: + return append(b, IntMax-2, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), + byte(v>>8), byte(v)) + case v <= 0xffffffffffffff: + return append(b, IntMax-1, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), + byte(v>>16), byte(v>>8), byte(v)) + default: + return append(b, IntMax, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), + byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + } +} + +// DecodeVarintAscending decodes a value encoded by EncodeVarintAscending. +func DecodeVarintAscending(b []byte) ([]byte, int64, error) { + if len(b) == 0 { + return nil, 0, fmt.Errorf("insufficient bytes to decode varint value") + } + length := int(b[0]) - intZero + if length < 0 { + length = -length + remB := b[1:] + if len(remB) < length { + return nil, 0, fmt.Errorf("insufficient bytes to decode varint value: %q", remB) + } + var v int64 + // Use the ones-complement of each encoded byte in order to build + // up a positive number, then take the ones-complement again to + // arrive at our negative value. + for _, t := range remB[:length] { + v = (v << 8) | int64(^t) + } + return remB[length:], ^v, nil + } + + remB, v, err := DecodeUvarintAscending(b) + if err != nil { + return remB, 0, err + } + if v > math.MaxInt64 { + return nil, 0, fmt.Errorf("varint %d overflows int64", v) + } + return remB, int64(v), nil +} + +// DecodeUvarintAscending decodes a uint64 encoded uint64 from the input +// buffer. The remainder of the input buffer and the decoded uint64 +// are returned. +func DecodeUvarintAscending(b []byte) ([]byte, uint64, error) { + if len(b) == 0 { + return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value") + } + length := int(b[0]) - intZero + b = b[1:] // skip length byte + if length <= intSmall { + return b, uint64(length), nil + } + length -= intSmall + if length < 0 || length > 8 { + return nil, 0, fmt.Errorf("invalid uvarint length of %d", length) + } else if len(b) < length { + return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value: %q", b) + } + var v uint64 + // It is faster to range over the elements in a slice than to index + // into the slice on each loop iteration. + for _, t := range b[:length] { + v = (v << 8) | uint64(t) + } + return b[length:], v, nil +} + +// DecodeVarintDescending decodes a int64 value which was encoded +// using EncodeVarintDescending. +func DecodeVarintDescending(b []byte) ([]byte, int64, error) { + leftover, v, err := DecodeVarintAscending(b) + return leftover, ^v, err +} + +// EncodeStringAscending encodes the string value using an escape-based encoding. See +// EncodeBytes for details. The encoded bytes are append to the supplied buffer +// and the resulting buffer is returned. +func EncodeStringAscending(b []byte, s string) []byte { + return encodeStringAscendingWithTerminatorAndPrefix(b, s, ascendingBytesEscapes.escapedTerm, bytesMarker) } -// decodeInt64 decodes an int64 value from little endian -func decodeInt64(value []byte) int64 { - return int64(binary.LittleEndian.Uint64(value)) +// encodeStringAscendingWithTerminatorAndPrefix encodes the string value using an escape-based encoding. See +// EncodeBytes for details. The encoded bytes are append to the supplied buffer +// and the resulting buffer is returned. We can also pass a terminator byte to be used with +// JSON key encoding. +func encodeStringAscendingWithTerminatorAndPrefix( + b []byte, s string, terminator byte, prefix byte, +) []byte { + unsafeString := UnsafeConvertStringToBytes(s) + return encodeBytesAscendingWithTerminatorAndPrefix(b, unsafeString, terminator, prefix) +} + +// encodeBytesAscendingWithTerminatorAndPrefix encodes the []byte value using an escape-based +// encoding. The encoded value is terminated with the sequence +// "\x00\terminator". The encoded bytes are append to the supplied buffer +// and the resulting buffer is returned. The terminator allows us to pass +// different terminators for things such as JSON key encoding. +func encodeBytesAscendingWithTerminatorAndPrefix( + b []byte, data []byte, terminator byte, prefix byte, +) []byte { + b = append(b, prefix) + return encodeBytesAscendingWithTerminator(b, data, terminator) +} + +// encodeBytesAscendingWithTerminator encodes the []byte value using an escape-based +// encoding. The encoded value is terminated with the sequence +// "\x00\terminator". The encoded bytes are append to the supplied buffer +// and the resulting buffer is returned. The terminator allows us to pass +// different terminators for things such as JSON key encoding. +func encodeBytesAscendingWithTerminator(b []byte, data []byte, terminator byte) []byte { + bs := encodeBytesAscendingWithoutTerminatorOrPrefix(b, data) + return append(bs, escape, terminator) +} + +// encodeBytesAscendingWithoutTerminatorOrPrefix encodes the []byte value using an escape-based +// encoding. +func encodeBytesAscendingWithoutTerminatorOrPrefix(b []byte, data []byte) []byte { + for { + // IndexByte is implemented by the go runtime in assembly and is + // much faster than looping over the bytes in the slice. + i := bytes.IndexByte(data, escape) + if i == -1 { + break + } + b = append(b, data[:i]...) + b = append(b, escape, escaped00) + data = data[i+1:] + } + return append(b, data...) +} + +// UnsafeConvertStringToBytes converts a string to a byte array to be used with +// string encoding functions. Note that the output byte array should not be +// modified if the input string is expected to be used again - doing so could +// violate Go semantics. +func UnsafeConvertStringToBytes(s string) []byte { + // unsafe.StringData output is unspecified for empty string input so always + // return nil. + if len(s) == 0 { + return nil + } + return unsafe.Slice(unsafe.StringData(s), len(s)) +} + +// DecodeUnsafeStringAscending decodes a string value from the input buffer which was +// encoded using EncodeString or EncodeBytes. The r []byte is used as a +// temporary buffer in order to avoid memory allocations. The remainder of the +// input buffer and the decoded string are returned. Note that the returned +// string may share storage with the input buffer. +func DecodeUnsafeStringAscending(b []byte, r []byte) ([]byte, string, error) { + b, r, err := DecodeBytesAscending(b, r) + return b, UnsafeConvertBytesToString(r), err +} + +// UnsafeConvertBytesToString performs an unsafe conversion from a []byte to a +// string. The returned string will share the underlying memory with the +// []byte which thus allows the string to be mutable through the []byte. We're +// careful to use this method only in situations in which the []byte will not +// be modified. +func UnsafeConvertBytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// DecodeBytesAscending decodes a []byte value from the input buffer +// which was encoded using EncodeBytesAscending. The decoded bytes +// are appended to r. The remainder of the input buffer and the +// decoded []byte are returned. +func DecodeBytesAscending(b []byte, r []byte) ([]byte, []byte, error) { + return decodeBytesInternal(b, r, ascendingBytesEscapes, true /* expectMarker */, false /* deepCopy */) +} + +// decodeBytesInternal decodes an encoded []byte value from b and appends it to +// r. The remainder of b and the decoded []byte are returned. If deepCopy is +// true, then the decoded []byte will be deep copied from b and there will no +// aliasing of the same memory. +func decodeBytesInternal( + b []byte, r []byte, e escapes, expectMarker bool, deepCopy bool, +) ([]byte, []byte, error) { + if expectMarker { + if len(b) == 0 || b[0] != e.marker { + return nil, nil, fmt.Errorf("did not find marker %#x in buffer %#x", e.marker, b) + } + b = b[1:] + } + + for { + i := bytes.IndexByte(b, e.escape) + if i == -1 { + return nil, nil, fmt.Errorf("did not find terminator %#x in buffer %#x", e.escape, b) + } + if i+1 >= len(b) { + return nil, nil, fmt.Errorf("malformed escape in buffer %#x", b) + } + v := b[i+1] + if v == e.escapedTerm { + if r == nil && !deepCopy { + r = b[:i] + } else { + r = append(r, b[:i]...) + } + return b[i+2:], r, nil + } + + if v != e.escaped00 { + return nil, nil, fmt.Errorf("unknown escape sequence: %#x %#x", e.escape, v) + } + + r = append(r, b[:i]...) + r = append(r, e.escapedFF) + b = b[i+2:] + } } // encodeBlock encodes the block in Amino binary diff --git a/storage/keys.go b/storage/keys.go deleted file mode 100644 index 8cffaf75..00000000 --- a/storage/keys.go +++ /dev/null @@ -1,13 +0,0 @@ -package storage - -// latestHeightKey is the quick lookup key -// for the latest height saved in the DB -var latestHeightKey = []byte("LATEST_HEIGHT") - -var ( - // blockPrefix is the prefix for each block saved - blockPrefix = []byte("BLOCK_") - - // txResultKey is the prefix for each tx result saved - txResultKey = []byte("TX_RESULT_") -) diff --git a/storage/pebble.go b/storage/pebble.go index d651138e..b3ea59ac 100644 --- a/storage/pebble.go +++ b/storage/pebble.go @@ -3,13 +3,42 @@ package storage import ( "errors" "fmt" + "math" "github.com/cockroachdb/pebble" "github.com/gnolang/gno/tm2/pkg/bft/types" + "go.uber.org/multierr" storageErrors "github.com/gnolang/tx-indexer/storage/errors" ) +const ( + // keyLatestHeight is the quick lookup key + // for the latest height saved in the DB + keyLatestHeight = "/meta/lh" + + // keyBlocks is the key for each block saved. They are stored by height + prefixKeyBlocks = "/data/blocks/" + + // keyTxs is the prefix for each transaction saved. + prefixKeyTxs = "/data/txs/" +) + +func keyTx(blockNum int64, txIndex uint32) []byte { + var key []byte + key = EncodeStringAscending(key, prefixKeyTxs) + key = EncodeVarintAscending(key, blockNum) + key = EncodeUint32Ascending(key, txIndex) + return key +} + +func keyBlock(blockNum int64) []byte { + var key []byte + key = EncodeStringAscending(key, prefixKeyBlocks) + key = EncodeVarintAscending(key, blockNum) + return key +} + var _ Storage = &Pebble{} // Pebble is the instance of an embedded storage @@ -34,7 +63,7 @@ func NewPebble(path string) (*Pebble, error) { // GetLatestHeight fetches the latest saved height from storage func (s *Pebble) GetLatestHeight() (int64, error) { - height, c, err := s.db.Get(latestHeightKey) + height, c, err := s.db.Get([]byte(keyLatestHeight)) if errors.Is(err, pebble.ErrNotFound) { return 0, storageErrors.ErrNotFound } @@ -45,12 +74,13 @@ func (s *Pebble) GetLatestHeight() (int64, error) { defer c.Close() - return decodeInt64(height), nil + _, val, err := DecodeVarintAscending(height) + return val, err } // GetBlock fetches the specified block from storage, if any func (s *Pebble) GetBlock(blockNum int64) (*types.Block, error) { - block, c, err := s.db.Get(append(blockPrefix, encodeInt64(blockNum)...)) + block, c, err := s.db.Get(keyBlock(blockNum)) if errors.Is(err, pebble.ErrNotFound) { return nil, storageErrors.ErrNotFound } @@ -65,8 +95,8 @@ func (s *Pebble) GetBlock(blockNum int64) (*types.Block, error) { } // GetTx fetches the specified tx result from storage, if any -func (s *Pebble) GetTx(txHash []byte) (*types.TxResult, error) { - tx, c, err := s.db.Get(append(txResultKey, txHash...)) +func (s *Pebble) GetTx(blockNum int64, index uint32) (*types.TxResult, error) { + tx, c, err := s.db.Get(keyTx(blockNum, index)) if errors.Is(err, pebble.ErrNotFound) { return nil, storageErrors.ErrNotFound } @@ -80,6 +110,53 @@ func (s *Pebble) GetTx(txHash []byte) (*types.TxResult, error) { return decodeTx(tx) } +func (s *Pebble) BlockIterator(fromBlockNum, toBlockNum int64) (Iterator[*types.Block], error) { + fromKey := keyBlock(fromBlockNum) + + if toBlockNum == 0 { + toBlockNum = math.MaxInt64 + } + toKey := keyBlock(toBlockNum) + + snap := s.db.NewSnapshot() + + it, err := snap.NewIter(&pebble.IterOptions{ + LowerBound: fromKey, + UpperBound: toKey, + }) + if err != nil { + return nil, multierr.Append(snap.Close(), err) + } + + return &PebbleBlockIter{i: it, s: snap}, nil + +} + +func (s *Pebble) TxIterator(fromBlockNum, toBlockNum int64, fromTxIndex, toTxIndex uint32) (Iterator[*types.TxResult], error) { + fromKey := keyTx(fromBlockNum, fromTxIndex) + + if toBlockNum == 0 { + toBlockNum = math.MaxInt64 + } + + if toTxIndex == 0 { + toTxIndex = math.MaxUint32 + } + + toKey := keyTx(toBlockNum, toTxIndex) + + snap := s.db.NewSnapshot() + it, err := snap.NewIter(&pebble.IterOptions{ + LowerBound: fromKey, + UpperBound: toKey, + }) + if err != nil { + return nil, multierr.Append(snap.Close(), err) + } + + return &PebbleTxIter{i: it, s: snap, fromIndex: fromTxIndex, toIndex: toTxIndex}, nil +} + func (s *Pebble) WriteBatch() Batch { return &PebbleBatch{ b: s.db.NewBatch(), @@ -90,6 +167,103 @@ func (s *Pebble) Close() error { return s.db.Close() } +var _ Iterator[*types.Block] = &PebbleBlockIter{} + +type PebbleBlockIter struct { + i *pebble.Iterator + s *pebble.Snapshot + + init bool +} + +func (pi *PebbleBlockIter) Next() bool { + if !pi.init { + pi.init = true + return pi.i.First() + } + + return pi.i.Valid() && pi.i.Next() +} + +func (pi *PebbleBlockIter) Error() error { + return pi.i.Error() +} + +func (pi *PebbleBlockIter) Value() (*types.Block, error) { + return decodeBlock(pi.i.Value()) +} + +func (pi *PebbleBlockIter) Close() error { + return multierr.Append(pi.i.Close(), pi.s.Close()) +} + +var _ Iterator[*types.TxResult] = &PebbleTxIter{} + +type PebbleTxIter struct { + i *pebble.Iterator + s *pebble.Snapshot + + fromIndex, toIndex uint32 + + init bool + nextError error +} + +func (pi *PebbleTxIter) Next() bool { + for { + if !pi.init { + pi.init = true + if !pi.i.First() { + return false + } + } + + if !pi.i.Valid() { + return false + } + if !pi.i.Next() { + return false + } + + var buf []byte + key, _, err := DecodeUnsafeStringAscending(pi.i.Key(), buf) + if err != nil { + pi.nextError = err + return false + } + key, _, err = DecodeVarintAscending(key) + if err != nil { + pi.nextError = err + return false + } + _, txIdx, err := DecodeUint32Ascending(key) + if err != nil { + pi.nextError = err + return false + } + + if txIdx >= pi.fromIndex && txIdx < pi.toIndex { + return true + } + } +} + +func (pi *PebbleTxIter) Error() error { + if pi.nextError != nil { + return pi.nextError + } + + return pi.i.Error() +} + +func (pi *PebbleTxIter) Value() (*types.TxResult, error) { + return decodeTx(pi.i.Value()) +} + +func (pi *PebbleTxIter) Close() error { + return multierr.Append(pi.i.Close(), pi.s.Close()) +} + var _ Batch = &PebbleBatch{} type PebbleBatch struct { @@ -97,7 +271,9 @@ type PebbleBatch struct { } func (b *PebbleBatch) SetLatestHeight(h int64) error { - return b.b.Set(latestHeightKey, encodeInt64(h), pebble.NoSync) + var val []byte + val = EncodeVarintAscending(val, h) + return b.b.Set([]byte(keyLatestHeight), val, pebble.NoSync) } func (b *PebbleBatch) SetBlock(block *types.Block) error { @@ -106,8 +282,10 @@ func (b *PebbleBatch) SetBlock(block *types.Block) error { return err } + key := keyBlock(block.Height) + return b.b.Set( - append(blockPrefix, encodeInt64(block.Height)...), + key, eb, pebble.NoSync, ) @@ -119,8 +297,10 @@ func (b *PebbleBatch) SetTx(tx *types.TxResult) error { return err } + key := keyTx(tx.Height, tx.Index) + return b.b.Set( - append(txResultKey, tx.Tx.Hash()...), + key, encodedTx, pebble.NoSync, ) diff --git a/storage/pebble_test.go b/storage/pebble_test.go index 5242d0a1..99a355a4 100644 --- a/storage/pebble_test.go +++ b/storage/pebble_test.go @@ -101,12 +101,93 @@ func TestStorage_Tx(t *testing.T) { require.NoError(t, wb.Commit()) for _, tx := range txs { - savedTx, err := s.GetTx(tx.Tx.Hash()) + savedTx, err := s.GetTx(tx.Height, tx.Index) require.NoError(t, err) assert.Equal(t, tx, savedTx) } } +func TestStorageIters(t *testing.T) { + t.Parallel() + + s, err := NewPebble(t.TempDir()) + require.NoError(t, err) + + txs := generateRandomTxs(t, 100) + blocks := generateRandomBlocks(t, 100) + + wb := s.WriteBatch() + + // Save the txs and fetch them + for i, tx := range txs { + assert.NoError(t, wb.SetTx(tx)) + assert.NoError(t, wb.SetBlock(blocks[i])) + } + + require.NoError(t, wb.Commit()) + + it, err := s.TxIterator(0, 0, 0, 3) + require.NoError(t, err) + + txCount := 0 + for { + if !it.Next() { + require.NoError(t, it.Error()) + break + } + + _, err := it.Value() + require.NoError(t, err) + require.NoError(t, it.Error()) + + txCount++ + } + + require.Equal(t, 2, txCount) + + defer require.NoError(t, it.Close()) + + it2, err := s.BlockIterator(0, 2) + require.NoError(t, err) + + blockCount := 0 + for { + if !it2.Next() { + require.NoError(t, it2.Error()) + break + } + + _, err := it2.Value() + require.NoError(t, err) + + blockCount++ + } + + require.Equal(t, 2, blockCount) + + defer require.NoError(t, it2.Close()) + + it, err = s.TxIterator(0, 0, 20000, 30000) + require.NoError(t, err) + + txCount = 0 + for { + if !it.Next() { + require.NoError(t, it.Error()) + break + } + + _, err := it.Value() + require.NoError(t, err) + require.NoError(t, it.Error()) + + txCount++ + } + + require.Equal(t, 0, txCount) + +} + // generateRandomBlocks generates dummy blocks func generateRandomBlocks(t *testing.T, count int) []*types.Block { t.Helper() diff --git a/storage/types.go b/storage/types.go index ead829be..51f9fe2f 100644 --- a/storage/types.go +++ b/storage/types.go @@ -22,8 +22,21 @@ type Reader interface { // GetBlock fetches the block by its number GetBlock(int64) (*types.Block, error) - // GetTx fetches the tx using its hash - GetTx([]byte) (*types.TxResult, error) + // GetTx fetches the tx using the block height and the transaction index + GetTx(blockNum int64, index uint32) (*types.TxResult, error) + + // BlockIterator iterates over Blocks, limiting the results to be between the provided block numbers + BlockIterator(fromBlockNum, toBlockNum int64) (Iterator[*types.Block], error) + + // TxIterator iterates over transactions, limiting the results to be between the provided block numbers and transaction indexes + TxIterator(fromBlockNum, toBlockNum int64, fromTxIndex, toTxIndex uint32) (Iterator[*types.TxResult], error) +} + +type Iterator[T any] interface { + io.Closer + Next() bool + Error() error + Value() (T, error) } // Writer defines the transaction storage interface for write methods diff --git a/tools.go b/tools.go new file mode 100644 index 00000000..fcdeac47 --- /dev/null +++ b/tools.go @@ -0,0 +1,8 @@ +//go:build tools +// +build tools + +package tools + +import ( + _ "github.com/99designs/gqlgen" +) From 44ce4a0af03728b4a5b5df172a6a87ca7662caeb Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 14 Feb 2024 12:57:14 +0100 Subject: [PATCH 02/13] Linter Signed-off-by: Antonio Navarro Perez --- internal/mock/storage.go | 12 +++++++--- serve/graph/resolver.go | 9 ++++---- serve/handlers/tx/tx_test.go | 1 + storage/encode.go | 43 ++++++++++++++++++++++++++++-------- storage/pebble.go | 28 ++++++++++++++++++----- storage/pebble_test.go | 15 ++++++++----- storage/types.go | 3 ++- 7 files changed, 84 insertions(+), 27 deletions(-) diff --git a/internal/mock/storage.go b/internal/mock/storage.go index c5dd1468..570a1958 100644 --- a/internal/mock/storage.go +++ b/internal/mock/storage.go @@ -42,12 +42,18 @@ func (m *Storage) GetTx(blockNum int64, index uint32) (*types.TxResult, error) { } // BlockIterator iterates over Blocks, limiting the results to be between the provided block numbers -func (m *Storage) BlockIterator(fromBlockNum int64, toBlockNum int64) (storage.Iterator[*types.Block], error) { +func (m *Storage) BlockIterator(fromBlockNum, toBlockNum int64) (storage.Iterator[*types.Block], error) { panic("not implemented") // TODO: Implement } -// TxIterator iterates over transactions, limiting the results to be between the provided block numbers and transaction indexes -func (m *Storage) TxIterator(fromBlockNum int64, toBlockNum int64, fromTxIndex uint32, toTxIndex uint32) (storage.Iterator[*types.TxResult], error) { +// TxIterator iterates over transactions, limiting the results to be between the provided block numbers +// and transaction indexes +func (m *Storage) TxIterator( + fromBlockNum, + toBlockNum int64, + fromTxIndex, + toTxIndex uint32, +) (storage.Iterator[*types.TxResult], error) { panic("not implemented") // TODO: Implement } diff --git a/serve/graph/resolver.go b/serve/graph/resolver.go index 3dc7da8e..0a2c08cc 100644 --- a/serve/graph/resolver.go +++ b/serve/graph/resolver.go @@ -17,18 +17,19 @@ const maxElementsPerQuery = 10000 func dereferenceInt(i *int) int { if i == nil { return 0 - } else { - return *i } + + return *i } func dereferenceTime(i *time.Time) time.Time { if i == nil { var t time.Time + return t - } else { - return *i } + + return *i } type Resolver struct { diff --git a/serve/handlers/tx/tx_test.go b/serve/handlers/tx/tx_test.go index 2e1c2980..2c9359d4 100644 --- a/serve/handlers/tx/tx_test.go +++ b/serve/handlers/tx/tx_test.go @@ -121,6 +121,7 @@ func TestGetBlock_Handler(t *testing.T) { getTxFn: func(bn int64, ti uint32) (*types.TxResult, error) { require.Equal(t, blockNum, bn) require.Equal(t, txIndex, ti) + return txResult, nil }, } diff --git a/storage/encode.go b/storage/encode.go index 54948d7c..28c6d918 100644 --- a/storage/encode.go +++ b/storage/encode.go @@ -42,10 +42,7 @@ type escapes struct { marker byte } -var ( - ascendingBytesEscapes = escapes{escape, escapedTerm, escaped00, escapedFF, bytesMarker} - descendingBytesEscapes = escapes{^escape, ^escapedTerm, ^escaped00, ^escapedFF, bytesDescMarker} -) +var ascendingBytesEscapes = escapes{escape, escapedTerm, escaped00, escapedFF, bytesMarker} // EncodeUint32Ascending encodes the uint32 value using a big-endian 4 byte // representation. The bytes are appended to the supplied buffer and @@ -67,7 +64,9 @@ func DecodeUint32Ascending(b []byte) ([]byte, uint32, error) { if len(b) < 4 { return nil, 0, fmt.Errorf("insufficient bytes to decode uint32 int value") } + v := binary.BigEndian.Uint32(b) + return b[4:], v, nil } @@ -75,6 +74,7 @@ func DecodeUint32Ascending(b []byte) ([]byte, uint32, error) { // using EncodeUint32Descending. func DecodeUint32Descending(b []byte) ([]byte, uint32, error) { leftover, v, err := DecodeUint32Ascending(b) + return leftover, ^v, err } @@ -109,6 +109,7 @@ func EncodeVarintAscending(b []byte, v int64) []byte { byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) } } + return EncodeUvarintAscending(b, uint64(v)) } @@ -155,13 +156,16 @@ func DecodeVarintAscending(b []byte) ([]byte, int64, error) { if len(b) == 0 { return nil, 0, fmt.Errorf("insufficient bytes to decode varint value") } + length := int(b[0]) - intZero if length < 0 { length = -length + remB := b[1:] if len(remB) < length { return nil, 0, fmt.Errorf("insufficient bytes to decode varint value: %q", remB) } + var v int64 // Use the ones-complement of each encoded byte in order to build // up a positive number, then take the ones-complement again to @@ -169,6 +173,7 @@ func DecodeVarintAscending(b []byte) ([]byte, int64, error) { for _, t := range remB[:length] { v = (v << 8) | int64(^t) } + return remB[length:], ^v, nil } @@ -176,9 +181,11 @@ func DecodeVarintAscending(b []byte) ([]byte, int64, error) { if err != nil { return remB, 0, err } + if v > math.MaxInt64 { return nil, 0, fmt.Errorf("varint %d overflows int64", v) } + return remB, int64(v), nil } @@ -189,23 +196,28 @@ func DecodeUvarintAscending(b []byte) ([]byte, uint64, error) { if len(b) == 0 { return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value") } + length := int(b[0]) - intZero + b = b[1:] // skip length byte if length <= intSmall { return b, uint64(length), nil } + length -= intSmall if length < 0 || length > 8 { return nil, 0, fmt.Errorf("invalid uvarint length of %d", length) } else if len(b) < length { return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value: %q", b) } + var v uint64 // It is faster to range over the elements in a slice than to index // into the slice on each loop iteration. for _, t := range b[:length] { v = (v << 8) | uint64(t) } + return b[length:], v, nil } @@ -213,6 +225,7 @@ func DecodeUvarintAscending(b []byte) ([]byte, uint64, error) { // using EncodeVarintDescending. func DecodeVarintDescending(b []byte) ([]byte, int64, error) { leftover, v, err := DecodeVarintAscending(b) + return leftover, ^v, err } @@ -231,6 +244,7 @@ func encodeStringAscendingWithTerminatorAndPrefix( b []byte, s string, terminator byte, prefix byte, ) []byte { unsafeString := UnsafeConvertStringToBytes(s) + return encodeBytesAscendingWithTerminatorAndPrefix(b, unsafeString, terminator, prefix) } @@ -243,6 +257,7 @@ func encodeBytesAscendingWithTerminatorAndPrefix( b []byte, data []byte, terminator byte, prefix byte, ) []byte { b = append(b, prefix) + return encodeBytesAscendingWithTerminator(b, data, terminator) } @@ -251,14 +266,15 @@ func encodeBytesAscendingWithTerminatorAndPrefix( // "\x00\terminator". The encoded bytes are append to the supplied buffer // and the resulting buffer is returned. The terminator allows us to pass // different terminators for things such as JSON key encoding. -func encodeBytesAscendingWithTerminator(b []byte, data []byte, terminator byte) []byte { +func encodeBytesAscendingWithTerminator(b, data []byte, terminator byte) []byte { bs := encodeBytesAscendingWithoutTerminatorOrPrefix(b, data) + return append(bs, escape, terminator) } // encodeBytesAscendingWithoutTerminatorOrPrefix encodes the []byte value using an escape-based // encoding. -func encodeBytesAscendingWithoutTerminatorOrPrefix(b []byte, data []byte) []byte { +func encodeBytesAscendingWithoutTerminatorOrPrefix(b, data []byte) []byte { for { // IndexByte is implemented by the go runtime in assembly and is // much faster than looping over the bytes in the slice. @@ -266,10 +282,13 @@ func encodeBytesAscendingWithoutTerminatorOrPrefix(b []byte, data []byte) []byte if i == -1 { break } + b = append(b, data[:i]...) b = append(b, escape, escaped00) + data = data[i+1:] } + return append(b, data...) } @@ -280,9 +299,10 @@ func encodeBytesAscendingWithoutTerminatorOrPrefix(b []byte, data []byte) []byte func UnsafeConvertStringToBytes(s string) []byte { // unsafe.StringData output is unspecified for empty string input so always // return nil. - if len(s) == 0 { + if s == "" { return nil } + return unsafe.Slice(unsafe.StringData(s), len(s)) } @@ -291,8 +311,9 @@ func UnsafeConvertStringToBytes(s string) []byte { // temporary buffer in order to avoid memory allocations. The remainder of the // input buffer and the decoded string are returned. Note that the returned // string may share storage with the input buffer. -func DecodeUnsafeStringAscending(b []byte, r []byte) ([]byte, string, error) { +func DecodeUnsafeStringAscending(b, r []byte) ([]byte, string, error) { b, r, err := DecodeBytesAscending(b, r) + return b, UnsafeConvertBytesToString(r), err } @@ -309,7 +330,7 @@ func UnsafeConvertBytesToString(b []byte) string { // which was encoded using EncodeBytesAscending. The decoded bytes // are appended to r. The remainder of the input buffer and the // decoded []byte are returned. -func DecodeBytesAscending(b []byte, r []byte) ([]byte, []byte, error) { +func DecodeBytesAscending(b, r []byte) ([]byte, []byte, error) { return decodeBytesInternal(b, r, ascendingBytesEscapes, true /* expectMarker */, false /* deepCopy */) } @@ -324,6 +345,7 @@ func decodeBytesInternal( if len(b) == 0 || b[0] != e.marker { return nil, nil, fmt.Errorf("did not find marker %#x in buffer %#x", e.marker, b) } + b = b[1:] } @@ -332,9 +354,11 @@ func decodeBytesInternal( if i == -1 { return nil, nil, fmt.Errorf("did not find terminator %#x in buffer %#x", e.escape, b) } + if i+1 >= len(b) { return nil, nil, fmt.Errorf("malformed escape in buffer %#x", b) } + v := b[i+1] if v == e.escapedTerm { if r == nil && !deepCopy { @@ -342,6 +366,7 @@ func decodeBytesInternal( } else { r = append(r, b[:i]...) } + return b[i+2:], r, nil } diff --git a/storage/pebble.go b/storage/pebble.go index b3ea59ac..a9da9b1d 100644 --- a/storage/pebble.go +++ b/storage/pebble.go @@ -29,6 +29,7 @@ func keyTx(blockNum int64, txIndex uint32) []byte { key = EncodeStringAscending(key, prefixKeyTxs) key = EncodeVarintAscending(key, blockNum) key = EncodeUint32Ascending(key, txIndex) + return key } @@ -36,6 +37,7 @@ func keyBlock(blockNum int64) []byte { var key []byte key = EncodeStringAscending(key, prefixKeyBlocks) key = EncodeVarintAscending(key, blockNum) + return key } @@ -75,6 +77,7 @@ func (s *Pebble) GetLatestHeight() (int64, error) { defer c.Close() _, val, err := DecodeVarintAscending(height) + return val, err } @@ -116,6 +119,7 @@ func (s *Pebble) BlockIterator(fromBlockNum, toBlockNum int64) (Iterator[*types. if toBlockNum == 0 { toBlockNum = math.MaxInt64 } + toKey := keyBlock(toBlockNum) snap := s.db.NewSnapshot() @@ -129,10 +133,14 @@ func (s *Pebble) BlockIterator(fromBlockNum, toBlockNum int64) (Iterator[*types. } return &PebbleBlockIter{i: it, s: snap}, nil - } -func (s *Pebble) TxIterator(fromBlockNum, toBlockNum int64, fromTxIndex, toTxIndex uint32) (Iterator[*types.TxResult], error) { +func (s *Pebble) TxIterator( + fromBlockNum, + toBlockNum int64, + fromTxIndex, + toTxIndex uint32, +) (Iterator[*types.TxResult], error) { fromKey := keyTx(fromBlockNum, fromTxIndex) if toBlockNum == 0 { @@ -146,6 +154,7 @@ func (s *Pebble) TxIterator(fromBlockNum, toBlockNum int64, fromTxIndex, toTxInd toKey := keyTx(toBlockNum, toTxIndex) snap := s.db.NewSnapshot() + it, err := snap.NewIter(&pebble.IterOptions{ LowerBound: fromKey, UpperBound: toKey, @@ -179,6 +188,7 @@ type PebbleBlockIter struct { func (pi *PebbleBlockIter) Next() bool { if !pi.init { pi.init = true + return pi.i.First() } @@ -200,13 +210,13 @@ func (pi *PebbleBlockIter) Close() error { var _ Iterator[*types.TxResult] = &PebbleTxIter{} type PebbleTxIter struct { - i *pebble.Iterator - s *pebble.Snapshot - fromIndex, toIndex uint32 init bool nextError error + + i *pebble.Iterator + s *pebble.Snapshot } func (pi *PebbleTxIter) Next() bool { @@ -221,24 +231,31 @@ func (pi *PebbleTxIter) Next() bool { if !pi.i.Valid() { return false } + if !pi.i.Next() { return false } var buf []byte + key, _, err := DecodeUnsafeStringAscending(pi.i.Key(), buf) if err != nil { pi.nextError = err + return false } + key, _, err = DecodeVarintAscending(key) if err != nil { pi.nextError = err + return false } + _, txIdx, err := DecodeUint32Ascending(key) if err != nil { pi.nextError = err + return false } @@ -273,6 +290,7 @@ type PebbleBatch struct { func (b *PebbleBatch) SetLatestHeight(h int64) error { var val []byte val = EncodeVarintAscending(val, h) + return b.b.Set([]byte(keyLatestHeight), val, pebble.NoSync) } diff --git a/storage/pebble_test.go b/storage/pebble_test.go index 99a355a4..370c0c6b 100644 --- a/storage/pebble_test.go +++ b/storage/pebble_test.go @@ -130,14 +130,16 @@ func TestStorageIters(t *testing.T) { require.NoError(t, err) txCount := 0 + for { if !it.Next() { require.NoError(t, it.Error()) + break } - _, err := it.Value() - require.NoError(t, err) + _, err2 := it.Value() + require.NoError(t, err2) require.NoError(t, it.Error()) txCount++ @@ -151,14 +153,16 @@ func TestStorageIters(t *testing.T) { require.NoError(t, err) blockCount := 0 + for { if !it2.Next() { require.NoError(t, it2.Error()) + break } - _, err := it2.Value() - require.NoError(t, err) + _, err2 := it2.Value() + require.NoError(t, err2) blockCount++ } @@ -171,9 +175,11 @@ func TestStorageIters(t *testing.T) { require.NoError(t, err) txCount = 0 + for { if !it.Next() { require.NoError(t, it.Error()) + break } @@ -185,7 +191,6 @@ func TestStorageIters(t *testing.T) { } require.Equal(t, 0, txCount) - } // generateRandomBlocks generates dummy blocks diff --git a/storage/types.go b/storage/types.go index 51f9fe2f..127aeb40 100644 --- a/storage/types.go +++ b/storage/types.go @@ -28,7 +28,8 @@ type Reader interface { // BlockIterator iterates over Blocks, limiting the results to be between the provided block numbers BlockIterator(fromBlockNum, toBlockNum int64) (Iterator[*types.Block], error) - // TxIterator iterates over transactions, limiting the results to be between the provided block numbers and transaction indexes + // TxIterator iterates over transactions, limiting the results to be between the provided block numbers + // and transaction indexes TxIterator(fromBlockNum, toBlockNum int64, fromTxIndex, toTxIndex uint32) (Iterator[*types.TxResult], error) } From 330e83712d9b17dd193c382e054bd4aaae15c10e Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Mon, 19 Feb 2024 16:18:30 +0100 Subject: [PATCH 03/13] Add subscriptions Signed-off-by: Antonio Navarro Perez --- cmd/start.go | 2 +- serve/graph/generated.go | 78 ++++----------------------------- serve/graph/resolver.go | 43 ++++++++++++++++-- serve/graph/schema.graphql | 10 +---- serve/graph/schema.resolvers.go | 19 +++++--- serve/graph/setup.go | 5 ++- 6 files changed, 66 insertions(+), 91 deletions(-) diff --git a/cmd/start.go b/cmd/start.go index 278e502b..5dfa456a 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -150,7 +150,7 @@ func (c *startCfg) exec(ctx context.Context) error { mux := chi.NewMux() mux = j.SetupRoutes(mux) - mux = graph.Setup(db, mux) + mux = graph.Setup(db, em, mux) // Create the HTTP server hs := serve.NewHTTPServer(mux, c.listenAddress, logger.Named("http-server")) diff --git a/serve/graph/generated.go b/serve/graph/generated.go index 62221cba..19a558b9 100644 --- a/serve/graph/generated.go +++ b/serve/graph/generated.go @@ -64,8 +64,8 @@ type ComplexityRoot struct { } Subscription struct { - Blocks func(childComplexity int, filter model.BlockFilter) int - Transactions func(childComplexity int, filter model.TransactionFilter) int + Blocks func(childComplexity int) int + Transactions func(childComplexity int) int } Transaction struct { @@ -83,8 +83,8 @@ type QueryResolver interface { LatestBlockHeight(ctx context.Context) (int, error) } type SubscriptionResolver interface { - Transactions(ctx context.Context, filter model.TransactionFilter) (<-chan *model.Transaction, error) - Blocks(ctx context.Context, filter model.BlockFilter) (<-chan *model.Block, error) + Transactions(ctx context.Context) (<-chan *model.Transaction, error) + Blocks(ctx context.Context) (<-chan *model.Block, error) } type executableSchema struct { @@ -177,24 +177,14 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in break } - args, err := ec.field_Subscription_blocks_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Subscription.Blocks(childComplexity, args["filter"].(model.BlockFilter)), true + return e.complexity.Subscription.Blocks(childComplexity), true case "Subscription.transactions": if e.complexity.Subscription.Transactions == nil { break } - args, err := ec.field_Subscription_transactions_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Subscription.Transactions(childComplexity, args["filter"].(model.TransactionFilter)), true + return e.complexity.Subscription.Transactions(childComplexity), true case "Transaction.block_height": if e.complexity.Transaction.BlockHeight == nil { @@ -404,36 +394,6 @@ func (ec *executionContext) field_Query_transactions_args(ctx context.Context, r return args, nil } -func (ec *executionContext) field_Subscription_blocks_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.BlockFilter - if tmp, ok := rawArgs["filter"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) - arg0, err = ec.unmarshalNBlockFilter2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐBlockFilter(ctx, tmp) - if err != nil { - return nil, err - } - } - args["filter"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Subscription_transactions_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 model.TransactionFilter - if tmp, ok := rawArgs["filter"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filter")) - arg0, err = ec.unmarshalNTransactionFilter2githubᚗcomᚋgnolangᚋtxᚑindexerᚋserveᚋgraphᚋmodelᚐTransactionFilter(ctx, tmp) - if err != nil { - return nil, err - } - } - args["filter"] = arg0 - return args, nil -} - func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1007,7 +967,7 @@ func (ec *executionContext) _Subscription_transactions(ctx context.Context, fiel }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Subscription().Transactions(rctx, fc.Args["filter"].(model.TransactionFilter)) + return ec.resolvers.Subscription().Transactions(rctx) }) if err != nil { ec.Error(ctx, err) @@ -1060,17 +1020,6 @@ func (ec *executionContext) fieldContext_Subscription_transactions(ctx context.C return nil, fmt.Errorf("no field named %q was found under type Transaction", field.Name) }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Subscription_transactions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } @@ -1088,7 +1037,7 @@ func (ec *executionContext) _Subscription_blocks(ctx context.Context, field grap }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Subscription().Blocks(rctx, fc.Args["filter"].(model.BlockFilter)) + return ec.resolvers.Subscription().Blocks(rctx) }) if err != nil { ec.Error(ctx, err) @@ -1141,17 +1090,6 @@ func (ec *executionContext) fieldContext_Subscription_blocks(ctx context.Context return nil, fmt.Errorf("no field named %q was found under type Block", field.Name) }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Subscription_blocks_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } diff --git a/serve/graph/resolver.go b/serve/graph/resolver.go index 0a2c08cc..64a235f4 100644 --- a/serve/graph/resolver.go +++ b/serve/graph/resolver.go @@ -3,9 +3,15 @@ package graph import ( + "context" + "fmt" "time" + "github.com/99designs/gqlgen/graphql" + + "github.com/gnolang/tx-indexer/events" "github.com/gnolang/tx-indexer/storage" + "github.com/gnolang/tx-indexer/types" ) // This file will not be regenerated automatically. @@ -32,10 +38,41 @@ func dereferenceTime(i *time.Time) time.Time { return *i } +func handleChannel[T any](ctx context.Context, m *events.Manager, writeToChannel func(*types.NewBlock, chan T)) chan T { + ch := make(chan T) + go func() { + defer close(ch) + + sub := m.Subscribe([]events.Type{types.NewBlockEvent}) + defer m.CancelSubscription(sub.ID) + for { + select { + case <-ctx.Done(): + graphql.AddError(ctx, ctx.Err()) + return + case rawE, ok := <-sub.SubCh: + if !ok { + return + } + e, ok := rawE.GetData().(*types.NewBlock) + if !ok { + graphql.AddError(ctx, fmt.Errorf("error casting event data. Obtained event ID: %q", rawE.GetType())) + return + } + + writeToChannel(e, ch) + } + } + }() + + return ch +} + type Resolver struct { - store storage.Storage + store storage.Storage + manager *events.Manager } -func NewResolver(s storage.Storage) *Resolver { - return &Resolver{store: s} +func NewResolver(s storage.Storage, m *events.Manager) *Resolver { + return &Resolver{store: s, manager: m} } diff --git a/serve/graph/schema.graphql b/serve/graph/schema.graphql index 150fa3f5..6191ced3 100644 --- a/serve/graph/schema.graphql +++ b/serve/graph/schema.graphql @@ -170,13 +170,10 @@ type Subscription { This is useful for applications needing to track Transactions in real-time, such as wallets tracking incoming transactions or analytics platforms monitoring blockchain activity. - Parameters: - - filter: TransactionFilter - Specifies the criteria used to filter the Transactions for which real-time updates are desired. - Returns: - Transaction: Each received update is a Transaction object that matches the filter criteria. """ - transactions(filter: TransactionFilter!): Transaction! + transactions: Transaction! """ Subscribes to real-time updates of Blocks that match the provided filter criteria. Similar to the Transactions subscription, @@ -185,13 +182,10 @@ type Subscription { This subscription is ideal for services that need to be notified of new Blocks for processing or analysis, such as block explorers, data aggregators, or security monitoring tools. - Parameters: - - filter: BlockFilter - Defines the conditions Blocks must meet to trigger an update to the subscriber. - Returns: - Block: Each update consists of a Block object that satisfies the filter criteria, allowing subscribers to process or analyze new Blocks in real time. """ - blocks(filter: BlockFilter!): Block! + blocks: Block! } """ diff --git a/serve/graph/schema.resolvers.go b/serve/graph/schema.resolvers.go index efc9ed61..adaa94e9 100644 --- a/serve/graph/schema.resolvers.go +++ b/serve/graph/schema.resolvers.go @@ -6,12 +6,11 @@ package graph import ( "context" - "fmt" "github.com/99designs/gqlgen/graphql" - "github.com/vektah/gqlparser/v2/gqlerror" - "github.com/gnolang/tx-indexer/serve/graph/model" + "github.com/gnolang/tx-indexer/types" + "github.com/vektah/gqlparser/v2/gqlerror" ) // Transactions is the resolver for the transactions field. @@ -126,13 +125,19 @@ func (r *queryResolver) LatestBlockHeight(ctx context.Context) (int, error) { } // Transactions is the resolver for the transactions field. -func (r *subscriptionResolver) Transactions(ctx context.Context, filter model.TransactionFilter) (<-chan *model.Transaction, error) { - panic(fmt.Errorf("not implemented: Transactions - transactions")) +func (r *subscriptionResolver) Transactions(ctx context.Context) (<-chan *model.Transaction, error) { + return handleChannel[*model.Transaction](ctx, r.manager, func(nb *types.NewBlock, c chan *model.Transaction) { + for _, tx := range nb.Results { + c <- model.NewTransaction(tx) + } + }), nil } // Blocks is the resolver for the blocks field. -func (r *subscriptionResolver) Blocks(ctx context.Context, filter model.BlockFilter) (<-chan *model.Block, error) { - panic(fmt.Errorf("not implemented: Blocks - blocks")) +func (r *subscriptionResolver) Blocks(ctx context.Context) (<-chan *model.Block, error) { + return handleChannel[*model.Block](ctx, r.manager, func(nb *types.NewBlock, c chan *model.Block) { + c <- model.NewBlock(nb.Block) + }), nil } // Query returns QueryResolver implementation. diff --git a/serve/graph/setup.go b/serve/graph/setup.go index 8203313b..787fbefc 100644 --- a/serve/graph/setup.go +++ b/serve/graph/setup.go @@ -6,11 +6,12 @@ import ( "github.com/99designs/gqlgen/graphql/playground" "github.com/go-chi/chi/v5" + "github.com/gnolang/tx-indexer/events" "github.com/gnolang/tx-indexer/storage" ) -func Setup(s storage.Storage, m *chi.Mux) *chi.Mux { - srv := handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: NewResolver(s)})) +func Setup(s storage.Storage, manager *events.Manager, m *chi.Mux) *chi.Mux { + srv := handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: NewResolver(s, manager)})) srv.AddTransport(&transport.Websocket{}) From 6db907136e3548ddc283a493415664142cde7cb0 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Mon, 19 Feb 2024 16:34:25 +0100 Subject: [PATCH 04/13] Make linter happy as usual. Signed-off-by: Antonio Navarro Perez --- Makefile | 2 +- internal/mock/storage.go | 10 +++++----- serve/graph/resolver.go | 4 ++++ serve/server.go | 2 +- storage/pebble.go | 11 +++++------ 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 0d55d775..7cafc6bd 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ gofumpt: .PHONY: fixalign fixalign: go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest - fieldalignment -fix $(filter-out $@,$(MAKECMDGOALS)) # the full package name (not path!) + fieldalignment -fix ./... .PHONY: test test: diff --git a/internal/mock/storage.go b/internal/mock/storage.go index 570a1958..11476fda 100644 --- a/internal/mock/storage.go +++ b/internal/mock/storage.go @@ -42,17 +42,17 @@ func (m *Storage) GetTx(blockNum int64, index uint32) (*types.TxResult, error) { } // BlockIterator iterates over Blocks, limiting the results to be between the provided block numbers -func (m *Storage) BlockIterator(fromBlockNum, toBlockNum int64) (storage.Iterator[*types.Block], error) { +func (m *Storage) BlockIterator(_, _ int64) (storage.Iterator[*types.Block], error) { panic("not implemented") // TODO: Implement } // TxIterator iterates over transactions, limiting the results to be between the provided block numbers // and transaction indexes func (m *Storage) TxIterator( - fromBlockNum, - toBlockNum int64, - fromTxIndex, - toTxIndex uint32, + _, + _ int64, + _, + _ uint32, ) (storage.Iterator[*types.TxResult], error) { panic("not implemented") // TODO: Implement } diff --git a/serve/graph/resolver.go b/serve/graph/resolver.go index 64a235f4..10e8dcbb 100644 --- a/serve/graph/resolver.go +++ b/serve/graph/resolver.go @@ -45,18 +45,22 @@ func handleChannel[T any](ctx context.Context, m *events.Manager, writeToChannel sub := m.Subscribe([]events.Type{types.NewBlockEvent}) defer m.CancelSubscription(sub.ID) + for { select { case <-ctx.Done(): graphql.AddError(ctx, ctx.Err()) + return case rawE, ok := <-sub.SubCh: if !ok { return } + e, ok := rawE.GetData().(*types.NewBlock) if !ok { graphql.AddError(ctx, fmt.Errorf("error casting event data. Obtained event ID: %q", rawE.GetType())) + return } diff --git a/serve/server.go b/serve/server.go index 7bede074..e07aa21f 100644 --- a/serve/server.go +++ b/serve/server.go @@ -17,8 +17,8 @@ const ( type HTTPServer struct { h http.Handler - addr string logger *zap.Logger + addr string } func NewHTTPServer(h http.Handler, addr string, logger *zap.Logger) *HTTPServer { diff --git a/storage/pebble.go b/storage/pebble.go index a9da9b1d..3319410d 100644 --- a/storage/pebble.go +++ b/storage/pebble.go @@ -210,13 +210,12 @@ func (pi *PebbleBlockIter) Close() error { var _ Iterator[*types.TxResult] = &PebbleTxIter{} type PebbleTxIter struct { - fromIndex, toIndex uint32 - - init bool nextError error - - i *pebble.Iterator - s *pebble.Snapshot + i *pebble.Iterator + s *pebble.Snapshot + fromIndex uint32 + toIndex uint32 + init bool } func (pi *PebbleTxIter) Next() bool { From b0ba39a6d6c0dc4fb6e1f0ae1be13d4bff789426 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Thu, 7 Mar 2024 16:14:34 +0100 Subject: [PATCH 05/13] Requested changes Signed-off-by: Antonio Navarro Perez --- Makefile | 6 +- client/batch.go | 10 +- client/http.go | 15 +- client/types/types.go | 4 +- fetch/fetch.go | 8 +- fetch/fetch_test.go | 80 +++++----- fetch/mocks_test.go | 20 +-- fetch/slots.go | 14 +- fetch/slots_test.go | 4 +- fetch/types.go | 6 +- fetch/worker.go | 6 +- internal/mock/storage.go | 20 +-- serve/graph/schema.resolvers.go | 11 +- serve/handlers/block/block.go | 5 +- serve/handlers/block/block_test.go | 16 +- serve/handlers/block/mocks_test.go | 4 +- serve/handlers/block/types.go | 2 +- serve/handlers/tx/mocks_test.go | 4 +- serve/handlers/tx/tx.go | 4 +- serve/handlers/tx/tx_test.go | 12 +- serve/handlers/tx/types.go | 2 +- storage/encode.go | 236 +++++++---------------------- storage/pebble.go | 46 +++--- storage/pebble_test.go | 6 +- storage/types.go | 12 +- 25 files changed, 215 insertions(+), 338 deletions(-) diff --git a/Makefile b/Makefile index 7cafc6bd..d59bdf16 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,11 @@ gofumpt: .PHONY: fixalign fixalign: go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest - fieldalignment -fix ./... + fieldalignment -fix $(filter-out $@,$(MAKECMDGOALS)) # the full package name (not path!) + +.PHONY: generate +generate: + go generate ./... .PHONY: test test: diff --git a/client/batch.go b/client/batch.go index 1cc55283..74e6a6fc 100644 --- a/client/batch.go +++ b/client/batch.go @@ -12,8 +12,9 @@ type Batch struct { } // AddBlockRequest adds a new block request (block fetch) to the batch -func (b *Batch) AddBlockRequest(blockNum int64) error { - if _, err := b.batch.Block(&blockNum); err != nil { +func (b *Batch) AddBlockRequest(blockNum uint64) error { + bn := int64(blockNum) + if _, err := b.batch.Block(&bn); err != nil { return fmt.Errorf("unable to add block request, %w", err) } @@ -21,8 +22,9 @@ func (b *Batch) AddBlockRequest(blockNum int64) error { } // AddBlockResultsRequest adds a new block results request (block results fetch) to the batch -func (b *Batch) AddBlockResultsRequest(blockNum int64) error { - if _, err := b.batch.BlockResults(&blockNum); err != nil { +func (b *Batch) AddBlockResultsRequest(blockNum uint64) error { + bn := int64(blockNum) + if _, err := b.batch.BlockResults(&bn); err != nil { return fmt.Errorf("unable to add block results request, %w", err) } diff --git a/client/http.go b/client/http.go index ee4c71a2..d155f7b9 100644 --- a/client/http.go +++ b/client/http.go @@ -5,6 +5,7 @@ import ( rpcClient "github.com/gnolang/gno/tm2/pkg/bft/rpc/client" core_types "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" + clientTypes "github.com/gnolang/tx-indexer/client/types" ) @@ -27,17 +28,18 @@ func (c *Client) CreateBatch() clientTypes.Batch { } } -func (c *Client) GetLatestBlockNumber() (int64, error) { +func (c *Client) GetLatestBlockNumber() (uint64, error) { status, err := c.client.Status() if err != nil { return 0, fmt.Errorf("unable to get chain status, %w", err) } - return status.SyncInfo.LatestBlockHeight, nil + return uint64(status.SyncInfo.LatestBlockHeight), nil } -func (c *Client) GetBlock(blockNum int64) (*core_types.ResultBlock, error) { - block, err := c.client.Block(&blockNum) +func (c *Client) GetBlock(blockNum uint64) (*core_types.ResultBlock, error) { + bn := int64(blockNum) + block, err := c.client.Block(&bn) if err != nil { return nil, fmt.Errorf("unable to get block, %w", err) } @@ -45,8 +47,9 @@ func (c *Client) GetBlock(blockNum int64) (*core_types.ResultBlock, error) { return block, nil } -func (c *Client) GetBlockResults(blockNum int64) (*core_types.ResultBlockResults, error) { - results, err := c.client.BlockResults(&blockNum) +func (c *Client) GetBlockResults(blockNum uint64) (*core_types.ResultBlockResults, error) { + bn := int64(blockNum) + results, err := c.client.BlockResults(&bn) if err != nil { return nil, fmt.Errorf("unable to get block results, %w", err) } diff --git a/client/types/types.go b/client/types/types.go index ea5e87d9..c11dca9d 100644 --- a/client/types/types.go +++ b/client/types/types.go @@ -3,10 +3,10 @@ package types // Batch defines the interface for the client batch type Batch interface { // AddBlockRequest adds a new block request (block fetch) to the batch - AddBlockRequest(int64) error + AddBlockRequest(uint64) error // AddBlockResultsRequest adds a new block results request (block results fetch) to the batch - AddBlockResultsRequest(int64) error + AddBlockResultsRequest(uint64) error // Execute sends the batch off for processing by the node Execute() ([]any, error) diff --git a/fetch/fetch.go b/fetch/fetch.go index a646f4cc..16024f78 100644 --- a/fetch/fetch.go +++ b/fetch/fetch.go @@ -110,8 +110,8 @@ func (f *Fetcher) FetchChainData(ctx context.Context) error { for _, gap := range gaps { f.logger.Info( "Fetching range", - zap.Int64("from", gap.from), - zap.Int64("to", gap.to), + zap.Uint64("from", gap.from), + zap.Uint64("to", gap.to), ) // Spawn worker @@ -223,8 +223,8 @@ func (f *Fetcher) FetchChainData(ctx context.Context) error { f.logger.Info( "Added to batch block and tx data for range", - zap.Int64("from", item.chunkRange.from), - zap.Int64("to", item.chunkRange.to), + zap.Uint64("from", item.chunkRange.from), + zap.Uint64("to", item.chunkRange.to), ) // Save the latest height data diff --git a/fetch/fetch_test.go b/fetch/fetch_test.go index 18dd6921..09e2bf72 100644 --- a/fetch/fetch_test.go +++ b/fetch/fetch_test.go @@ -35,7 +35,7 @@ func TestFetcher_FetchTransactions_Invalid(t *testing.T) { fetchErr = errors.New("random DB error") mockStorage = &mock.Storage{ - GetLatestSavedHeightFn: func() (int64, error) { + GetLatestSavedHeightFn: func() (uint64, error) { return 0, fetchErr }, } @@ -85,10 +85,10 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { }, } - latestSaved = int64(0) + latestSaved = uint64(0) mockStorage = &mock.Storage{ - GetLatestSavedHeightFn: func() (int64, error) { + GetLatestSavedHeightFn: func() (uint64, error) { if latestSaved == 0 { return 0, storageErrors.ErrNotFound } @@ -106,7 +106,7 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { cancelFn() } - latestSaved = block.Height + latestSaved = uint64(block.Height) return nil }, @@ -131,12 +131,12 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { }, } }, - getLatestBlockNumberFn: func() (int64, error) { - return int64(blockNum), nil + getLatestBlockNumberFn: func() (uint64, error) { + return uint64(blockNum), nil }, - getBlockFn: func(num int64) (*core_types.ResultBlock, error) { + getBlockFn: func(num uint64) (*core_types.ResultBlock, error) { // Sanity check - if num > int64(blockNum) { + if num > uint64(blockNum) { t.Fatalf("invalid block requested, %d", num) } @@ -144,14 +144,14 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { Block: blocks[num], }, nil }, - getBlockResultsFn: func(num int64) (*core_types.ResultBlockResults, error) { + getBlockResultsFn: func(num uint64) (*core_types.ResultBlockResults, error) { // Sanity check - if num > int64(blockNum) { + if num > uint64(blockNum) { t.Fatalf("invalid block requested, %d", num) } return &core_types.ResultBlockResults{ - Height: num, + Height: int64(num), Results: &state.ABCIResponses{ DeliverTxs: make([]abci.ResponseDeliverTx, txCount), }, @@ -240,10 +240,10 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { }, } - latestSaved = int64(0) + latestSaved = uint64(0) mockStorage = &mock.Storage{ - GetLatestSavedHeightFn: func() (int64, error) { + GetLatestSavedHeightFn: func() (uint64, error) { if latestSaved == 0 { return 0, storageErrors.ErrNotFound } @@ -261,7 +261,7 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { cancelFn() } - latestSaved = block.Height + latestSaved = uint64(block.Height) return nil }, @@ -290,9 +290,9 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { countFn: func() int { return len(batch) }, - addBlockRequestFn: func(num int64) error { + addBlockRequestFn: func(num uint64) error { // Sanity check - if num > int64(blockNum) { + if num > uint64(blockNum) { t.Fatalf("invalid block requested, %d", num) } @@ -305,15 +305,15 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { return nil }, - addBlockResultsRequestFn: func(num int64) error { + addBlockResultsRequestFn: func(num uint64) error { // Sanity check - if num > int64(blockNum) { + if num > uint64(blockNum) { t.Fatalf("invalid block requested, %d", num) } batch = append(batch, &core_types.ResultBlockResults{ - Height: num, + Height: int64(num), Results: &state.ABCIResponses{ DeliverTxs: make([]abci.ResponseDeliverTx, txCount), }, @@ -324,8 +324,8 @@ func TestFetcher_FetchTransactions_Valid_FullBlocks(t *testing.T) { }, } }, - getLatestBlockNumberFn: func() (int64, error) { - return int64(blockNum), nil + getLatestBlockNumberFn: func() (uint64, error) { + return uint64(blockNum), nil }, } ) @@ -417,7 +417,7 @@ func TestFetcher_FetchTransactions_Valid_EmptyBlocks(t *testing.T) { } mockStorage = &mock.Storage{ - GetLatestSavedHeightFn: func() (int64, error) { + GetLatestSavedHeightFn: func() (uint64, error) { return 0, storageErrors.ErrNotFound }, GetWriteBatchFn: func() storage.Batch { @@ -454,12 +454,12 @@ func TestFetcher_FetchTransactions_Valid_EmptyBlocks(t *testing.T) { }, } }, - getLatestBlockNumberFn: func() (int64, error) { - return int64(blockNum), nil + getLatestBlockNumberFn: func() (uint64, error) { + return uint64(blockNum), nil }, - getBlockFn: func(num int64) (*core_types.ResultBlock, error) { + getBlockFn: func(num uint64) (*core_types.ResultBlock, error) { // Sanity check - if num > int64(blockNum) { + if num > uint64(blockNum) { t.Fatalf("invalid block requested, %d", num) } @@ -467,7 +467,7 @@ func TestFetcher_FetchTransactions_Valid_EmptyBlocks(t *testing.T) { Block: blocks[num], }, nil }, - getBlockResultsFn: func(_ int64) (*core_types.ResultBlockResults, error) { + getBlockResultsFn: func(_ uint64) (*core_types.ResultBlockResults, error) { t.Fatalf("should not request results") return nil, nil @@ -523,7 +523,7 @@ func TestFetcher_FetchTransactions_Valid_EmptyBlocks(t *testing.T) { } mockStorage = &mock.Storage{ - GetLatestSavedHeightFn: func() (int64, error) { + GetLatestSavedHeightFn: func() (uint64, error) { return 0, storageErrors.ErrNotFound }, GetWriteBatchFn: func() storage.Batch { @@ -564,9 +564,9 @@ func TestFetcher_FetchTransactions_Valid_EmptyBlocks(t *testing.T) { countFn: func() int { return len(batch) }, - addBlockRequestFn: func(num int64) error { + addBlockRequestFn: func(num uint64) error { // Sanity check - if num > int64(blockNum) { + if num > uint64(blockNum) { t.Fatalf("invalid block requested, %d", num) } @@ -579,15 +579,15 @@ func TestFetcher_FetchTransactions_Valid_EmptyBlocks(t *testing.T) { return nil }, - addBlockResultsRequestFn: func(num int64) error { + addBlockResultsRequestFn: func(num uint64) error { t.Fatalf("block %d should not have txs", num) return nil }, } }, - getLatestBlockNumberFn: func() (int64, error) { - return int64(blockNum), nil + getLatestBlockNumberFn: func() (uint64, error) { + return uint64(blockNum), nil }, } ) @@ -643,7 +643,7 @@ func TestFetcher_InvalidBlocks(t *testing.T) { } mockStorage = &mock.Storage{ - GetLatestSavedHeightFn: func() (int64, error) { + GetLatestSavedHeightFn: func() (uint64, error) { return 0, storageErrors.ErrNotFound }, GetWriteBatchFn: func() storage.Batch { @@ -680,12 +680,12 @@ func TestFetcher_InvalidBlocks(t *testing.T) { }, } }, - getLatestBlockNumberFn: func() (int64, error) { - return int64(blockNum), nil + getLatestBlockNumberFn: func() (uint64, error) { + return uint64(blockNum), nil }, - getBlockFn: func(num int64) (*core_types.ResultBlock, error) { + getBlockFn: func(num uint64) (*core_types.ResultBlock, error) { // Sanity check - if num > int64(blockNum) { + if num > uint64(blockNum) { t.Fatalf("invalid block requested, %d", num) } @@ -693,8 +693,8 @@ func TestFetcher_InvalidBlocks(t *testing.T) { Block: blocks[num], }, nil }, - getBlockResultsFn: func(num int64) (*core_types.ResultBlockResults, error) { - require.LessOrEqual(t, num, int64(blockNum)) + getBlockResultsFn: func(num uint64) (*core_types.ResultBlockResults, error) { + require.LessOrEqual(t, num, uint64(blockNum)) return nil, fmt.Errorf("unable to fetch result for block %d", num) }, diff --git a/fetch/mocks_test.go b/fetch/mocks_test.go index dc966054..91f9a1e9 100644 --- a/fetch/mocks_test.go +++ b/fetch/mocks_test.go @@ -8,9 +8,9 @@ import ( ) type ( - getLatestBlockNumberDelegate func() (int64, error) - getBlockDelegate func(int64) (*core_types.ResultBlock, error) - getBlockResultsDelegate func(int64) (*core_types.ResultBlockResults, error) + getLatestBlockNumberDelegate func() (uint64, error) + getBlockDelegate func(uint64) (*core_types.ResultBlock, error) + getBlockResultsDelegate func(uint64) (*core_types.ResultBlockResults, error) createBatchDelegate func() clientTypes.Batch ) @@ -23,7 +23,7 @@ type mockClient struct { createBatchFn createBatchDelegate } -func (m *mockClient) GetLatestBlockNumber() (int64, error) { +func (m *mockClient) GetLatestBlockNumber() (uint64, error) { if m.getLatestBlockNumberFn != nil { return m.getLatestBlockNumberFn() } @@ -31,7 +31,7 @@ func (m *mockClient) GetLatestBlockNumber() (int64, error) { return 0, nil } -func (m *mockClient) GetBlock(blockNum int64) (*core_types.ResultBlock, error) { +func (m *mockClient) GetBlock(blockNum uint64) (*core_types.ResultBlock, error) { if m.getBlockFn != nil { return m.getBlockFn(blockNum) } @@ -39,7 +39,7 @@ func (m *mockClient) GetBlock(blockNum int64) (*core_types.ResultBlock, error) { return nil, nil } -func (m *mockClient) GetBlockResults(blockNum int64) (*core_types.ResultBlockResults, error) { +func (m *mockClient) GetBlockResults(blockNum uint64) (*core_types.ResultBlockResults, error) { if m.getBlockResultsFn != nil { return m.getBlockResultsFn(blockNum) } @@ -56,8 +56,8 @@ func (m *mockClient) CreateBatch() clientTypes.Batch { } type ( - addBlockRequestDelegate func(int64) error - addBlockResultsRequestDelegate func(int64) error + addBlockRequestDelegate func(uint64) error + addBlockResultsRequestDelegate func(uint64) error executeDelegate func() ([]any, error) countDelegate func() int ) @@ -69,7 +69,7 @@ type mockBatch struct { countFn countDelegate } -func (m *mockBatch) AddBlockRequest(num int64) error { +func (m *mockBatch) AddBlockRequest(num uint64) error { if m.addBlockRequestFn != nil { return m.addBlockRequestFn(num) } @@ -77,7 +77,7 @@ func (m *mockBatch) AddBlockRequest(num int64) error { return nil } -func (m *mockBatch) AddBlockResultsRequest(num int64) error { +func (m *mockBatch) AddBlockResultsRequest(num uint64) error { if m.addBlockResultsRequestFn != nil { return m.addBlockResultsRequestFn(num) } diff --git a/fetch/slots.go b/fetch/slots.go index 5713a23a..49dc1084 100644 --- a/fetch/slots.go +++ b/fetch/slots.go @@ -27,8 +27,8 @@ func (s *slot) Less(i queue.Item) bool { // chunkRange is the data sequence range for the data type chunkRange struct { - from int64 // sequence from (inclusive) - to int64 // sequence to (inclusive) + from uint64 // sequence from (inclusive) + to uint64 // sequence to (inclusive) } // less returns a flag indicating if the current chunk range is less than the other @@ -61,7 +61,7 @@ func (s *slots) setChunk(index int, chunk *chunk) { } // reserveChunkRanges reserves empty chunk ranges, and returns them, if any -func (s *slots) reserveChunkRanges(start, end, maxChunkSize int64) []chunkRange { +func (s *slots) reserveChunkRanges(start, end uint64, maxChunkSize int64) []chunkRange { freeSlots := s.maxSlots - s.Len() gaps := s.findGaps(start, end, maxChunkSize) @@ -86,7 +86,7 @@ func (s *slots) reserveChunkRanges(start, end, maxChunkSize int64) []chunkRange // can potentially recover unfilled gaps, since they will exist given the // proper start and end ranges. This situation is reflected in the testing // suite for the slots -func (s *slots) findGaps(start, end, maxSize int64) []chunkRange { +func (s *slots) findGaps(start, end uint64, maxSize int64) []chunkRange { var ( chunkRanges []chunkRange // contains all gaps dividedGaps []chunkRange // contains at most maxSize gaps @@ -122,16 +122,16 @@ func (s *slots) findGaps(start, end, maxSize int64) []chunkRange { } for _, gap := range chunkRanges { - if gap.to-gap.from+1 <= maxSize { + if gap.to-gap.from+1 <= uint64(maxSize) { dividedGaps = append(dividedGaps, gap) continue } - for i := gap.from; i <= gap.to; i += maxSize { + for i := gap.from; i <= gap.to; i += uint64(maxSize) { newGap := chunkRange{ from: i, - to: i + maxSize - 1, + to: i + uint64(maxSize) - 1, } if newGap.to > gap.to { diff --git a/fetch/slots_test.go b/fetch/slots_test.go index 95d2f42f..c40744a4 100644 --- a/fetch/slots_test.go +++ b/fetch/slots_test.go @@ -56,8 +56,8 @@ func TestSlots_FindGaps(t *testing.T) { existingRanges []chunkRange expectedRanges []chunkRange - start int64 - end int64 + start uint64 + end uint64 maxChunkSize int64 }{ { diff --git a/fetch/types.go b/fetch/types.go index 80a0cac0..cb75e844 100644 --- a/fetch/types.go +++ b/fetch/types.go @@ -10,14 +10,14 @@ import ( // Client defines the interface for the node (client) communication type Client interface { // GetLatestBlockNumber returns the latest block height from the chain - GetLatestBlockNumber() (int64, error) + GetLatestBlockNumber() (uint64, error) // GetBlock returns specified block - GetBlock(int64) (*core_types.ResultBlock, error) + GetBlock(uint64) (*core_types.ResultBlock, error) // GetBlockResults returns the results of executing the transactions // for the specified block - GetBlockResults(int64) (*core_types.ResultBlockResults, error) + GetBlockResults(uint64) (*core_types.ResultBlockResults, error) // CreateBatch creates a new client batch CreateBatch() clientTypes.Batch diff --git a/fetch/worker.go b/fetch/worker.go index c877943e..63813406 100644 --- a/fetch/worker.go +++ b/fetch/worker.go @@ -108,7 +108,7 @@ func getBlocksSequentially(chunkRange chunkRange, client Client) ([]*types.Block for blockNum := chunkRange.from; blockNum <= chunkRange.to; blockNum++ { // Get block info from the chain - block, err := client.GetBlock(blockNum) + block, err := client.GetBlock(uint64(blockNum)) if err != nil { errs = append(errs, fmt.Errorf("unable to get block %d, %w", blockNum, err)) @@ -139,7 +139,7 @@ func getTxResultFromBatch(blocks []*types.Block, client Client) ([][]*types.TxRe } // Add the request to the batch - if err := batch.AddBlockResultsRequest(block.Height); err != nil { + if err := batch.AddBlockResultsRequest(uint64(block.Height)); err != nil { return nil, fmt.Errorf( "unable to add block results request for block %d, %w", block.Height, @@ -203,7 +203,7 @@ func getTxResultsSequentially(blocks []*types.Block, client Client) ([][]*types. } // Get the transaction execution results - blockResults, err := client.GetBlockResults(block.Height) + blockResults, err := client.GetBlockResults(uint64(block.Height)) if err != nil { errs = append( errs, diff --git a/internal/mock/storage.go b/internal/mock/storage.go index 11476fda..81dfe5eb 100644 --- a/internal/mock/storage.go +++ b/internal/mock/storage.go @@ -9,13 +9,13 @@ import ( var _ storage.Storage = &Storage{} type Storage struct { - GetLatestSavedHeightFn func() (int64, error) + GetLatestSavedHeightFn func() (uint64, error) GetWriteBatchFn func() storage.Batch - GetBlockFn func(int64) (*types.Block, error) - GetTxFn func(int64, uint32) (*types.TxResult, error) + GetBlockFn func(uint64) (*types.Block, error) + GetTxFn func(uint64, uint32) (*types.TxResult, error) } -func (m *Storage) GetLatestHeight() (int64, error) { +func (m *Storage) GetLatestHeight() (uint64, error) { if m.GetLatestSavedHeightFn != nil { return m.GetLatestSavedHeightFn() } @@ -24,7 +24,7 @@ func (m *Storage) GetLatestHeight() (int64, error) { } // GetBlock fetches the block by its number -func (m *Storage) GetBlock(blockNum int64) (*types.Block, error) { +func (m *Storage) GetBlock(blockNum uint64) (*types.Block, error) { if m.GetBlockFn != nil { return m.GetBlockFn(blockNum) } @@ -33,7 +33,7 @@ func (m *Storage) GetBlock(blockNum int64) (*types.Block, error) { } // GetTx fetches the tx using block height and transaction index -func (m *Storage) GetTx(blockNum int64, index uint32) (*types.TxResult, error) { +func (m *Storage) GetTx(blockNum uint64, index uint32) (*types.TxResult, error) { if m.GetTxFn != nil { return m.GetTxFn(blockNum, index) } @@ -42,7 +42,7 @@ func (m *Storage) GetTx(blockNum int64, index uint32) (*types.TxResult, error) { } // BlockIterator iterates over Blocks, limiting the results to be between the provided block numbers -func (m *Storage) BlockIterator(_, _ int64) (storage.Iterator[*types.Block], error) { +func (m *Storage) BlockIterator(_, _ uint64) (storage.Iterator[*types.Block], error) { panic("not implemented") // TODO: Implement } @@ -50,7 +50,7 @@ func (m *Storage) BlockIterator(_, _ int64) (storage.Iterator[*types.Block], err // and transaction indexes func (m *Storage) TxIterator( _, - _ int64, + _ uint64, _, _ uint32, ) (storage.Iterator[*types.TxResult], error) { @@ -72,13 +72,13 @@ func (m *Storage) Close() error { } type WriteBatch struct { - SetLatestHeightFn func(int64) error + SetLatestHeightFn func(uint64) error SetBlockFn func(*types.Block) error SetTxFn func(*types.TxResult) error } // SetLatestHeight saves the latest block height to the storage -func (mb *WriteBatch) SetLatestHeight(h int64) error { +func (mb *WriteBatch) SetLatestHeight(h uint64) error { if mb.SetLatestHeightFn != nil { return mb.SetLatestHeightFn(h) } diff --git a/serve/graph/schema.resolvers.go b/serve/graph/schema.resolvers.go index adaa94e9..cb13c533 100644 --- a/serve/graph/schema.resolvers.go +++ b/serve/graph/schema.resolvers.go @@ -8,9 +8,10 @@ import ( "context" "github.com/99designs/gqlgen/graphql" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/gnolang/tx-indexer/serve/graph/model" "github.com/gnolang/tx-indexer/types" - "github.com/vektah/gqlparser/v2/gqlerror" ) // Transactions is the resolver for the transactions field. @@ -18,8 +19,8 @@ func (r *queryResolver) Transactions(ctx context.Context, filter model.Transacti it, err := r. store. TxIterator( - int64(dereferenceInt(filter.FromBlockHeight)), - int64(dereferenceInt(filter.ToBlockHeight)), + uint64(dereferenceInt(filter.FromBlockHeight)), + uint64(dereferenceInt(filter.ToBlockHeight)), uint32(dereferenceInt(filter.FromIndex)), uint32(dereferenceInt(filter.ToIndex)), ) @@ -74,8 +75,8 @@ func (r *queryResolver) Blocks(ctx context.Context, filter model.BlockFilter) ([ it, err := r. store. BlockIterator( - int64(dereferenceInt(filter.FromHeight)), - int64(dereferenceInt(filter.ToHeight)), + uint64(dereferenceInt(filter.FromHeight)), + uint64(dereferenceInt(filter.ToHeight)), ) if err != nil { return nil, gqlerror.Wrap(err) diff --git a/serve/handlers/block/block.go b/serve/handlers/block/block.go index 33e50789..5475e0bf 100644 --- a/serve/handlers/block/block.go +++ b/serve/handlers/block/block.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/gnolang/gno/tm2/pkg/bft/types" + "github.com/gnolang/tx-indexer/serve/encode" "github.com/gnolang/tx-indexer/serve/metadata" "github.com/gnolang/tx-indexer/serve/spec" @@ -36,7 +37,7 @@ func (h *Handler) GetBlockHandler( return nil, spec.GenerateInvalidParamError(1) } - blockNum, err := strconv.ParseInt(requestedBlock, 10, 64) + blockNum, err := strconv.ParseUint(requestedBlock, 10, 64) if err != nil { return nil, spec.GenerateInvalidParamError(1) } @@ -60,7 +61,7 @@ func (h *Handler) GetBlockHandler( } // getBlock fetches the block from storage, if any -func (h *Handler) getBlock(blockNum int64) (*types.Block, error) { +func (h *Handler) getBlock(blockNum uint64) (*types.Block, error) { block, err := h.storage.GetBlock(blockNum) if errors.Is(err, storageErrors.ErrNotFound) { // Wrap the error diff --git a/serve/handlers/block/block_test.go b/serve/handlers/block/block_test.go index 5733aef6..fc1d6525 100644 --- a/serve/handlers/block/block_test.go +++ b/serve/handlers/block/block_test.go @@ -3,16 +3,16 @@ package block import ( "encoding/base64" "errors" - "math" "strconv" "testing" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" - "github.com/gnolang/tx-indexer/serve/spec" - storageErrors "github.com/gnolang/tx-indexer/storage/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/gnolang/tx-indexer/serve/spec" + storageErrors "github.com/gnolang/tx-indexer/storage/errors" ) func TestGetBlock_InvalidParams(t *testing.T) { @@ -30,10 +30,6 @@ func TestGetBlock_InvalidParams(t *testing.T) { "invalid param type", []any{1}, }, - { - "invalid int64 type", - []any{strconv.FormatUint(math.MaxUint64, 10)}, - }, } for _, testCase := range testTable { @@ -61,7 +57,7 @@ func TestGetBlock_Handler(t *testing.T) { t.Parallel() mockStorage := &mockStorage{ - getBlockFn: func(_ int64) (*types.Block, error) { + getBlockFn: func(_ uint64) (*types.Block, error) { return nil, storageErrors.ErrNotFound }, } @@ -82,7 +78,7 @@ func TestGetBlock_Handler(t *testing.T) { fetchErr = errors.New("random error") mockStorage = &mockStorage{ - getBlockFn: func(_ int64) (*types.Block, error) { + getBlockFn: func(_ uint64) (*types.Block, error) { return nil, fetchErr }, } @@ -113,7 +109,7 @@ func TestGetBlock_Handler(t *testing.T) { } mockStorage = &mockStorage{ - getBlockFn: func(num int64) (*types.Block, error) { + getBlockFn: func(num uint64) (*types.Block, error) { require.EqualValues(t, blockNum, num) return block, nil diff --git a/serve/handlers/block/mocks_test.go b/serve/handlers/block/mocks_test.go index 0b7f269b..f53ad1ba 100644 --- a/serve/handlers/block/mocks_test.go +++ b/serve/handlers/block/mocks_test.go @@ -2,13 +2,13 @@ package block import "github.com/gnolang/gno/tm2/pkg/bft/types" -type getBlockDelegate func(int64) (*types.Block, error) +type getBlockDelegate func(uint64) (*types.Block, error) type mockStorage struct { getBlockFn getBlockDelegate } -func (m *mockStorage) GetBlock(num int64) (*types.Block, error) { +func (m *mockStorage) GetBlock(num uint64) (*types.Block, error) { if m.getBlockFn != nil { return m.getBlockFn(num) } diff --git a/serve/handlers/block/types.go b/serve/handlers/block/types.go index 95f204b7..6558fb2a 100644 --- a/serve/handlers/block/types.go +++ b/serve/handlers/block/types.go @@ -6,5 +6,5 @@ import ( type Storage interface { // GetBlock returns specified block from permanent storage - GetBlock(int64) (*types.Block, error) + GetBlock(uint64) (*types.Block, error) } diff --git a/serve/handlers/tx/mocks_test.go b/serve/handlers/tx/mocks_test.go index 260b7a82..aaa5080c 100644 --- a/serve/handlers/tx/mocks_test.go +++ b/serve/handlers/tx/mocks_test.go @@ -2,13 +2,13 @@ package tx import "github.com/gnolang/gno/tm2/pkg/bft/types" -type getTxDelegate func(int64, uint32) (*types.TxResult, error) +type getTxDelegate func(uint64, uint32) (*types.TxResult, error) type mockStorage struct { getTxFn getTxDelegate } -func (m *mockStorage) GetTx(bn int64, ti uint32) (*types.TxResult, error) { +func (m *mockStorage) GetTx(bn uint64, ti uint32) (*types.TxResult, error) { if m.getTxFn != nil { return m.getTxFn(bn, ti) } diff --git a/serve/handlers/tx/tx.go b/serve/handlers/tx/tx.go index 0d3fd410..4e84d855 100644 --- a/serve/handlers/tx/tx.go +++ b/serve/handlers/tx/tx.go @@ -31,7 +31,7 @@ func (h *Handler) GetTxHandler( } // Extract the params - blockNum, ok := params[0].(int64) + blockNum, ok := params[0].(uint64) if !ok { return nil, spec.GenerateInvalidParamError(1) } @@ -60,7 +60,7 @@ func (h *Handler) GetTxHandler( } // getTx fetches the tx from storage, if any -func (h *Handler) getTx(blockNum int64, txIndex uint32) (*types.TxResult, error) { +func (h *Handler) getTx(blockNum uint64, txIndex uint32) (*types.TxResult, error) { tx, err := h.storage.GetTx(blockNum, txIndex) if errors.Is(err, storageErrors.ErrNotFound) { // Wrap the error diff --git a/serve/handlers/tx/tx_test.go b/serve/handlers/tx/tx_test.go index 2c9359d4..3351ebf2 100644 --- a/serve/handlers/tx/tx_test.go +++ b/serve/handlers/tx/tx_test.go @@ -56,11 +56,11 @@ func TestGetBlock_Handler(t *testing.T) { t.Parallel() var ( - blockNum = int64(42) + blockNum = uint64(42) txIndex = uint32(42) mockStorage = &mockStorage{ - getTxFn: func(bn int64, ti uint32) (*types.TxResult, error) { + getTxFn: func(bn uint64, ti uint32) (*types.TxResult, error) { require.Equal(t, blockNum, bn) require.Equal(t, txIndex, ti) @@ -82,13 +82,13 @@ func TestGetBlock_Handler(t *testing.T) { t.Parallel() var ( - blockNum = int64(42) + blockNum = uint64(42) txIndex = uint32(42) fetchErr = errors.New("random error") mockStorage = &mockStorage{ - getTxFn: func(_ int64, _ uint32) (*types.TxResult, error) { + getTxFn: func(_ uint64, _ uint32) (*types.TxResult, error) { return nil, fetchErr }, } @@ -110,7 +110,7 @@ func TestGetBlock_Handler(t *testing.T) { t.Parallel() var ( - blockNum = int64(42) + blockNum = uint64(42) txIndex = uint32(42) txResult = &types.TxResult{ @@ -118,7 +118,7 @@ func TestGetBlock_Handler(t *testing.T) { } mockStorage = &mockStorage{ - getTxFn: func(bn int64, ti uint32) (*types.TxResult, error) { + getTxFn: func(bn uint64, ti uint32) (*types.TxResult, error) { require.Equal(t, blockNum, bn) require.Equal(t, txIndex, ti) diff --git a/serve/handlers/tx/types.go b/serve/handlers/tx/types.go index 8e998a07..29d98058 100644 --- a/serve/handlers/tx/types.go +++ b/serve/handlers/tx/types.go @@ -4,5 +4,5 @@ import "github.com/gnolang/gno/tm2/pkg/bft/types" type Storage interface { // GetTx returns specified tx from permanent storage - GetTx(int64, uint32) (*types.TxResult, error) + GetTx(uint64, uint32) (*types.TxResult, error) } diff --git a/storage/encode.go b/storage/encode.go index 28c6d918..127872e5 100644 --- a/storage/encode.go +++ b/storage/encode.go @@ -4,34 +4,22 @@ import ( "bytes" "encoding/binary" "fmt" - "math" "unsafe" "github.com/gnolang/gno/tm2/pkg/amino" "github.com/gnolang/gno/tm2/pkg/bft/types" + "github.com/pkg/errors" ) const ( - bytesMarker byte = 0x12 - bytesDescMarker = bytesMarker + 1 - - // IntMin is chosen such that the range of int tags does not overlap the - // ascii character set that is frequently used in testing. - IntMin = 0x80 // 128 - intMaxWidth = 8 - intZero = IntMin + intMaxWidth // 136 - intSmall = IntMax - intZero - intMaxWidth // 109 - // IntMax is the maximum int tag value. - IntMax = 0xfd // 253 + bytesMarker byte = 0x12 // -> \x00\x01 // \x00 -> \x00\xff - escape byte = 0x00 - escapedTerm byte = 0x01 - escapedJSONObjectKeyTerm byte = 0x02 - escapedJSONArray byte = 0x03 - escaped00 byte = 0xff - escapedFF byte = 0x00 + escape byte = 0x00 + escapedTerm byte = 0x01 + escaped00 byte = 0xff + escapedFF byte = 0x00 ) type escapes struct { @@ -44,195 +32,77 @@ type escapes struct { var ascendingBytesEscapes = escapes{escape, escapedTerm, escaped00, escapedFF, bytesMarker} -// EncodeUint32Ascending encodes the uint32 value using a big-endian 4 byte +// encodeUint32Ascending encodes the uint32 value using a big-endian 4 byte // representation. The bytes are appended to the supplied buffer and // the final buffer is returned. -func EncodeUint32Ascending(b []byte, v uint32) []byte { +func encodeUint32Ascending(b []byte, v uint32) []byte { return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) } -// EncodeUint32Descending encodes the uint32 value so that it sorts in +// encodeUint32Descending encodes the uint32 value so that it sorts in // reverse order, from largest to smallest. -func EncodeUint32Descending(b []byte, v uint32) []byte { - return EncodeUint32Ascending(b, ^v) +func encodeUint32Descending(b []byte, v uint32) []byte { + return encodeUint32Ascending(b, ^v) } -// DecodeUint32Ascending decodes a uint32 from the input buffer, treating +// decodeUint32Ascending decodes a uint32 from the input buffer, treating // the input as a big-endian 4 byte uint32 representation. The remainder // of the input buffer and the decoded uint32 are returned. -func DecodeUint32Ascending(b []byte) ([]byte, uint32, error) { +func decodeUint32Ascending(b []byte) ([]byte, uint32, error) { if len(b) < 4 { return nil, 0, fmt.Errorf("insufficient bytes to decode uint32 int value") } - v := binary.BigEndian.Uint32(b) + v := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 return b[4:], v, nil } -// DecodeUint32Descending decodes a uint32 value which was encoded +// decodeUint32Descending decodes a uint32 value which was encoded // using EncodeUint32Descending. -func DecodeUint32Descending(b []byte) ([]byte, uint32, error) { - leftover, v, err := DecodeUint32Ascending(b) +func decodeUint32Descending(b []byte) ([]byte, uint32, error) { + leftover, v, err := decodeUint32Ascending(b) return leftover, ^v, err } -// EncodeVarintAscending encodes the int64 value using a variable length -// (length-prefixed) representation. The length is encoded as a single -// byte. If the value to be encoded is negative the length is encoded -// as 8-numBytes. If the value is positive it is encoded as -// 8+numBytes. The encoded bytes are appended to the supplied buffer -// and the final buffer is returned. -func EncodeVarintAscending(b []byte, v int64) []byte { - if v < 0 { - switch { - case v >= -0xff: - return append(b, IntMin+7, byte(v)) - case v >= -0xffff: - return append(b, IntMin+6, byte(v>>8), byte(v)) - case v >= -0xffffff: - return append(b, IntMin+5, byte(v>>16), byte(v>>8), byte(v)) - case v >= -0xffffffff: - return append(b, IntMin+4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) - case v >= -0xffffffffff: - return append(b, IntMin+3, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), - byte(v)) - case v >= -0xffffffffffff: - return append(b, IntMin+2, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), - byte(v>>8), byte(v)) - case v >= -0xffffffffffffff: - return append(b, IntMin+1, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), - byte(v>>16), byte(v>>8), byte(v)) - default: - return append(b, IntMin, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), - byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) - } - } - - return EncodeUvarintAscending(b, uint64(v)) -} - -// EncodeVarintDescending encodes the int64 value so that it sorts in reverse -// order, from largest to smallest. -func EncodeVarintDescending(b []byte, v int64) []byte { - return EncodeVarintAscending(b, ^v) -} - -// EncodeUvarintAscending encodes the uint64 value using a variable length -// (length-prefixed) representation. The length is encoded as a single -// byte indicating the number of encoded bytes (-8) to follow. See -// EncodeVarintAscending for rationale. The encoded bytes are appended to the -// supplied buffer and the final buffer is returned. -func EncodeUvarintAscending(b []byte, v uint64) []byte { - switch { - case v <= intSmall: - return append(b, intZero+byte(v)) - case v <= 0xff: - return append(b, IntMax-7, byte(v)) - case v <= 0xffff: - return append(b, IntMax-6, byte(v>>8), byte(v)) - case v <= 0xffffff: - return append(b, IntMax-5, byte(v>>16), byte(v>>8), byte(v)) - case v <= 0xffffffff: - return append(b, IntMax-4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) - case v <= 0xffffffffff: - return append(b, IntMax-3, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), - byte(v)) - case v <= 0xffffffffffff: - return append(b, IntMax-2, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), - byte(v>>8), byte(v)) - case v <= 0xffffffffffffff: - return append(b, IntMax-1, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), - byte(v>>16), byte(v>>8), byte(v)) - default: - return append(b, IntMax, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), - byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) - } +// encodeUint64Ascending encodes the uint64 value using a big-endian 8 byte +// representation. The bytes are appended to the supplied buffer and +// the final buffer is returned. +func encodeUint64Ascending(b []byte, v uint64) []byte { + return append(b, + byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), + byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) } -// DecodeVarintAscending decodes a value encoded by EncodeVarintAscending. -func DecodeVarintAscending(b []byte) ([]byte, int64, error) { - if len(b) == 0 { - return nil, 0, fmt.Errorf("insufficient bytes to decode varint value") - } - - length := int(b[0]) - intZero - if length < 0 { - length = -length - - remB := b[1:] - if len(remB) < length { - return nil, 0, fmt.Errorf("insufficient bytes to decode varint value: %q", remB) - } - - var v int64 - // Use the ones-complement of each encoded byte in order to build - // up a positive number, then take the ones-complement again to - // arrive at our negative value. - for _, t := range remB[:length] { - v = (v << 8) | int64(^t) - } - - return remB[length:], ^v, nil - } - - remB, v, err := DecodeUvarintAscending(b) - if err != nil { - return remB, 0, err - } - - if v > math.MaxInt64 { - return nil, 0, fmt.Errorf("varint %d overflows int64", v) - } - - return remB, int64(v), nil +// encodeUint64Descending encodes the uint64 value so that it sorts in +// reverse order, from largest to smallest. +func encodeUint64Descending(b []byte, v uint64) []byte { + return encodeUint64Ascending(b, ^v) } -// DecodeUvarintAscending decodes a uint64 encoded uint64 from the input -// buffer. The remainder of the input buffer and the decoded uint64 -// are returned. -func DecodeUvarintAscending(b []byte) ([]byte, uint64, error) { - if len(b) == 0 { - return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value") - } - - length := int(b[0]) - intZero - - b = b[1:] // skip length byte - if length <= intSmall { - return b, uint64(length), nil - } - - length -= intSmall - if length < 0 || length > 8 { - return nil, 0, fmt.Errorf("invalid uvarint length of %d", length) - } else if len(b) < length { - return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value: %q", b) +// decodeUint64Ascending decodes a uint64 from the input buffer, treating +// the input as a big-endian 8 byte uint64 representation. The remainder +// of the input buffer and the decoded uint64 are returned. +func decodeUint64Ascending(b []byte) ([]byte, uint64, error) { + if len(b) < 8 { + return nil, 0, errors.Errorf("insufficient bytes to decode uint64 int value") } - - var v uint64 - // It is faster to range over the elements in a slice than to index - // into the slice on each loop iteration. - for _, t := range b[:length] { - v = (v << 8) | uint64(t) - } - - return b[length:], v, nil + v := binary.BigEndian.Uint64(b) + return b[8:], v, nil } -// DecodeVarintDescending decodes a int64 value which was encoded -// using EncodeVarintDescending. -func DecodeVarintDescending(b []byte) ([]byte, int64, error) { - leftover, v, err := DecodeVarintAscending(b) - +// decodeUint64Descending decodes a uint64 value which was encoded +// using EncodeUint64Descending. +func decodeUint64Descending(b []byte) ([]byte, uint64, error) { + leftover, v, err := decodeUint64Ascending(b) return leftover, ^v, err } -// EncodeStringAscending encodes the string value using an escape-based encoding. See +// dncodeStringAscending encodes the string value using an escape-based encoding. See // EncodeBytes for details. The encoded bytes are append to the supplied buffer // and the resulting buffer is returned. -func EncodeStringAscending(b []byte, s string) []byte { +func encodeStringAscending(b []byte, s string) []byte { return encodeStringAscendingWithTerminatorAndPrefix(b, s, ascendingBytesEscapes.escapedTerm, bytesMarker) } @@ -243,7 +113,7 @@ func EncodeStringAscending(b []byte, s string) []byte { func encodeStringAscendingWithTerminatorAndPrefix( b []byte, s string, terminator byte, prefix byte, ) []byte { - unsafeString := UnsafeConvertStringToBytes(s) + unsafeString := unsafeConvertStringToBytes(s) return encodeBytesAscendingWithTerminatorAndPrefix(b, unsafeString, terminator, prefix) } @@ -292,11 +162,11 @@ func encodeBytesAscendingWithoutTerminatorOrPrefix(b, data []byte) []byte { return append(b, data...) } -// UnsafeConvertStringToBytes converts a string to a byte array to be used with +// unsafeConvertStringToBytes converts a string to a byte array to be used with // string encoding functions. Note that the output byte array should not be // modified if the input string is expected to be used again - doing so could // violate Go semantics. -func UnsafeConvertStringToBytes(s string) []byte { +func unsafeConvertStringToBytes(s string) []byte { // unsafe.StringData output is unspecified for empty string input so always // return nil. if s == "" { @@ -306,31 +176,31 @@ func UnsafeConvertStringToBytes(s string) []byte { return unsafe.Slice(unsafe.StringData(s), len(s)) } -// DecodeUnsafeStringAscending decodes a string value from the input buffer which was +// decodeUnsafeStringAscending decodes a string value from the input buffer which was // encoded using EncodeString or EncodeBytes. The r []byte is used as a // temporary buffer in order to avoid memory allocations. The remainder of the // input buffer and the decoded string are returned. Note that the returned // string may share storage with the input buffer. -func DecodeUnsafeStringAscending(b, r []byte) ([]byte, string, error) { - b, r, err := DecodeBytesAscending(b, r) +func decodeUnsafeStringAscending(b, r []byte) ([]byte, string, error) { + b, r, err := decodeBytesAscending(b, r) - return b, UnsafeConvertBytesToString(r), err + return b, unsafeConvertBytesToString(r), err } -// UnsafeConvertBytesToString performs an unsafe conversion from a []byte to a +// unsafeConvertBytesToString performs an unsafe conversion from a []byte to a // string. The returned string will share the underlying memory with the // []byte which thus allows the string to be mutable through the []byte. We're // careful to use this method only in situations in which the []byte will not // be modified. -func UnsafeConvertBytesToString(b []byte) string { +func unsafeConvertBytesToString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) } -// DecodeBytesAscending decodes a []byte value from the input buffer +// decodeBytesAscending decodes a []byte value from the input buffer // which was encoded using EncodeBytesAscending. The decoded bytes // are appended to r. The remainder of the input buffer and the // decoded []byte are returned. -func DecodeBytesAscending(b, r []byte) ([]byte, []byte, error) { +func decodeBytesAscending(b, r []byte) ([]byte, []byte, error) { return decodeBytesInternal(b, r, ascendingBytesEscapes, true /* expectMarker */, false /* deepCopy */) } diff --git a/storage/pebble.go b/storage/pebble.go index 3319410d..f46574ae 100644 --- a/storage/pebble.go +++ b/storage/pebble.go @@ -24,19 +24,19 @@ const ( prefixKeyTxs = "/data/txs/" ) -func keyTx(blockNum int64, txIndex uint32) []byte { - var key []byte - key = EncodeStringAscending(key, prefixKeyTxs) - key = EncodeVarintAscending(key, blockNum) - key = EncodeUint32Ascending(key, txIndex) +func keyTx(blockNum uint64, txIndex uint32) []byte { + key := make([]byte, len(prefixKeyTxs)+8+4) + key = encodeStringAscending(key, prefixKeyTxs) + key = encodeUint64Ascending(key, blockNum) + key = encodeUint32Ascending(key, txIndex) return key } -func keyBlock(blockNum int64) []byte { - var key []byte - key = EncodeStringAscending(key, prefixKeyBlocks) - key = EncodeVarintAscending(key, blockNum) +func keyBlock(blockNum uint64) []byte { + key := make([]byte, len(prefixKeyBlocks)+8) + key = encodeStringAscending(key, prefixKeyBlocks) + key = encodeUint64Ascending(key, blockNum) return key } @@ -64,7 +64,7 @@ func NewPebble(path string) (*Pebble, error) { } // GetLatestHeight fetches the latest saved height from storage -func (s *Pebble) GetLatestHeight() (int64, error) { +func (s *Pebble) GetLatestHeight() (uint64, error) { height, c, err := s.db.Get([]byte(keyLatestHeight)) if errors.Is(err, pebble.ErrNotFound) { return 0, storageErrors.ErrNotFound @@ -76,13 +76,13 @@ func (s *Pebble) GetLatestHeight() (int64, error) { defer c.Close() - _, val, err := DecodeVarintAscending(height) + _, val, err := decodeUint64Ascending(height) return val, err } // GetBlock fetches the specified block from storage, if any -func (s *Pebble) GetBlock(blockNum int64) (*types.Block, error) { +func (s *Pebble) GetBlock(blockNum uint64) (*types.Block, error) { block, c, err := s.db.Get(keyBlock(blockNum)) if errors.Is(err, pebble.ErrNotFound) { return nil, storageErrors.ErrNotFound @@ -98,8 +98,8 @@ func (s *Pebble) GetBlock(blockNum int64) (*types.Block, error) { } // GetTx fetches the specified tx result from storage, if any -func (s *Pebble) GetTx(blockNum int64, index uint32) (*types.TxResult, error) { - tx, c, err := s.db.Get(keyTx(blockNum, index)) +func (s *Pebble) GetTx(blockNum uint64, index uint32) (*types.TxResult, error) { + tx, c, err := s.db.Get(keyTx(uint64(blockNum), index)) if errors.Is(err, pebble.ErrNotFound) { return nil, storageErrors.ErrNotFound } @@ -113,7 +113,7 @@ func (s *Pebble) GetTx(blockNum int64, index uint32) (*types.TxResult, error) { return decodeTx(tx) } -func (s *Pebble) BlockIterator(fromBlockNum, toBlockNum int64) (Iterator[*types.Block], error) { +func (s *Pebble) BlockIterator(fromBlockNum, toBlockNum uint64) (Iterator[*types.Block], error) { fromKey := keyBlock(fromBlockNum) if toBlockNum == 0 { @@ -137,7 +137,7 @@ func (s *Pebble) BlockIterator(fromBlockNum, toBlockNum int64) (Iterator[*types. func (s *Pebble) TxIterator( fromBlockNum, - toBlockNum int64, + toBlockNum uint64, fromTxIndex, toTxIndex uint32, ) (Iterator[*types.TxResult], error) { @@ -237,21 +237,21 @@ func (pi *PebbleTxIter) Next() bool { var buf []byte - key, _, err := DecodeUnsafeStringAscending(pi.i.Key(), buf) + key, _, err := decodeUnsafeStringAscending(pi.i.Key(), buf) if err != nil { pi.nextError = err return false } - key, _, err = DecodeVarintAscending(key) + key, _, err = decodeUint64Ascending(key) if err != nil { pi.nextError = err return false } - _, txIdx, err := DecodeUint32Ascending(key) + _, txIdx, err := decodeUint32Ascending(key) if err != nil { pi.nextError = err @@ -286,9 +286,9 @@ type PebbleBatch struct { b *pebble.Batch } -func (b *PebbleBatch) SetLatestHeight(h int64) error { +func (b *PebbleBatch) SetLatestHeight(h uint64) error { var val []byte - val = EncodeVarintAscending(val, h) + val = encodeUint64Ascending(val, h) return b.b.Set([]byte(keyLatestHeight), val, pebble.NoSync) } @@ -299,7 +299,7 @@ func (b *PebbleBatch) SetBlock(block *types.Block) error { return err } - key := keyBlock(block.Height) + key := keyBlock(uint64(block.Height)) return b.b.Set( key, @@ -314,7 +314,7 @@ func (b *PebbleBatch) SetTx(tx *types.TxResult) error { return err } - key := keyTx(tx.Height, tx.Index) + key := keyTx(uint64(tx.Height), tx.Index) return b.b.Set( key, diff --git a/storage/pebble_test.go b/storage/pebble_test.go index 370c0c6b..eb26a686 100644 --- a/storage/pebble_test.go +++ b/storage/pebble_test.go @@ -39,7 +39,7 @@ func TestStorage_LatestHeight(t *testing.T) { require.EqualValues(t, 0, latest) // Save the latest height and grab it - for i := int64(0); i < 100; i++ { + for i := uint64(0); i < 100; i++ { b := s.WriteBatch() require.NoError(t, b.SetLatestHeight(i)) @@ -73,7 +73,7 @@ func TestStorage_Block(t *testing.T) { require.NoError(t, b.Commit()) for _, block := range blocks { - savedBlock, err := s.GetBlock(block.Height) + savedBlock, err := s.GetBlock(uint64(block.Height)) require.NoError(t, err) assert.Equal(t, block, savedBlock) } @@ -101,7 +101,7 @@ func TestStorage_Tx(t *testing.T) { require.NoError(t, wb.Commit()) for _, tx := range txs { - savedTx, err := s.GetTx(tx.Height, tx.Index) + savedTx, err := s.GetTx(uint64(tx.Height), tx.Index) require.NoError(t, err) assert.Equal(t, tx, savedTx) } diff --git a/storage/types.go b/storage/types.go index 127aeb40..006b4f70 100644 --- a/storage/types.go +++ b/storage/types.go @@ -17,20 +17,20 @@ type Storage interface { type Reader interface { io.Closer // GetLatestHeight returns the latest block height from the storage - GetLatestHeight() (int64, error) + GetLatestHeight() (uint64, error) // GetBlock fetches the block by its number - GetBlock(int64) (*types.Block, error) + GetBlock(uint64) (*types.Block, error) // GetTx fetches the tx using the block height and the transaction index - GetTx(blockNum int64, index uint32) (*types.TxResult, error) + GetTx(blockNum uint64, index uint32) (*types.TxResult, error) // BlockIterator iterates over Blocks, limiting the results to be between the provided block numbers - BlockIterator(fromBlockNum, toBlockNum int64) (Iterator[*types.Block], error) + BlockIterator(fromBlockNum, toBlockNum uint64) (Iterator[*types.Block], error) // TxIterator iterates over transactions, limiting the results to be between the provided block numbers // and transaction indexes - TxIterator(fromBlockNum, toBlockNum int64, fromTxIndex, toTxIndex uint32) (Iterator[*types.TxResult], error) + TxIterator(fromBlockNum, toBlockNum uint64, fromTxIndex, toTxIndex uint32) (Iterator[*types.TxResult], error) } type Iterator[T any] interface { @@ -50,7 +50,7 @@ type Writer interface { type Batch interface { // SetLatestHeight saves the latest block height to the storage - SetLatestHeight(int64) error + SetLatestHeight(uint64) error // SetBlock saves the block to the permanent storage SetBlock(block *types.Block) error // SetTx saves the transaction to the permanent storage From 02e2f95dd4217e67d84e460da6ca91f21e5d66e8 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Thu, 7 Mar 2024 16:38:30 +0100 Subject: [PATCH 06/13] Requested changes Signed-off-by: Antonio Navarro Perez --- serve/graph/resolver.go | 2 +- serve/graph/schema.resolvers.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/serve/graph/resolver.go b/serve/graph/resolver.go index 10e8dcbb..88b415ea 100644 --- a/serve/graph/resolver.go +++ b/serve/graph/resolver.go @@ -38,7 +38,7 @@ func dereferenceTime(i *time.Time) time.Time { return *i } -func handleChannel[T any](ctx context.Context, m *events.Manager, writeToChannel func(*types.NewBlock, chan T)) chan T { +func handleChannel[T any](ctx context.Context, m *events.Manager, writeToChannel func(*types.NewBlock, chan<- T)) <-chan T { ch := make(chan T) go func() { defer close(ch) diff --git a/serve/graph/schema.resolvers.go b/serve/graph/schema.resolvers.go index cb13c533..978088a7 100644 --- a/serve/graph/schema.resolvers.go +++ b/serve/graph/schema.resolvers.go @@ -127,7 +127,7 @@ func (r *queryResolver) LatestBlockHeight(ctx context.Context) (int, error) { // Transactions is the resolver for the transactions field. func (r *subscriptionResolver) Transactions(ctx context.Context) (<-chan *model.Transaction, error) { - return handleChannel[*model.Transaction](ctx, r.manager, func(nb *types.NewBlock, c chan *model.Transaction) { + return handleChannel(ctx, r.manager, func(nb *types.NewBlock, c chan<- *model.Transaction) { for _, tx := range nb.Results { c <- model.NewTransaction(tx) } @@ -136,7 +136,7 @@ func (r *subscriptionResolver) Transactions(ctx context.Context) (<-chan *model. // Blocks is the resolver for the blocks field. func (r *subscriptionResolver) Blocks(ctx context.Context) (<-chan *model.Block, error) { - return handleChannel[*model.Block](ctx, r.manager, func(nb *types.NewBlock, c chan *model.Block) { + return handleChannel(ctx, r.manager, func(nb *types.NewBlock, c chan<- *model.Block) { c <- model.NewBlock(nb.Block) }), nil } From 383b54cfffaa1718f5c243c1e1fb9b291696bbb2 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Thu, 7 Mar 2024 16:40:16 +0100 Subject: [PATCH 07/13] go mod tidy Signed-off-by: Antonio Navarro Perez --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 8098720b..64ede94c 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/madz-lab/insertion-queue v0.0.0-20230520191346-295d3348f63a github.com/olahol/melody v1.1.4 github.com/peterbourgon/ff/v3 v3.4.0 + github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.9.0 github.com/vektah/gqlparser/v2 v2.5.11 go.uber.org/multierr v1.11.0 @@ -50,7 +51,6 @@ require ( github.com/linxGnu/grocksdb v1.8.5 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.18.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect From ceaa5657c6cf0b05bbfd02442eb8adffe31ebca0 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Thu, 7 Mar 2024 17:49:31 +0100 Subject: [PATCH 08/13] Fix linter and remove key optimization Signed-off-by: Antonio Navarro Perez --- client/http.go | 2 ++ fetch/worker.go | 2 +- serve/graph/resolver.go | 6 +++++- serve/graph/schema.resolvers.go | 3 +-- storage/encode.go | 29 ++--------------------------- storage/pebble.go | 6 +++--- 6 files changed, 14 insertions(+), 34 deletions(-) diff --git a/client/http.go b/client/http.go index d155f7b9..561d29f8 100644 --- a/client/http.go +++ b/client/http.go @@ -39,6 +39,7 @@ func (c *Client) GetLatestBlockNumber() (uint64, error) { func (c *Client) GetBlock(blockNum uint64) (*core_types.ResultBlock, error) { bn := int64(blockNum) + block, err := c.client.Block(&bn) if err != nil { return nil, fmt.Errorf("unable to get block, %w", err) @@ -49,6 +50,7 @@ func (c *Client) GetBlock(blockNum uint64) (*core_types.ResultBlock, error) { func (c *Client) GetBlockResults(blockNum uint64) (*core_types.ResultBlockResults, error) { bn := int64(blockNum) + results, err := c.client.BlockResults(&bn) if err != nil { return nil, fmt.Errorf("unable to get block results, %w", err) diff --git a/fetch/worker.go b/fetch/worker.go index 63813406..66cb3d4d 100644 --- a/fetch/worker.go +++ b/fetch/worker.go @@ -108,7 +108,7 @@ func getBlocksSequentially(chunkRange chunkRange, client Client) ([]*types.Block for blockNum := chunkRange.from; blockNum <= chunkRange.to; blockNum++ { // Get block info from the chain - block, err := client.GetBlock(uint64(blockNum)) + block, err := client.GetBlock(blockNum) if err != nil { errs = append(errs, fmt.Errorf("unable to get block %d, %w", blockNum, err)) diff --git a/serve/graph/resolver.go b/serve/graph/resolver.go index 88b415ea..6176c127 100644 --- a/serve/graph/resolver.go +++ b/serve/graph/resolver.go @@ -38,7 +38,11 @@ func dereferenceTime(i *time.Time) time.Time { return *i } -func handleChannel[T any](ctx context.Context, m *events.Manager, writeToChannel func(*types.NewBlock, chan<- T)) <-chan T { +func handleChannel[T any]( + ctx context.Context, + m *events.Manager, + writeToChannel func(*types.NewBlock, chan<- T), +) <-chan T { ch := make(chan T) go func() { defer close(ch) diff --git a/serve/graph/schema.resolvers.go b/serve/graph/schema.resolvers.go index 978088a7..cd6dbd9b 100644 --- a/serve/graph/schema.resolvers.go +++ b/serve/graph/schema.resolvers.go @@ -8,10 +8,9 @@ import ( "context" "github.com/99designs/gqlgen/graphql" - "github.com/vektah/gqlparser/v2/gqlerror" - "github.com/gnolang/tx-indexer/serve/graph/model" "github.com/gnolang/tx-indexer/types" + "github.com/vektah/gqlparser/v2/gqlerror" ) // Transactions is the resolver for the transactions field. diff --git a/storage/encode.go b/storage/encode.go index 127872e5..9de6c241 100644 --- a/storage/encode.go +++ b/storage/encode.go @@ -39,12 +39,6 @@ func encodeUint32Ascending(b []byte, v uint32) []byte { return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) } -// encodeUint32Descending encodes the uint32 value so that it sorts in -// reverse order, from largest to smallest. -func encodeUint32Descending(b []byte, v uint32) []byte { - return encodeUint32Ascending(b, ^v) -} - // decodeUint32Ascending decodes a uint32 from the input buffer, treating // the input as a big-endian 4 byte uint32 representation. The remainder // of the input buffer and the decoded uint32 are returned. @@ -58,14 +52,6 @@ func decodeUint32Ascending(b []byte) ([]byte, uint32, error) { return b[4:], v, nil } -// decodeUint32Descending decodes a uint32 value which was encoded -// using EncodeUint32Descending. -func decodeUint32Descending(b []byte) ([]byte, uint32, error) { - leftover, v, err := decodeUint32Ascending(b) - - return leftover, ^v, err -} - // encodeUint64Ascending encodes the uint64 value using a big-endian 8 byte // representation. The bytes are appended to the supplied buffer and // the final buffer is returned. @@ -75,12 +61,6 @@ func encodeUint64Ascending(b []byte, v uint64) []byte { byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) } -// encodeUint64Descending encodes the uint64 value so that it sorts in -// reverse order, from largest to smallest. -func encodeUint64Descending(b []byte, v uint64) []byte { - return encodeUint64Ascending(b, ^v) -} - // decodeUint64Ascending decodes a uint64 from the input buffer, treating // the input as a big-endian 8 byte uint64 representation. The remainder // of the input buffer and the decoded uint64 are returned. @@ -88,15 +68,10 @@ func decodeUint64Ascending(b []byte) ([]byte, uint64, error) { if len(b) < 8 { return nil, 0, errors.Errorf("insufficient bytes to decode uint64 int value") } + v := binary.BigEndian.Uint64(b) - return b[8:], v, nil -} -// decodeUint64Descending decodes a uint64 value which was encoded -// using EncodeUint64Descending. -func decodeUint64Descending(b []byte) ([]byte, uint64, error) { - leftover, v, err := decodeUint64Ascending(b) - return leftover, ^v, err + return b[8:], v, nil } // dncodeStringAscending encodes the string value using an escape-based encoding. See diff --git a/storage/pebble.go b/storage/pebble.go index f46574ae..ec8d3c25 100644 --- a/storage/pebble.go +++ b/storage/pebble.go @@ -25,7 +25,7 @@ const ( ) func keyTx(blockNum uint64, txIndex uint32) []byte { - key := make([]byte, len(prefixKeyTxs)+8+4) + var key []byte key = encodeStringAscending(key, prefixKeyTxs) key = encodeUint64Ascending(key, blockNum) key = encodeUint32Ascending(key, txIndex) @@ -34,7 +34,7 @@ func keyTx(blockNum uint64, txIndex uint32) []byte { } func keyBlock(blockNum uint64) []byte { - key := make([]byte, len(prefixKeyBlocks)+8) + var key []byte key = encodeStringAscending(key, prefixKeyBlocks) key = encodeUint64Ascending(key, blockNum) @@ -99,7 +99,7 @@ func (s *Pebble) GetBlock(blockNum uint64) (*types.Block, error) { // GetTx fetches the specified tx result from storage, if any func (s *Pebble) GetTx(blockNum uint64, index uint32) (*types.TxResult, error) { - tx, c, err := s.db.Get(keyTx(uint64(blockNum), index)) + tx, c, err := s.db.Get(keyTx(blockNum, index)) if errors.Is(err, pebble.ErrNotFound) { return nil, storageErrors.ErrNotFound } From f4b0716373b5a3a3eaf842c5cf0265cdef926fd7 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 13 Mar 2024 15:54:05 +0100 Subject: [PATCH 09/13] Requested changes Signed-off-by: Antonio Navarro Perez --- tools.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools.go b/tools.go index fcdeac47..ad3c7f9b 100644 --- a/tools.go +++ b/tools.go @@ -1,5 +1,4 @@ -//go:build tools -// +build tools +// go:build tools package tools From 7ba9e8867f9a44bdf300791577e697b587772ace Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Thu, 14 Mar 2024 16:01:59 +0100 Subject: [PATCH 10/13] dereference time Signed-off-by: Antonio Navarro Perez --- serve/graph/schema.resolvers.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/serve/graph/schema.resolvers.go b/serve/graph/schema.resolvers.go index cd6dbd9b..8b8ddf8b 100644 --- a/serve/graph/schema.resolvers.go +++ b/serve/graph/schema.resolvers.go @@ -8,9 +8,10 @@ import ( "context" "github.com/99designs/gqlgen/graphql" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/gnolang/tx-indexer/serve/graph/model" "github.com/gnolang/tx-indexer/types" - "github.com/vektah/gqlparser/v2/gqlerror" ) // Transactions is the resolver for the transactions field. @@ -82,8 +83,6 @@ func (r *queryResolver) Blocks(ctx context.Context, filter model.BlockFilter) ([ } defer it.Close() - dft := dereferenceTime(filter.FromTime) - var out []*model.Block i := 0 @@ -108,7 +107,10 @@ func (r *queryResolver) Blocks(ctx context.Context, filter model.BlockFilter) ([ return out, nil } - if !((b.Time.After(dft) || b.Time.Equal(dft)) && (filter.ToTime == nil || b.Time.Before(*filter.ToTime))) { + dft := dereferenceTime(filter.FromTime) + dtt := dereferenceTime(filter.ToTime) + + if !((b.Time.After(dft) || b.Time.Equal(dft)) && (dtt.IsZero() || b.Time.Before(dtt))) { continue } From 05edf241c5080c5edabaa59102c0afd65913476c Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Mon, 18 Mar 2024 11:08:08 +0100 Subject: [PATCH 11/13] Rollback tag to avoid errors when testing Signed-off-by: Antonio Navarro Perez --- tools.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools.go b/tools.go index ad3c7f9b..fcdeac47 100644 --- a/tools.go +++ b/tools.go @@ -1,4 +1,5 @@ -// go:build tools +//go:build tools +// +build tools package tools From c5eb603d95c2aacbea6e6236bc6003944a82198b Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Mon, 18 Mar 2024 11:40:49 +0100 Subject: [PATCH 12/13] Requested changes. Signed-off-by: Antonio Navarro Perez --- serve/graph/resolver.go | 21 +++++--------------- serve/graph/schema.graphql | 2 +- serve/graph/schema.resolvers.go | 35 ++++++++++++++++++++------------- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/serve/graph/resolver.go b/serve/graph/resolver.go index 6176c127..328b9ca9 100644 --- a/serve/graph/resolver.go +++ b/serve/graph/resolver.go @@ -5,7 +5,6 @@ package graph import ( "context" "fmt" - "time" "github.com/99designs/gqlgen/graphql" @@ -20,22 +19,12 @@ import ( const maxElementsPerQuery = 10000 -func dereferenceInt(i *int) int { - if i == nil { - return 0 +func deref[T any](v *T) T { + if v == nil { + var zero T + return zero } - - return *i -} - -func dereferenceTime(i *time.Time) time.Time { - if i == nil { - var t time.Time - - return t - } - - return *i + return *v } func handleChannel[T any]( diff --git a/serve/graph/schema.graphql b/serve/graph/schema.graphql index 6191ced3..53a43b9f 100644 --- a/serve/graph/schema.graphql +++ b/serve/graph/schema.graphql @@ -56,7 +56,7 @@ type Transaction { """ The actual amount of computational effort consumed to execute this Transaction. It could be less or equal to `gas_wanted`. """ - gas_used: Int! + gas_used: Int! """ The payload of the Transaction in a raw format, typically containing the instructions and any data necessary for execution. diff --git a/serve/graph/schema.resolvers.go b/serve/graph/schema.resolvers.go index 8b8ddf8b..16f24a75 100644 --- a/serve/graph/schema.resolvers.go +++ b/serve/graph/schema.resolvers.go @@ -6,6 +6,7 @@ package graph import ( "context" + "math" "github.com/99designs/gqlgen/graphql" "github.com/vektah/gqlparser/v2/gqlerror" @@ -19,20 +20,26 @@ func (r *queryResolver) Transactions(ctx context.Context, filter model.Transacti it, err := r. store. TxIterator( - uint64(dereferenceInt(filter.FromBlockHeight)), - uint64(dereferenceInt(filter.ToBlockHeight)), - uint32(dereferenceInt(filter.FromIndex)), - uint32(dereferenceInt(filter.ToIndex)), + uint64(deref(filter.FromBlockHeight)), + uint64(deref(filter.ToBlockHeight)), + uint32(deref(filter.FromIndex)), + uint32(deref(filter.ToIndex)), ) if err != nil { return nil, gqlerror.Wrap(err) } defer it.Close() - fgw := dereferenceInt(filter.FromGasUsed) - tgw := dereferenceInt(filter.ToGasWanted) - fgu := dereferenceInt(filter.FromGasUsed) - tgu := dereferenceInt(filter.ToGasUsed) + fgw := deref(filter.FromGasUsed) + tgw := deref(filter.ToGasWanted) + if tgw == 0 { + tgw = math.MaxInt + } + fgu := deref(filter.FromGasUsed) + tgu := deref(filter.ToGasUsed) + if tgu == 0 { + tgu = math.MaxInt + } var out []*model.Transaction i := 0 @@ -57,10 +64,10 @@ func (r *queryResolver) Transactions(ctx context.Context, filter model.Transacti return out, nil } - if !(t.Response.GasUsed >= int64(fgu) && (tgu == 0 || t.Response.GasUsed <= int64(tgu))) { + if !(t.Response.GasUsed >= int64(fgu) && (t.Response.GasUsed <= int64(tgu))) { continue } - if !(t.Response.GasWanted >= int64(fgw) && (tgw == 0 || t.Response.GasWanted <= int64(tgw))) { + if !(t.Response.GasWanted >= int64(fgw) && (t.Response.GasWanted <= int64(tgw))) { continue } @@ -75,8 +82,8 @@ func (r *queryResolver) Blocks(ctx context.Context, filter model.BlockFilter) ([ it, err := r. store. BlockIterator( - uint64(dereferenceInt(filter.FromHeight)), - uint64(dereferenceInt(filter.ToHeight)), + uint64(deref(filter.FromHeight)), + uint64(deref(filter.ToHeight)), ) if err != nil { return nil, gqlerror.Wrap(err) @@ -107,8 +114,8 @@ func (r *queryResolver) Blocks(ctx context.Context, filter model.BlockFilter) ([ return out, nil } - dft := dereferenceTime(filter.FromTime) - dtt := dereferenceTime(filter.ToTime) + dft := deref(filter.FromTime) + dtt := deref(filter.ToTime) if !((b.Time.After(dft) || b.Time.Equal(dft)) && (dtt.IsZero() || b.Time.Before(dtt))) { continue From 72b29dab735108eb6d827f92cdcdd88ed6bfa1ca Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Mon, 18 Mar 2024 11:43:13 +0100 Subject: [PATCH 13/13] linter Signed-off-by: Antonio Navarro Perez --- serve/graph/resolver.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/serve/graph/resolver.go b/serve/graph/resolver.go index 328b9ca9..8241fc3b 100644 --- a/serve/graph/resolver.go +++ b/serve/graph/resolver.go @@ -22,8 +22,10 @@ const maxElementsPerQuery = 10000 func deref[T any](v *T) T { if v == nil { var zero T + return zero } + return *v }