forked from cerc-io/ipld-eth-server
Compare commits
74
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
000c0ef066 | ||
|
|
e00e602098 | ||
|
|
148addb24d | ||
|
|
2630e2d8dc | ||
|
|
924d0be0b9 | ||
|
|
70f7face75 | ||
|
|
afc63ac960 | ||
|
|
f1a61d0991 | ||
|
|
9a5581b543 | ||
|
|
1d18d1fed8 | ||
|
|
0a14bd9f0f | ||
|
|
a3ca08b653 | ||
|
|
b2828a814f | ||
|
|
a284a566d5 | ||
|
|
b90fcb53e6 | ||
|
|
18266c4f9d | ||
|
|
42f066772b | ||
|
|
9aaea6e016 | ||
|
|
969da82f6e | ||
|
|
f7fe3c2fc1 | ||
|
|
c4f7fa2821 | ||
|
|
b1a6fb0514 | ||
|
|
e7744cce4b | ||
|
|
491d779d58 | ||
|
|
2c1bc557e5 | ||
|
|
9cf75ca66c | ||
|
|
3b3716499f | ||
|
|
b3ef2934b7 | ||
|
|
8c16dc2b35 | ||
|
|
7babaf6c05 | ||
|
|
954e028306 | ||
|
|
6844c60f7b | ||
|
|
97d8c4dc86 | ||
|
|
1141f3909c | ||
|
|
c62799fdd6 | ||
|
|
cef4b1ddc6 | ||
|
|
39141bd30d | ||
|
|
0aa0f38c93 | ||
|
|
8ac6d48772 | ||
|
|
bcbd2de5f3 | ||
|
|
d09b756768 | ||
|
|
36b62f9b72 | ||
|
|
9b960a105f | ||
|
|
2e5286baef | ||
|
|
f8b9d9475e | ||
|
|
9d590e15bc | ||
|
|
d5cf74e202 | ||
|
|
7d88e78fa8 | ||
|
|
9d6791706d | ||
|
|
50d53535bb | ||
|
|
c813ff00f4 | ||
|
|
53f06a66f5 | ||
|
|
3c57fa1064 | ||
|
|
141b3eaffe | ||
|
|
31cbaec567 | ||
|
|
75debec01a | ||
|
|
07519468e9 | ||
|
|
524ab42674 | ||
|
|
325516da70 | ||
|
|
08df7beca3 | ||
|
|
f4ff261b21 | ||
|
|
aff66d950b | ||
|
|
677cdf0a72 | ||
|
|
72e830e164 | ||
|
|
6b919a8734 | ||
|
|
86aa1c16e6 | ||
|
|
4ea61b08ca | ||
|
|
88e499e5d3 | ||
|
|
df454c414e | ||
|
|
5200fd71dc | ||
|
|
86f3f44cac | ||
|
|
f6780ddd95 | ||
|
|
8d10dc98ee | ||
|
|
d3f30b621b |
@@ -11,7 +11,7 @@ jobs:
|
|||||||
- name: Run docker build
|
- name: Run docker build
|
||||||
run: make docker-build
|
run: make docker-build
|
||||||
test:
|
test:
|
||||||
name: Run integration tests
|
name: Run unit tests
|
||||||
env:
|
env:
|
||||||
GOPATH: /tmp/go
|
GOPATH: /tmp/go
|
||||||
strategy:
|
strategy:
|
||||||
@@ -33,3 +33,28 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sleep 10
|
sleep 10
|
||||||
PGPASSWORD=password DATABASE_USER=vdbm DATABASE_PORT=8077 DATABASE_PASSWORD=password DATABASE_HOSTNAME=127.0.0.1 make test
|
PGPASSWORD=password DATABASE_USER=vdbm DATABASE_PORT=8077 DATABASE_PASSWORD=password DATABASE_HOSTNAME=127.0.0.1 make test
|
||||||
|
|
||||||
|
integrationtest:
|
||||||
|
name: Run integration tests
|
||||||
|
env:
|
||||||
|
GOPATH: /tmp/go
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go-version: [1.15.x]
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Create GOPATH
|
||||||
|
run: mkdir -p /tmp/go
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go-version }}
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Run database
|
||||||
|
run: docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8081)" != "200" ]; do echo "waiting for ipld-eth-server..." && sleep 5; done && \
|
||||||
|
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8545)" != "200" ]; do echo "waiting for geth-statediff..." && sleep 5; done && \
|
||||||
|
make integrationtest
|
||||||
|
|||||||
+11
-2
@@ -6,8 +6,17 @@ RUN apk add busybox-extras
|
|||||||
|
|
||||||
# Build ipld-eth-server
|
# Build ipld-eth-server
|
||||||
WORKDIR /go/src/github.com/vulcanize/ipld-eth-server
|
WORKDIR /go/src/github.com/vulcanize/ipld-eth-server
|
||||||
ADD . .
|
|
||||||
RUN GO111MODULE=on GCO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o ipld-eth-server .
|
# Cache the modules
|
||||||
|
ENV GO111MODULE=on
|
||||||
|
COPY go.mod .
|
||||||
|
COPY go.sum .
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the binary
|
||||||
|
RUN GCO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o ipld-eth-server .
|
||||||
|
|
||||||
# Copy migration tool
|
# Copy migration tool
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|||||||
@@ -61,39 +61,25 @@ test: | $(GINKGO) $(GOOSE)
|
|||||||
dropdb -h $(DATABASE_HOSTNAME) -p $(DATABASE_PORT) -U $(DATABASE_USER) --if-exists $(TEST_DB)
|
dropdb -h $(DATABASE_HOSTNAME) -p $(DATABASE_PORT) -U $(DATABASE_USER) --if-exists $(TEST_DB)
|
||||||
createdb -h $(DATABASE_HOSTNAME) -p $(DATABASE_PORT) -U $(DATABASE_USER) $(TEST_DB)
|
createdb -h $(DATABASE_HOSTNAME) -p $(DATABASE_PORT) -U $(DATABASE_USER) $(TEST_DB)
|
||||||
$(GOOSE) -dir db/migrations postgres "$(TEST_CONNECT_STRING)" up
|
$(GOOSE) -dir db/migrations postgres "$(TEST_CONNECT_STRING)" up
|
||||||
$(GINKGO) -r --skipPackage=integration_tests,integration
|
$(GINKGO) -r --skipPackage=test
|
||||||
|
|
||||||
.PHONY: integrationtest
|
.PHONY: integrationtest
|
||||||
integrationtest: | $(GINKGO) $(GOOSE)
|
integrationtest: | $(GINKGO) $(GOOSE)
|
||||||
go vet ./...
|
go vet ./...
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
export PGPASSWORD=$(DATABASE_PASSWORD)
|
$(GINKGO) -r test/ -v
|
||||||
dropdb -h $(DATABASE_HOSTNAME) -p $(DATABASE_PORT) -U $(DATABASE_USER) --if-exists $(TEST_DB)
|
|
||||||
createdb -h $(DATABASE_HOSTNAME) -p $(DATABASE_PORT) -U $(DATABASE_USER) $(TEST_DB)
|
|
||||||
$(GOOSE) -dir db/migrations postgres "$(TEST_CONNECT_STRING)" up
|
|
||||||
$(GINKGO) -r integration_test/
|
|
||||||
|
|
||||||
.PHONY: test_local
|
.PHONY: test_local
|
||||||
test_local: | $(GINKGO) $(GOOSE)
|
test_local: | $(GINKGO) $(GOOSE)
|
||||||
go vet ./...
|
go vet ./...
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
dropdb -h $(HOST_NAME) -p $(PORT) -U $(USER) --if-exists $(TEST_DB)
|
./scripts/run_unit_test.sh
|
||||||
createdb -h $(HOST_NAME) -p $(PORT) -U $(USER) $(TEST_DB)
|
|
||||||
$(GOOSE) -dir db/migrations postgres "$(TEST_CONNECT_STRING_LOCAL)" up
|
|
||||||
$(GOOSE) -dir db/migrations postgres "$(TEST_CONNECT_STRING_LOCAL)" reset
|
|
||||||
make migrate NAME=$(TEST_DB)
|
|
||||||
$(GINKGO) -r --skipPackage=integration_tests,integration
|
|
||||||
|
|
||||||
.PHONY: integrationtest_local
|
.PHONY: integrationtest_local
|
||||||
integrationtest_local: | $(GINKGO) $(GOOSE)
|
integrationtest_local: | $(GINKGO) $(GOOSE)
|
||||||
go vet ./...
|
go vet ./...
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
dropdb -h $(HOST_NAME) -p $(PORT) -U $(USER) --if-exists $(TEST_DB)
|
./scripts/run_intregration_test.sh
|
||||||
createdb -h $(HOST_NAME) -p $(PORT) -U $(USER) $(TEST_DB)
|
|
||||||
$(GOOSE) -dir db/migrations postgres "$(TEST_CONNECT_STRING_LOCAL)" up
|
|
||||||
$(GOOSE) -dir db/migrations postgres "$(TEST_CONNECT_STRING_LOCAL)" reset
|
|
||||||
make migrate NAME=$(TEST_DB)
|
|
||||||
$(GINKGO) -r integration_test/
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
|
|||||||
@@ -121,6 +121,32 @@ The currently supported standard endpoints are:
|
|||||||
|
|
||||||
TODO: Add the rest of the standard endpoints and unique endpoints (e.g. getSlice)
|
TODO: Add the rest of the standard endpoints and unique endpoints (e.g. getSlice)
|
||||||
|
|
||||||
|
|
||||||
|
### CLI Options and Environment variables
|
||||||
|
|
||||||
|
|
||||||
|
| CLI Option | Environment Variable | Default Value | Comment |
|
||||||
|
| ----------------------------- | ----------------------------- | ---------------- | ----------------------------------- |
|
||||||
|
| `database-hostname` | `DATABASE_HOSTNAME` | localhost | IPLD database host |
|
||||||
|
| `database-port` | `DATABASE_PORT` | 5432 | IPLD database port |
|
||||||
|
| `database-name` | `DATABASE_NAME` | vulcanize_public | IPLD database name |
|
||||||
|
| `database-user` | `DATABASE_USER` | | IPLD database user |
|
||||||
|
| `database-password` | `DATABASE_PASSWORD` | | IPLD database password |
|
||||||
|
| `eth-server-graphql` | `ETH_SERVER_GRAPHQL` | false | If `true` enable Eth GraphQL Server |
|
||||||
|
| `eth-server-graphql-path` | `ETH_SERVER_GRAPHQLPATH` | | If `eth-server-graphql` set to true, endpoint url for graphql server (host:port) |
|
||||||
|
| `eth-server-http` | `ETH_SERVER_HTTP` | true | If `true` enable Eth HTTP JSON-RPC Server |
|
||||||
|
| `eth-server-http-path` | `ETH_SERVER_HTTPPATH` | | If `eth-server-http` set to `true`, endpoint url for Eth HTTP JSON-RPC server (host:port) |
|
||||||
|
| `eth-server-ws` | `ETH_SERVER_WS` | false | If `true` enable Eth WS JSON-RPC Server |
|
||||||
|
| `eth-server-ws-path` | `ETH_SERVER_WSPATH` | | If `eth-server-ws` set to `true`, endpoint url for Eth WS JSON-RPC server (host:port) |
|
||||||
|
| `eth-server-ipc` | `ETH_SERVER_IPC` | false | If `true` enable Eth IPC JSON-RPC Server |
|
||||||
|
| `eth-server-ipc-path` | `ETH_SERVER_IPC_PATH` | | If `eth-server-ws` set to `true`, path for Eth IPC JSON-RPC server |
|
||||||
|
| `ipld-server-graphql` | `IPLD_SERVER_GRAPHQL` | false | If `true` enable IPLD GraphQL Server |
|
||||||
|
| `ipld-server-graphql-path` | `IPLD_SERVER_GRAPHQLPATH` | | If `ipld-server-graphql` set to true, endpoint url for graphql server (host:port) |
|
||||||
|
| `ipld-postgraphile-path` | `IPLD_POSTGRAPHILEPATH` | | If `ipld-server-graphql` set to true, http url for postgraphile server on top of IPLD db |
|
||||||
|
| `tracing-http-path` | `TRACING_HTTPPATH` | | If `ipld-server-graphql` set to true, http url for tracing server |
|
||||||
|
| `tracing-postgraphile-path` | `TRACING.POSTGRAPHILEPATH` | | If `ipld-server-graphql` set to true, http url for postgraphile server on top of tracing db |
|
||||||
|
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
`make test` will run the unit tests
|
`make test` will run the unit tests
|
||||||
`make test` setups a clean `vulcanize_testing` db
|
`make test` setups a clean `vulcanize_testing` db
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"chainId": 4,
|
||||||
|
"homesteadBlock": 1,
|
||||||
|
"eip150Block": 2,
|
||||||
|
"eip150Hash": "0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9",
|
||||||
|
"eip155Block": 3,
|
||||||
|
"eip158Block": 3,
|
||||||
|
"byzantiumBlock": 3,
|
||||||
|
"constantinopleBlock": 3,
|
||||||
|
"petersburgBlock": 3,
|
||||||
|
"istanbulBlock": 3,
|
||||||
|
"clique": {
|
||||||
|
"period": 15,
|
||||||
|
"epoch": 30000
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-10
@@ -99,11 +99,7 @@ func init() {
|
|||||||
viper.AutomaticEnv()
|
viper.AutomaticEnv()
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file location")
|
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file location")
|
||||||
rootCmd.PersistentFlags().String("database-name", "vulcanize_public", "database name")
|
|
||||||
rootCmd.PersistentFlags().Int("database-port", 5432, "database port")
|
|
||||||
rootCmd.PersistentFlags().String("database-hostname", "localhost", "database hostname")
|
|
||||||
rootCmd.PersistentFlags().String("database-user", "", "database user")
|
|
||||||
rootCmd.PersistentFlags().String("database-password", "", "database password")
|
|
||||||
rootCmd.PersistentFlags().String("client-ipcPath", "", "location of geth.ipc file")
|
rootCmd.PersistentFlags().String("client-ipcPath", "", "location of geth.ipc file")
|
||||||
rootCmd.PersistentFlags().String("log-level", log.InfoLevel.String(), "log level (trace, debug, info, warn, error, fatal, panic)")
|
rootCmd.PersistentFlags().String("log-level", log.InfoLevel.String(), "log level (trace, debug, info, warn, error, fatal, panic)")
|
||||||
rootCmd.PersistentFlags().String("log-file", "", "file path for logging")
|
rootCmd.PersistentFlags().String("log-file", "", "file path for logging")
|
||||||
@@ -114,11 +110,6 @@ func init() {
|
|||||||
rootCmd.PersistentFlags().String("prom-http-addr", "127.0.0.1", "http host for prometheus")
|
rootCmd.PersistentFlags().String("prom-http-addr", "127.0.0.1", "http host for prometheus")
|
||||||
rootCmd.PersistentFlags().String("prom-http-port", "8090", "http port for prometheus")
|
rootCmd.PersistentFlags().String("prom-http-port", "8090", "http port for prometheus")
|
||||||
|
|
||||||
viper.BindPFlag("database.name", rootCmd.PersistentFlags().Lookup("database-name"))
|
|
||||||
viper.BindPFlag("database.port", rootCmd.PersistentFlags().Lookup("database-port"))
|
|
||||||
viper.BindPFlag("database.hostname", rootCmd.PersistentFlags().Lookup("database-hostname"))
|
|
||||||
viper.BindPFlag("database.user", rootCmd.PersistentFlags().Lookup("database-user"))
|
|
||||||
viper.BindPFlag("database.password", rootCmd.PersistentFlags().Lookup("database-password"))
|
|
||||||
viper.BindPFlag("log.level", rootCmd.PersistentFlags().Lookup("log-level"))
|
viper.BindPFlag("log.level", rootCmd.PersistentFlags().Lookup("log-level"))
|
||||||
viper.BindPFlag("log.file", rootCmd.PersistentFlags().Lookup("log-file"))
|
viper.BindPFlag("log.file", rootCmd.PersistentFlags().Lookup("log-file"))
|
||||||
|
|
||||||
|
|||||||
+179
-31
@@ -16,24 +16,29 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-server/pkg/graphql"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/vulcanize/gap-filler/pkg/mux"
|
||||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||||
|
"github.com/vulcanize/ipld-eth-server/pkg/graphql"
|
||||||
srpc "github.com/vulcanize/ipld-eth-server/pkg/rpc"
|
srpc "github.com/vulcanize/ipld-eth-server/pkg/rpc"
|
||||||
s "github.com/vulcanize/ipld-eth-server/pkg/serve"
|
s "github.com/vulcanize/ipld-eth-server/pkg/serve"
|
||||||
v "github.com/vulcanize/ipld-eth-server/version"
|
v "github.com/vulcanize/ipld-eth-server/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrNoRpcEndpoints = errors.New("no rpc endpoints is available")
|
||||||
|
|
||||||
// serveCmd represents the serve command
|
// serveCmd represents the serve command
|
||||||
var serveCmd = &cobra.Command{
|
var serveCmd = &cobra.Command{
|
||||||
Use: "serve",
|
Use: "serve",
|
||||||
@@ -71,7 +76,12 @@ func serve() {
|
|||||||
if err := startServers(server, serverConfig); err != nil {
|
if err := startServers(server, serverConfig); err != nil {
|
||||||
logWithCommand.Fatal(err)
|
logWithCommand.Fatal(err)
|
||||||
}
|
}
|
||||||
graphQL, err := startGraphQL(server)
|
graphQL, err := startEthGraphQL(server, serverConfig)
|
||||||
|
if err != nil {
|
||||||
|
logWithCommand.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = startIpldGraphQL(serverConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logWithCommand.Fatal(err)
|
logWithCommand.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -87,27 +97,43 @@ func serve() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startServers(server s.Server, settings *s.Config) error {
|
func startServers(server s.Server, settings *s.Config) error {
|
||||||
logWithCommand.Info("starting up IPC server")
|
if settings.IPCEnabled {
|
||||||
_, _, err := srpc.StartIPCEndpoint(settings.IPCEndpoint, server.APIs())
|
logWithCommand.Info("starting up IPC server")
|
||||||
if err != nil {
|
_, _, err := srpc.StartIPCEndpoint(settings.IPCEndpoint, server.APIs())
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logWithCommand.Info("IPC server is disabled")
|
||||||
}
|
}
|
||||||
logWithCommand.Info("starting up WS server")
|
|
||||||
_, _, err = srpc.StartWSEndpoint(settings.WSEndpoint, server.APIs(), []string{"vdb"}, nil, true)
|
if settings.WSEnabled {
|
||||||
if err != nil {
|
logWithCommand.Info("starting up WS server")
|
||||||
return err
|
_, _, err := srpc.StartWSEndpoint(settings.WSEndpoint, server.APIs(), []string{"vdb", "net"}, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logWithCommand.Info("WS server is disabled")
|
||||||
}
|
}
|
||||||
logWithCommand.Info("starting up HTTP server")
|
|
||||||
_, err = srpc.StartHTTPEndpoint(settings.HTTPEndpoint, server.APIs(), []string{"eth"}, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
if settings.HTTPEnabled {
|
||||||
return err
|
logWithCommand.Info("starting up HTTP server")
|
||||||
|
_, err := srpc.StartHTTPEndpoint(settings.HTTPEndpoint, server.APIs(), []string{"eth", "net"}, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logWithCommand.Info("HTTP server is disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startGraphQL(server s.Server) (graphQLServer *graphql.Service, err error) {
|
func startEthGraphQL(server s.Server, settings *s.Config) (graphQLServer *graphql.Service, err error) {
|
||||||
viper.BindEnv("server.graphql", "SERVER_GRAPHQL")
|
if settings.EthGraphqlEnabled {
|
||||||
if viper.GetBool("server.graphql") {
|
logWithCommand.Info("starting up ETH GraphQL server")
|
||||||
logWithCommand.Info("starting up GraphQL server")
|
endPoint := settings.EthGraphqlEndpoint
|
||||||
viper.BindEnv("server.graphqlEndpoint", "SERVER_GRAPHQL_ENDPOINT")
|
|
||||||
endPoint := viper.GetString("server.graphqlEndpoint")
|
|
||||||
if endPoint != "" {
|
if endPoint != "" {
|
||||||
graphQLServer, err = graphql.New(server.Backend(), endPoint, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
graphQLServer, err = graphql.New(server.Backend(), endPoint, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -115,19 +141,113 @@ func startGraphQL(server s.Server) (graphQLServer *graphql.Service, err error) {
|
|||||||
}
|
}
|
||||||
err = graphQLServer.Start(nil)
|
err = graphQLServer.Start(nil)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logWithCommand.Info("ETH GraphQL server is disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func startIpldGraphQL(settings *s.Config) error {
|
||||||
|
if settings.IpldGraphqlEnabled {
|
||||||
|
logWithCommand.Info("starting up IPLD GraphQL server")
|
||||||
|
|
||||||
|
gqlIpldAddr, err := url.Parse(settings.IpldPostgraphileEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
gqlTracingAPIAddr, err := url.Parse(settings.TracingPostgraphileEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ethClients, err := parseRpcAddresses(settings.EthHttpEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tracingClients []*rpc.Client
|
||||||
|
tracingEndpoint := viper.GetString("tracing.httpPath")
|
||||||
|
if tracingEndpoint != "" {
|
||||||
|
tracingClients, err = parseRpcAddresses(tracingEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
router, err := mux.NewServeMux(&mux.Options{
|
||||||
|
BasePath: "/",
|
||||||
|
EnableGraphiQL: true,
|
||||||
|
Postgraphile: mux.PostgraphileOptions{
|
||||||
|
Default: gqlIpldAddr,
|
||||||
|
TracingAPI: gqlTracingAPIAddr,
|
||||||
|
},
|
||||||
|
RPC: mux.RPCOptions{
|
||||||
|
DefaultClients: ethClients,
|
||||||
|
TracingClients: tracingClients,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
go http.ListenAndServe(settings.IpldGraphqlEndpoint, router)
|
||||||
|
} else {
|
||||||
|
logWithCommand.Info("IPLD GraphQL server is disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRpcAddresses(value string) ([]*rpc.Client, error) {
|
||||||
|
rpcAddresses := strings.Split(value, ",")
|
||||||
|
rpcClients := make([]*rpc.Client, 0, len(rpcAddresses))
|
||||||
|
for _, address := range rpcAddresses {
|
||||||
|
rpcClient, err := rpc.Dial(address)
|
||||||
|
if err != nil {
|
||||||
|
logWithCommand.Errorf("couldn't connect to %s. Error: %s", address, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcClients = append(rpcClients, rpcClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rpcClients) == 0 {
|
||||||
|
logWithCommand.Error(ErrNoRpcEndpoints)
|
||||||
|
return nil, ErrNoRpcEndpoints
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpcClients, nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(serveCmd)
|
rootCmd.AddCommand(serveCmd)
|
||||||
|
|
||||||
|
// database credentials
|
||||||
|
serveCmd.PersistentFlags().String("database-name", "vulcanize_public", "database name")
|
||||||
|
serveCmd.PersistentFlags().Int("database-port", 5432, "database port")
|
||||||
|
serveCmd.PersistentFlags().String("database-hostname", "localhost", "database hostname")
|
||||||
|
serveCmd.PersistentFlags().String("database-user", "", "database user")
|
||||||
|
serveCmd.PersistentFlags().String("database-password", "", "database password")
|
||||||
|
|
||||||
// flags for all config variables
|
// flags for all config variables
|
||||||
serveCmd.PersistentFlags().Bool("server-graphql", false, "turn on the graphql server")
|
// eth graphql and json-rpc parameters
|
||||||
serveCmd.PersistentFlags().String("server-graphql-endpoint", "", "endpoint url for graphql server")
|
serveCmd.PersistentFlags().Bool("eth-server-graphql", false, "turn on the eth graphql server")
|
||||||
serveCmd.PersistentFlags().String("server-ws-path", "", "vdb server ws path")
|
serveCmd.PersistentFlags().String("eth-server-graphql-path", "", "endpoint url for eth graphql server (host:port)")
|
||||||
serveCmd.PersistentFlags().String("server-http-path", "", "vdb server http path")
|
serveCmd.PersistentFlags().Bool("eth-server-http", true, "turn on the eth http json-rpc server")
|
||||||
serveCmd.PersistentFlags().String("server-ipc-path", "", "vdb server ipc path")
|
serveCmd.PersistentFlags().String("eth-server-http-path", "", "endpoint url for eth http json-rpc server (host:port)")
|
||||||
|
serveCmd.PersistentFlags().Bool("eth-server-ws", false, "turn on the eth websocket json-rpc server")
|
||||||
|
serveCmd.PersistentFlags().String("eth-server-ws-path", "", "endpoint url for eth websocket json-rpc server (host:port)")
|
||||||
|
serveCmd.PersistentFlags().Bool("eth-server-ipc", false, "turn on the eth ipc json-rpc server")
|
||||||
|
serveCmd.PersistentFlags().String("eth-server-ipc-path", "", "path for eth ipc json-rpc server")
|
||||||
|
|
||||||
|
// ipld and tracing graphql parameters
|
||||||
|
serveCmd.PersistentFlags().Bool("ipld-server-graphql", false, "turn on the ipld graphql server")
|
||||||
|
serveCmd.PersistentFlags().String("ipld-server-graphql-path", "", "endpoint url for ipld graphql server (host:port)")
|
||||||
|
serveCmd.PersistentFlags().String("ipld-postgraphile-path", "", "http url to postgraphile on top of ipld database")
|
||||||
|
serveCmd.PersistentFlags().String("tracing-http-path", "", "http url to tracing service")
|
||||||
|
serveCmd.PersistentFlags().String("tracing-postgraphile-path", "", "http url to postgraphile on top of tracing db")
|
||||||
|
|
||||||
serveCmd.PersistentFlags().String("eth-http-path", "", "http url for ethereum node")
|
serveCmd.PersistentFlags().String("eth-http-path", "", "http url for ethereum node")
|
||||||
serveCmd.PersistentFlags().String("eth-node-id", "", "eth node id")
|
serveCmd.PersistentFlags().String("eth-node-id", "", "eth node id")
|
||||||
@@ -137,13 +257,39 @@ func init() {
|
|||||||
serveCmd.PersistentFlags().String("eth-chain-id", "1", "eth chain id")
|
serveCmd.PersistentFlags().String("eth-chain-id", "1", "eth chain id")
|
||||||
serveCmd.PersistentFlags().String("eth-default-sender", "", "default sender address")
|
serveCmd.PersistentFlags().String("eth-default-sender", "", "default sender address")
|
||||||
serveCmd.PersistentFlags().String("eth-rpc-gas-cap", "", "rpc gas cap (for eth_Call execution)")
|
serveCmd.PersistentFlags().String("eth-rpc-gas-cap", "", "rpc gas cap (for eth_Call execution)")
|
||||||
|
serveCmd.PersistentFlags().String("eth-chain-config", "", "json chain config file location")
|
||||||
|
serveCmd.PersistentFlags().Bool("eth-supports-state-diff", false, "whether or not the proxy ethereum client supports statediffing endpoints")
|
||||||
|
|
||||||
// and their bindings
|
// and their bindings
|
||||||
viper.BindPFlag("server.graphql", serveCmd.PersistentFlags().Lookup("server-graphql"))
|
// database
|
||||||
viper.BindPFlag("server.graphqlEndpoint", serveCmd.PersistentFlags().Lookup("server-graphql-endpoint"))
|
viper.BindPFlag("database.name", serveCmd.PersistentFlags().Lookup("database-name"))
|
||||||
viper.BindPFlag("server.wsPath", serveCmd.PersistentFlags().Lookup("server-ws-path"))
|
viper.BindPFlag("database.port", serveCmd.PersistentFlags().Lookup("database-port"))
|
||||||
viper.BindPFlag("server.httpPath", serveCmd.PersistentFlags().Lookup("server-http-path"))
|
viper.BindPFlag("database.hostname", serveCmd.PersistentFlags().Lookup("database-hostname"))
|
||||||
viper.BindPFlag("server.ipcPath", serveCmd.PersistentFlags().Lookup("server-ipc-path"))
|
viper.BindPFlag("database.user", serveCmd.PersistentFlags().Lookup("database-user"))
|
||||||
|
viper.BindPFlag("database.password", serveCmd.PersistentFlags().Lookup("database-password"))
|
||||||
|
|
||||||
|
// eth graphql server
|
||||||
|
viper.BindPFlag("eth.server.graphql", serveCmd.PersistentFlags().Lookup("eth-server-graphql"))
|
||||||
|
viper.BindPFlag("eth.server.graphqlPath", serveCmd.PersistentFlags().Lookup("eth-server-graphql-path"))
|
||||||
|
|
||||||
|
// eth http json-rpc server
|
||||||
|
viper.BindPFlag("eth.server.http", serveCmd.PersistentFlags().Lookup("eth-server-http"))
|
||||||
|
viper.BindPFlag("eth.server.httpPath", serveCmd.PersistentFlags().Lookup("eth-server-http-path"))
|
||||||
|
|
||||||
|
// eth websocket json-rpc server
|
||||||
|
viper.BindPFlag("eth.server.ws", serveCmd.PersistentFlags().Lookup("eth-server-ws"))
|
||||||
|
viper.BindPFlag("eth.server.wsPath", serveCmd.PersistentFlags().Lookup("eth-server-ws-path"))
|
||||||
|
|
||||||
|
// eth ipc json-rpc server
|
||||||
|
viper.BindPFlag("eth.server.ipc", serveCmd.PersistentFlags().Lookup("eth-server-ipc"))
|
||||||
|
viper.BindPFlag("eth.server.ipcPath", serveCmd.PersistentFlags().Lookup("eth-server-ipc-path"))
|
||||||
|
|
||||||
|
// ipld and tracing graphql parameters
|
||||||
|
viper.BindPFlag("ipld.server.graphql", serveCmd.PersistentFlags().Lookup("ipld-server-graphql"))
|
||||||
|
viper.BindPFlag("ipld.server.graphqlPath", serveCmd.PersistentFlags().Lookup("ipld-server-graphql-path"))
|
||||||
|
viper.BindPFlag("ipld.postgraphilePath", serveCmd.PersistentFlags().Lookup("ipld-postgraphile-path"))
|
||||||
|
viper.BindPFlag("tracing.httpPath", serveCmd.PersistentFlags().Lookup("tracing-http-path"))
|
||||||
|
viper.BindPFlag("tracing.postgraphilePath", serveCmd.PersistentFlags().Lookup("tracing-postgraphile-path"))
|
||||||
|
|
||||||
viper.BindPFlag("ethereum.httpPath", serveCmd.PersistentFlags().Lookup("eth-http-path"))
|
viper.BindPFlag("ethereum.httpPath", serveCmd.PersistentFlags().Lookup("eth-http-path"))
|
||||||
viper.BindPFlag("ethereum.nodeID", serveCmd.PersistentFlags().Lookup("eth-node-id"))
|
viper.BindPFlag("ethereum.nodeID", serveCmd.PersistentFlags().Lookup("eth-node-id"))
|
||||||
@@ -153,4 +299,6 @@ func init() {
|
|||||||
viper.BindPFlag("ethereum.chainID", serveCmd.PersistentFlags().Lookup("eth-chain-id"))
|
viper.BindPFlag("ethereum.chainID", serveCmd.PersistentFlags().Lookup("eth-chain-id"))
|
||||||
viper.BindPFlag("ethereum.defaultSender", serveCmd.PersistentFlags().Lookup("eth-default-sender"))
|
viper.BindPFlag("ethereum.defaultSender", serveCmd.PersistentFlags().Lookup("eth-default-sender"))
|
||||||
viper.BindPFlag("ethereum.rpcGasCap", serveCmd.PersistentFlags().Lookup("eth-rpc-gas-cap"))
|
viper.BindPFlag("ethereum.rpcGasCap", serveCmd.PersistentFlags().Lookup("eth-rpc-gas-cap"))
|
||||||
|
viper.BindPFlag("ethereum.chainConfig", serveCmd.PersistentFlags().Lookup("eth-chain-config"))
|
||||||
|
viper.BindPFlag("ethereum.supportsStateDiff", serveCmd.PersistentFlags().Lookup("eth-supports-state-diff"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ CREATE TABLE nodes (
|
|||||||
genesis_block VARCHAR(66),
|
genesis_block VARCHAR(66),
|
||||||
network_id VARCHAR,
|
network_id VARCHAR,
|
||||||
node_id VARCHAR(128),
|
node_id VARCHAR(128),
|
||||||
CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id)
|
chain_id INTEGER DEFAULT 1,
|
||||||
|
CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id, chain_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ CREATE TABLE eth.transaction_cids (
|
|||||||
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||||
dst VARCHAR(66) NOT NULL,
|
dst VARCHAR(66) NOT NULL,
|
||||||
src VARCHAR(66) NOT NULL,
|
src VARCHAR(66) NOT NULL,
|
||||||
deployment BOOL NOT NULL,
|
|
||||||
tx_data BYTEA,
|
tx_data BYTEA,
|
||||||
UNIQUE (header_id, tx_hash)
|
UNIQUE (header_id, tx_hash)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ CREATE TABLE eth.receipt_cids (
|
|||||||
topic2s VARCHAR(66)[],
|
topic2s VARCHAR(66)[],
|
||||||
topic3s VARCHAR(66)[],
|
topic3s VARCHAR(66)[],
|
||||||
log_contracts VARCHAR(66)[],
|
log_contracts VARCHAR(66)[],
|
||||||
|
post_state VARCHAR(66),
|
||||||
|
post_status INTEGER,
|
||||||
UNIQUE (tx_id)
|
UNIQUE (tx_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-- +goose Up
|
-- +goose Up
|
||||||
CREATE TABLE eth.state_cids (
|
CREATE TABLE eth.state_cids (
|
||||||
id SERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
header_id INTEGER NOT NULL REFERENCES eth.header_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
header_id INTEGER NOT NULL REFERENCES eth.header_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||||
state_leaf_key VARCHAR(66),
|
state_leaf_key VARCHAR(66),
|
||||||
cid TEXT NOT NULL,
|
cid TEXT NOT NULL,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
-- +goose Up
|
-- +goose Up
|
||||||
CREATE TABLE eth.storage_cids (
|
CREATE TABLE eth.storage_cids (
|
||||||
id SERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
state_id INTEGER NOT NULL REFERENCES eth.state_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
state_id BIGINT NOT NULL REFERENCES eth.state_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||||
storage_leaf_key VARCHAR(66),
|
storage_leaf_key VARCHAR(66),
|
||||||
cid TEXT NOT NULL,
|
cid TEXT NOT NULL,
|
||||||
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
-- +goose Up
|
-- +goose Up
|
||||||
CREATE TABLE eth.state_accounts (
|
CREATE TABLE eth.state_accounts (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
state_id INTEGER NOT NULL REFERENCES eth.state_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
state_id BIGINT NOT NULL REFERENCES eth.state_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||||
balance NUMERIC NOT NULL,
|
balance NUMERIC NOT NULL,
|
||||||
nonce INTEGER NOT NULL,
|
nonce INTEGER NOT NULL,
|
||||||
code_hash BYTEA NOT NULL,
|
code_hash BYTEA NOT NULL,
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
ALTER TABLE public.nodes
|
|
||||||
ADD COLUMN chain_id INTEGER DEFAULT 1;
|
|
||||||
|
|
||||||
ALTER TABLE public.nodes
|
|
||||||
DROP CONSTRAINT node_uc;
|
|
||||||
|
|
||||||
ALTER TABLE public.nodes
|
|
||||||
ADD CONSTRAINT node_uc
|
|
||||||
UNIQUE (genesis_block, network_id, node_id, chain_id);
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
ALTER TABLE public.nodes
|
|
||||||
DROP CONSTRAINT node_uc;
|
|
||||||
|
|
||||||
ALTER TABLE public.nodes
|
|
||||||
ADD CONSTRAINT node_uc
|
|
||||||
UNIQUE (genesis_block, network_id, node_id);
|
|
||||||
|
|
||||||
ALTER TABLE public.nodes
|
|
||||||
DROP COLUMN chain_id;
|
|
||||||
+71
-34
@@ -1,34 +1,69 @@
|
|||||||
-- +goose Up
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- returns if a storage node at the provided path was removed in the range >= the provided height and <= the provided block hash
|
||||||
|
CREATE OR REPLACE FUNCTION was_storage_removed(path BYTEA, height BIGINT, hash VARCHAR(66)) RETURNS BOOLEAN
|
||||||
|
AS $$
|
||||||
|
SELECT exists(SELECT 1
|
||||||
|
FROM eth.storage_cids
|
||||||
|
INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id)
|
||||||
|
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||||
|
WHERE storage_path = path
|
||||||
|
AND block_number >= height
|
||||||
|
AND block_number <= (SELECT block_number
|
||||||
|
FROM eth.header_cids
|
||||||
|
WHERE block_hash = hash)
|
||||||
|
AND storage_cids.node_type = 3
|
||||||
|
LIMIT 1);
|
||||||
|
$$ LANGUAGE SQL;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
|
-- +goose StatementBegin
|
||||||
|
-- returns if a state node at the provided path was removed in the range > the provided height and <= the provided block hash
|
||||||
|
CREATE OR REPLACE FUNCTION was_state_removed(path BYTEA, height BIGINT, hash VARCHAR(66)) RETURNS BOOLEAN
|
||||||
|
AS $$
|
||||||
|
SELECT exists(SELECT 1
|
||||||
|
FROM eth.state_cids
|
||||||
|
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||||
|
WHERE state_path = path
|
||||||
|
AND block_number > height
|
||||||
|
AND block_number <= (SELECT block_number
|
||||||
|
FROM eth.header_cids
|
||||||
|
WHERE block_hash = hash)
|
||||||
|
AND state_cids.node_type = 3
|
||||||
|
LIMIT 1);
|
||||||
|
$$ LANGUAGE SQL;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
-- +goose StatementBegin
|
-- +goose StatementBegin
|
||||||
CREATE TYPE child_result AS (
|
CREATE TYPE child_result AS (
|
||||||
has_child BOOLEAN,
|
has_child BOOLEAN,
|
||||||
children eth.header_cids[]
|
children eth.header_cids[]
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION has_child(hash VARCHAR(66), height BIGINT) RETURNS child_result AS
|
CREATE OR REPLACE FUNCTION has_child(hash VARCHAR(66), height BIGINT) RETURNS child_result AS
|
||||||
$BODY$
|
$BODY$
|
||||||
DECLARE
|
DECLARE
|
||||||
child_height INT;
|
child_height INT;
|
||||||
temp_child eth.header_cids;
|
temp_child eth.header_cids;
|
||||||
new_child_result child_result;
|
new_child_result child_result;
|
||||||
BEGIN
|
BEGIN
|
||||||
child_height = height + 1;
|
child_height = height + 1;
|
||||||
-- short circuit if there are no children
|
-- short circuit if there are no children
|
||||||
SELECT exists(SELECT 1
|
SELECT exists(SELECT 1
|
||||||
FROM eth.header_cids
|
FROM eth.header_cids
|
||||||
WHERE parent_hash = hash
|
WHERE parent_hash = hash
|
||||||
AND block_number = child_height
|
AND block_number = child_height
|
||||||
LIMIT 1)
|
LIMIT 1)
|
||||||
INTO new_child_result.has_child;
|
INTO new_child_result.has_child;
|
||||||
-- collect all the children for this header
|
-- collect all the children for this header
|
||||||
IF new_child_result.has_child THEN
|
IF new_child_result.has_child THEN
|
||||||
FOR temp_child IN
|
FOR temp_child IN
|
||||||
SELECT * FROM eth.header_cids WHERE parent_hash = hash AND block_number = child_height
|
SELECT * FROM eth.header_cids WHERE parent_hash = hash AND block_number = child_height
|
||||||
LOOP
|
LOOP
|
||||||
new_child_result.children = array_append(new_child_result.children, temp_child);
|
new_child_result.children = array_append(new_child_result.children, temp_child);
|
||||||
END LOOP;
|
END LOOP;
|
||||||
END IF;
|
END IF;
|
||||||
RETURN new_child_result;
|
RETURN new_child_result;
|
||||||
END
|
END
|
||||||
$BODY$
|
$BODY$
|
||||||
LANGUAGE 'plpgsql';
|
LANGUAGE 'plpgsql';
|
||||||
@@ -38,7 +73,7 @@ LANGUAGE 'plpgsql';
|
|||||||
CREATE OR REPLACE FUNCTION canonical_header_from_array(headers eth.header_cids[]) RETURNS eth.header_cids AS
|
CREATE OR REPLACE FUNCTION canonical_header_from_array(headers eth.header_cids[]) RETURNS eth.header_cids AS
|
||||||
$BODY$
|
$BODY$
|
||||||
DECLARE
|
DECLARE
|
||||||
canonical_header eth.header_cids;
|
canonical_header eth.header_cids;
|
||||||
canonical_child eth.header_cids;
|
canonical_child eth.header_cids;
|
||||||
header eth.header_cids;
|
header eth.header_cids;
|
||||||
current_child_result child_result;
|
current_child_result child_result;
|
||||||
@@ -57,25 +92,25 @@ BEGIN
|
|||||||
current_header_with_child = header;
|
current_header_with_child = header;
|
||||||
-- and add the children to the growing set of child headers
|
-- and add the children to the growing set of child headers
|
||||||
child_headers = array_cat(child_headers, current_child_result.children);
|
child_headers = array_cat(child_headers, current_child_result.children);
|
||||||
END IF;
|
END IF;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
-- if none of the headers had children, none is more canonical than the other
|
-- if none of the headers had children, none is more canonical than the other
|
||||||
IF has_children_count = 0 THEN
|
IF has_children_count = 0 THEN
|
||||||
-- return the first one selected
|
-- return the first one selected
|
||||||
SELECT * INTO canonical_header FROM unnest(headers) LIMIT 1;
|
SELECT * INTO canonical_header FROM unnest(headers) LIMIT 1;
|
||||||
-- if only one header had children, it can be considered the heaviest/canonical header of the set
|
-- if only one header had children, it can be considered the heaviest/canonical header of the set
|
||||||
ELSIF has_children_count = 1 THEN
|
ELSIF has_children_count = 1 THEN
|
||||||
-- return the only header with a child
|
-- return the only header with a child
|
||||||
canonical_header = current_header_with_child;
|
canonical_header = current_header_with_child;
|
||||||
-- if there are multiple headers with children
|
-- if there are multiple headers with children
|
||||||
ELSE
|
ELSE
|
||||||
-- find the canonical header from the child set
|
-- find the canonical header from the child set
|
||||||
canonical_child = canonical_header_from_array(child_headers);
|
canonical_child = canonical_header_from_array(child_headers);
|
||||||
-- the header that is parent to this header, is the canonical header at this level
|
-- the header that is parent to this header, is the canonical header at this level
|
||||||
SELECT * INTO canonical_header FROM unnest(headers)
|
SELECT * INTO canonical_header FROM unnest(headers)
|
||||||
WHERE block_hash = canonical_child.parent_hash;
|
WHERE block_hash = canonical_child.parent_hash;
|
||||||
END IF;
|
END IF;
|
||||||
RETURN canonical_header;
|
RETURN canonical_header;
|
||||||
END
|
END
|
||||||
$BODY$
|
$BODY$
|
||||||
LANGUAGE 'plpgsql';
|
LANGUAGE 'plpgsql';
|
||||||
@@ -85,17 +120,17 @@ LANGUAGE 'plpgsql';
|
|||||||
CREATE OR REPLACE FUNCTION canonical_header_id(height BIGINT) RETURNS INTEGER AS
|
CREATE OR REPLACE FUNCTION canonical_header_id(height BIGINT) RETURNS INTEGER AS
|
||||||
$BODY$
|
$BODY$
|
||||||
DECLARE
|
DECLARE
|
||||||
canonical_header eth.header_cids;
|
canonical_header eth.header_cids;
|
||||||
headers eth.header_cids[];
|
headers eth.header_cids[];
|
||||||
header_count INT;
|
header_count INT;
|
||||||
temp_header eth.header_cids;
|
temp_header eth.header_cids;
|
||||||
BEGIN
|
BEGIN
|
||||||
-- collect all headers at this height
|
-- collect all headers at this height
|
||||||
FOR temp_header IN
|
FOR temp_header IN
|
||||||
SELECT * FROM eth.header_cids WHERE block_number = height
|
SELECT * FROM eth.header_cids WHERE block_number = height
|
||||||
LOOP
|
LOOP
|
||||||
headers = array_append(headers, temp_header);
|
headers = array_append(headers, temp_header);
|
||||||
END LOOP;
|
END LOOP;
|
||||||
-- count the number of headers collected
|
-- count the number of headers collected
|
||||||
header_count = array_length(headers, 1);
|
header_count = array_length(headers, 1);
|
||||||
-- if we have less than 1 header, return NULL
|
-- if we have less than 1 header, return NULL
|
||||||
@@ -105,17 +140,19 @@ BEGIN
|
|||||||
ELSIF header_count = 1 THEN
|
ELSIF header_count = 1 THEN
|
||||||
RETURN headers[1].id;
|
RETURN headers[1].id;
|
||||||
-- if we have multiple headers we need to determine which one is canonical
|
-- if we have multiple headers we need to determine which one is canonical
|
||||||
ELSE
|
ELSE
|
||||||
canonical_header = canonical_header_from_array(headers);
|
canonical_header = canonical_header_from_array(headers);
|
||||||
RETURN canonical_header.id;
|
RETURN canonical_header.id;
|
||||||
END IF;
|
END IF;
|
||||||
END;
|
END;
|
||||||
$BODY$
|
$BODY$
|
||||||
LANGUAGE 'plpgsql';
|
LANGUAGE 'plpgsql';
|
||||||
-- +goose StatementEnd
|
-- +goose StatementEnd
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
|
DROP FUNCTION was_storage_removed;
|
||||||
|
DROP FUNCTION was_state_removed;
|
||||||
DROP FUNCTION canonical_header_id;
|
DROP FUNCTION canonical_header_id;
|
||||||
DROP FUNCTION canonical_header_from_array;
|
DROP FUNCTION canonical_header_from_array;
|
||||||
DROP FUNCTION has_child;
|
DROP FUNCTION has_child;
|
||||||
DROP TYPE child_result;
|
DROP TYPE child_result;
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
-- +goose StatementBegin
|
|
||||||
-- returns the number of child headers that reference backwards to the header with the provided hash
|
|
||||||
CREATE OR REPLACE FUNCTION header_weight(hash VARCHAR(66)) RETURNS BIGINT
|
|
||||||
AS $$
|
|
||||||
WITH RECURSIVE validator AS (
|
|
||||||
SELECT block_hash, parent_hash, block_number
|
|
||||||
FROM eth.header_cids
|
|
||||||
WHERE block_hash = hash
|
|
||||||
UNION
|
|
||||||
SELECT eth.header_cids.block_hash, eth.header_cids.parent_hash, eth.header_cids.block_number
|
|
||||||
FROM eth.header_cids
|
|
||||||
INNER JOIN validator
|
|
||||||
ON eth.header_cids.parent_hash = validator.block_hash
|
|
||||||
AND eth.header_cids.block_number = validator.block_number + 1
|
|
||||||
)
|
|
||||||
SELECT COUNT(*) FROM validator;
|
|
||||||
$$ LANGUAGE SQL;
|
|
||||||
-- +goose StatementEnd
|
|
||||||
|
|
||||||
-- +goose StatementBegin
|
|
||||||
-- returns the id for the header at the provided height which is heaviest
|
|
||||||
CREATE OR REPLACE FUNCTION canonical_header(height BIGINT) RETURNS INT AS
|
|
||||||
$BODY$
|
|
||||||
DECLARE
|
|
||||||
current_weight INT;
|
|
||||||
heaviest_weight INT DEFAULT 0;
|
|
||||||
heaviest_id INT;
|
|
||||||
r eth.header_cids%ROWTYPE;
|
|
||||||
BEGIN
|
|
||||||
FOR r IN SELECT * FROM eth.header_cids
|
|
||||||
WHERE block_number = height
|
|
||||||
LOOP
|
|
||||||
SELECT INTO current_weight * FROM header_weight(r.block_hash);
|
|
||||||
IF current_weight > heaviest_weight THEN
|
|
||||||
heaviest_weight := current_weight;
|
|
||||||
heaviest_id := r.id;
|
|
||||||
END IF;
|
|
||||||
END LOOP;
|
|
||||||
RETURN heaviest_id;
|
|
||||||
END
|
|
||||||
$BODY$
|
|
||||||
LANGUAGE 'plpgsql';
|
|
||||||
-- +goose StatementEnd
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP FUNCTION header_weight;
|
|
||||||
DROP FUNCTION canonical_header;
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
ALTER TABLE eth.transaction_cids
|
|
||||||
DROP COLUMN deployment;
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
ALTER TABLE eth.transaction_cids
|
|
||||||
ADD COLUMN deployment BOOL NOT NULL DEFAULT FALSE;
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
ALTER TABLE eth.storage_cids
|
|
||||||
ALTER COLUMN state_id TYPE BIGINT;
|
|
||||||
|
|
||||||
ALTER TABLE eth.state_accounts
|
|
||||||
ALTER COLUMN state_id TYPE BIGINT;
|
|
||||||
|
|
||||||
ALTER TABLE eth.state_cids
|
|
||||||
ALTER COLUMN id TYPE BIGINT;
|
|
||||||
|
|
||||||
ALTER TABLE eth.storage_cids
|
|
||||||
ALTER COLUMN id TYPE BIGINT;
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
ALTER TABLE eth.storage_cids
|
|
||||||
ALTER COLUMN id TYPE INTEGER;
|
|
||||||
|
|
||||||
ALTER TABLE eth.state_cids
|
|
||||||
ALTER COLUMN id TYPE INTEGER;
|
|
||||||
|
|
||||||
ALTER TABLE eth.state_accounts
|
|
||||||
ALTER COLUMN state_id TYPE INTEGER;
|
|
||||||
|
|
||||||
ALTER TABLE eth.storage_cids
|
|
||||||
ALTER COLUMN state_id TYPE INTEGER;
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
-- +goose StatementBegin
|
|
||||||
-- returns if a storage node at the provided path was removed in the range > the provided height and <= the provided block hash
|
|
||||||
CREATE OR REPLACE FUNCTION was_storage_removed(path BYTEA, height BIGINT, hash VARCHAR(66)) RETURNS BOOLEAN
|
|
||||||
AS $$
|
|
||||||
SELECT exists(SELECT 1
|
|
||||||
FROM eth.storage_cids
|
|
||||||
INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id)
|
|
||||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
|
||||||
WHERE storage_path = path
|
|
||||||
AND block_number > height
|
|
||||||
AND block_number <= (SELECT block_number
|
|
||||||
FROM eth.header_cids
|
|
||||||
WHERE block_hash = hash)
|
|
||||||
AND storage_cids.node_type = 3
|
|
||||||
LIMIT 1);
|
|
||||||
$$ LANGUAGE SQL;
|
|
||||||
-- +goose StatementEnd
|
|
||||||
|
|
||||||
-- +goose StatementBegin
|
|
||||||
-- returns if a state node at the provided path was removed in the range > the provided height and <= the provided block hash
|
|
||||||
CREATE OR REPLACE FUNCTION was_state_removed(path BYTEA, height BIGINT, hash VARCHAR(66)) RETURNS BOOLEAN
|
|
||||||
AS $$
|
|
||||||
SELECT exists(SELECT 1
|
|
||||||
FROM eth.state_cids
|
|
||||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
|
||||||
WHERE state_path = path
|
|
||||||
AND block_number > height
|
|
||||||
AND block_number <= (SELECT block_number
|
|
||||||
FROM eth.header_cids
|
|
||||||
WHERE block_hash = hash)
|
|
||||||
AND state_cids.node_type = 3
|
|
||||||
LIMIT 1);
|
|
||||||
$$ LANGUAGE SQL;
|
|
||||||
-- +goose StatementEnd
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
DROP FUNCTION was_storage_removed;
|
|
||||||
DROP FUNCTION was_state_removed;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
-- +goose Up
|
|
||||||
ALTER TABLE eth.receipt_cids
|
|
||||||
ADD COLUMN post_state VARCHAR(66);
|
|
||||||
|
|
||||||
ALTER TABLE eth.receipt_cids
|
|
||||||
ADD COLUMN post_status INTEGER;
|
|
||||||
|
|
||||||
-- +goose Down
|
|
||||||
ALTER TABLE eth.receipt_cids
|
|
||||||
DROP COLUMN post_status;
|
|
||||||
|
|
||||||
ALTER TABLE eth.receipt_cids
|
|
||||||
DROP COLUMN post_state;
|
|
||||||
+52
-103
@@ -103,33 +103,6 @@ end;
|
|||||||
$_$;
|
$_$;
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: canonical_header(bigint); Type: FUNCTION; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE FUNCTION public.canonical_header(height bigint) RETURNS integer
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
current_weight INT;
|
|
||||||
heaviest_weight INT DEFAULT 0;
|
|
||||||
heaviest_id INT;
|
|
||||||
r eth.header_cids%ROWTYPE;
|
|
||||||
BEGIN
|
|
||||||
FOR r IN SELECT * FROM eth.header_cids
|
|
||||||
WHERE block_number = height
|
|
||||||
LOOP
|
|
||||||
SELECT INTO current_weight * FROM header_weight(r.block_hash);
|
|
||||||
IF current_weight > heaviest_weight THEN
|
|
||||||
heaviest_weight := current_weight;
|
|
||||||
heaviest_id := r.id;
|
|
||||||
END IF;
|
|
||||||
END LOOP;
|
|
||||||
RETURN heaviest_id;
|
|
||||||
END
|
|
||||||
$$;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: canonical_header_from_array(eth.header_cids[]); Type: FUNCTION; Schema: public; Owner: -
|
-- Name: canonical_header_from_array(eth.header_cids[]); Type: FUNCTION; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -138,7 +111,7 @@ CREATE FUNCTION public.canonical_header_from_array(headers eth.header_cids[]) RE
|
|||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
AS $$
|
AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
canonical_header eth.header_cids;
|
canonical_header eth.header_cids;
|
||||||
canonical_child eth.header_cids;
|
canonical_child eth.header_cids;
|
||||||
header eth.header_cids;
|
header eth.header_cids;
|
||||||
current_child_result child_result;
|
current_child_result child_result;
|
||||||
@@ -157,25 +130,25 @@ BEGIN
|
|||||||
current_header_with_child = header;
|
current_header_with_child = header;
|
||||||
-- and add the children to the growing set of child headers
|
-- and add the children to the growing set of child headers
|
||||||
child_headers = array_cat(child_headers, current_child_result.children);
|
child_headers = array_cat(child_headers, current_child_result.children);
|
||||||
END IF;
|
END IF;
|
||||||
END LOOP;
|
END LOOP;
|
||||||
-- if none of the headers had children, none is more canonical than the other
|
-- if none of the headers had children, none is more canonical than the other
|
||||||
IF has_children_count = 0 THEN
|
IF has_children_count = 0 THEN
|
||||||
-- return the first one selected
|
-- return the first one selected
|
||||||
SELECT * INTO canonical_header FROM unnest(headers) LIMIT 1;
|
SELECT * INTO canonical_header FROM unnest(headers) LIMIT 1;
|
||||||
-- if only one header had children, it can be considered the heaviest/canonical header of the set
|
-- if only one header had children, it can be considered the heaviest/canonical header of the set
|
||||||
ELSIF has_children_count = 1 THEN
|
ELSIF has_children_count = 1 THEN
|
||||||
-- return the only header with a child
|
-- return the only header with a child
|
||||||
canonical_header = current_header_with_child;
|
canonical_header = current_header_with_child;
|
||||||
-- if there are multiple headers with children
|
-- if there are multiple headers with children
|
||||||
ELSE
|
ELSE
|
||||||
-- find the canonical header from the child set
|
-- find the canonical header from the child set
|
||||||
canonical_child = canonical_header_from_array(child_headers);
|
canonical_child = canonical_header_from_array(child_headers);
|
||||||
-- the header that is parent to this header, is the canonical header at this level
|
-- the header that is parent to this header, is the canonical header at this level
|
||||||
SELECT * INTO canonical_header FROM unnest(headers)
|
SELECT * INTO canonical_header FROM unnest(headers)
|
||||||
WHERE block_hash = canonical_child.parent_hash;
|
WHERE block_hash = canonical_child.parent_hash;
|
||||||
END IF;
|
END IF;
|
||||||
RETURN canonical_header;
|
RETURN canonical_header;
|
||||||
END
|
END
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
@@ -188,17 +161,17 @@ CREATE FUNCTION public.canonical_header_id(height bigint) RETURNS integer
|
|||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
AS $$
|
AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
canonical_header eth.header_cids;
|
canonical_header eth.header_cids;
|
||||||
headers eth.header_cids[];
|
headers eth.header_cids[];
|
||||||
header_count INT;
|
header_count INT;
|
||||||
temp_header eth.header_cids;
|
temp_header eth.header_cids;
|
||||||
BEGIN
|
BEGIN
|
||||||
-- collect all headers at this height
|
-- collect all headers at this height
|
||||||
FOR temp_header IN
|
FOR temp_header IN
|
||||||
SELECT * FROM eth.header_cids WHERE block_number = height
|
SELECT * FROM eth.header_cids WHERE block_number = height
|
||||||
LOOP
|
LOOP
|
||||||
headers = array_append(headers, temp_header);
|
headers = array_append(headers, temp_header);
|
||||||
END LOOP;
|
END LOOP;
|
||||||
-- count the number of headers collected
|
-- count the number of headers collected
|
||||||
header_count = array_length(headers, 1);
|
header_count = array_length(headers, 1);
|
||||||
-- if we have less than 1 header, return NULL
|
-- if we have less than 1 header, return NULL
|
||||||
@@ -208,10 +181,10 @@ BEGIN
|
|||||||
ELSIF header_count = 1 THEN
|
ELSIF header_count = 1 THEN
|
||||||
RETURN headers[1].id;
|
RETURN headers[1].id;
|
||||||
-- if we have multiple headers we need to determine which one is canonical
|
-- if we have multiple headers we need to determine which one is canonical
|
||||||
ELSE
|
ELSE
|
||||||
canonical_header = canonical_header_from_array(headers);
|
canonical_header = canonical_header_from_array(headers);
|
||||||
RETURN canonical_header.id;
|
RETURN canonical_header.id;
|
||||||
END IF;
|
END IF;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
@@ -224,53 +197,31 @@ CREATE FUNCTION public.has_child(hash character varying, height bigint) RETURNS
|
|||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
AS $$
|
AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
child_height INT;
|
child_height INT;
|
||||||
temp_child eth.header_cids;
|
temp_child eth.header_cids;
|
||||||
new_child_result child_result;
|
new_child_result child_result;
|
||||||
BEGIN
|
BEGIN
|
||||||
child_height = height + 1;
|
child_height = height + 1;
|
||||||
-- short circuit if there are no children
|
-- short circuit if there are no children
|
||||||
SELECT exists(SELECT 1
|
SELECT exists(SELECT 1
|
||||||
FROM eth.header_cids
|
FROM eth.header_cids
|
||||||
WHERE parent_hash = hash
|
WHERE parent_hash = hash
|
||||||
AND block_number = child_height
|
AND block_number = child_height
|
||||||
LIMIT 1)
|
LIMIT 1)
|
||||||
INTO new_child_result.has_child;
|
INTO new_child_result.has_child;
|
||||||
-- collect all the children for this header
|
-- collect all the children for this header
|
||||||
IF new_child_result.has_child THEN
|
IF new_child_result.has_child THEN
|
||||||
FOR temp_child IN
|
FOR temp_child IN
|
||||||
SELECT * FROM eth.header_cids WHERE parent_hash = hash AND block_number = child_height
|
SELECT * FROM eth.header_cids WHERE parent_hash = hash AND block_number = child_height
|
||||||
LOOP
|
LOOP
|
||||||
new_child_result.children = array_append(new_child_result.children, temp_child);
|
new_child_result.children = array_append(new_child_result.children, temp_child);
|
||||||
END LOOP;
|
END LOOP;
|
||||||
END IF;
|
END IF;
|
||||||
RETURN new_child_result;
|
RETURN new_child_result;
|
||||||
END
|
END
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: header_weight(character varying); Type: FUNCTION; Schema: public; Owner: -
|
|
||||||
--
|
|
||||||
|
|
||||||
CREATE FUNCTION public.header_weight(hash character varying) RETURNS bigint
|
|
||||||
LANGUAGE sql
|
|
||||||
AS $$
|
|
||||||
WITH RECURSIVE validator AS (
|
|
||||||
SELECT block_hash, parent_hash, block_number
|
|
||||||
FROM eth.header_cids
|
|
||||||
WHERE block_hash = hash
|
|
||||||
UNION
|
|
||||||
SELECT eth.header_cids.block_hash, eth.header_cids.parent_hash, eth.header_cids.block_number
|
|
||||||
FROM eth.header_cids
|
|
||||||
INNER JOIN validator
|
|
||||||
ON eth.header_cids.parent_hash = validator.block_hash
|
|
||||||
AND eth.header_cids.block_number = validator.block_number + 1
|
|
||||||
)
|
|
||||||
SELECT COUNT(*) FROM validator;
|
|
||||||
$$;
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: was_state_removed(bytea, bigint, character varying); Type: FUNCTION; Schema: public; Owner: -
|
-- Name: was_state_removed(bytea, bigint, character varying); Type: FUNCTION; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@@ -278,16 +229,16 @@ $$;
|
|||||||
CREATE FUNCTION public.was_state_removed(path bytea, height bigint, hash character varying) RETURNS boolean
|
CREATE FUNCTION public.was_state_removed(path bytea, height bigint, hash character varying) RETURNS boolean
|
||||||
LANGUAGE sql
|
LANGUAGE sql
|
||||||
AS $$
|
AS $$
|
||||||
SELECT exists(SELECT 1
|
SELECT exists(SELECT 1
|
||||||
FROM eth.state_cids
|
FROM eth.state_cids
|
||||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||||
WHERE state_path = path
|
WHERE state_path = path
|
||||||
AND block_number > height
|
AND block_number > height
|
||||||
AND block_number <= (SELECT block_number
|
AND block_number <= (SELECT block_number
|
||||||
FROM eth.header_cids
|
FROM eth.header_cids
|
||||||
WHERE block_hash = hash)
|
WHERE block_hash = hash)
|
||||||
AND state_cids.node_type = 3
|
AND state_cids.node_type = 3
|
||||||
LIMIT 1);
|
LIMIT 1);
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
|
||||||
@@ -298,17 +249,17 @@ $$;
|
|||||||
CREATE FUNCTION public.was_storage_removed(path bytea, height bigint, hash character varying) RETURNS boolean
|
CREATE FUNCTION public.was_storage_removed(path bytea, height bigint, hash character varying) RETURNS boolean
|
||||||
LANGUAGE sql
|
LANGUAGE sql
|
||||||
AS $$
|
AS $$
|
||||||
SELECT exists(SELECT 1
|
SELECT exists(SELECT 1
|
||||||
FROM eth.storage_cids
|
FROM eth.storage_cids
|
||||||
INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id)
|
INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id)
|
||||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||||
WHERE storage_path = path
|
WHERE storage_path = path
|
||||||
AND block_number > height
|
AND block_number > height
|
||||||
AND block_number <= (SELECT block_number
|
AND block_number <= (SELECT block_number
|
||||||
FROM eth.header_cids
|
FROM eth.header_cids
|
||||||
WHERE block_hash = hash)
|
WHERE block_hash = hash)
|
||||||
AND storage_cids.node_type = 3
|
AND storage_cids.node_type = 3
|
||||||
LIMIT 1);
|
LIMIT 1);
|
||||||
$$;
|
$$;
|
||||||
|
|
||||||
|
|
||||||
@@ -428,7 +379,6 @@ CREATE TABLE eth.state_cids (
|
|||||||
--
|
--
|
||||||
|
|
||||||
CREATE SEQUENCE eth.state_cids_id_seq
|
CREATE SEQUENCE eth.state_cids_id_seq
|
||||||
AS integer
|
|
||||||
START WITH 1
|
START WITH 1
|
||||||
INCREMENT BY 1
|
INCREMENT BY 1
|
||||||
NO MINVALUE
|
NO MINVALUE
|
||||||
@@ -464,7 +414,6 @@ CREATE TABLE eth.storage_cids (
|
|||||||
--
|
--
|
||||||
|
|
||||||
CREATE SEQUENCE eth.storage_cids_id_seq
|
CREATE SEQUENCE eth.storage_cids_id_seq
|
||||||
AS integer
|
|
||||||
START WITH 1
|
START WITH 1
|
||||||
INCREMENT BY 1
|
INCREMENT BY 1
|
||||||
NO MINVALUE
|
NO MINVALUE
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
version: '3.2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
contract:
|
||||||
|
depends_on:
|
||||||
|
- dapptools
|
||||||
|
build:
|
||||||
|
context: ./test/contract
|
||||||
|
args:
|
||||||
|
ETH_ADDR: "http://dapptools:8545"
|
||||||
|
environment:
|
||||||
|
ETH_ADDR: "http://dapptools:8545"
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:3000:3000"
|
||||||
+31
-22
@@ -3,11 +3,31 @@ version: '3.2'
|
|||||||
services:
|
services:
|
||||||
dapptools:
|
dapptools:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
image: vulcanize/dapptools:v0.29.0-statediff-0.0.2
|
depends_on:
|
||||||
|
- statediff-migrations
|
||||||
|
image: vulcanize/dapptools:v0.29.0-v1.10.2-statediff-0.0.19
|
||||||
|
environment:
|
||||||
|
DB_USER: vdbm
|
||||||
|
DB_NAME: vulcanize_public
|
||||||
|
DB_HOST: db
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_PASSWORD: password
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8545:8545"
|
- "127.0.0.1:8545:8545"
|
||||||
- "127.0.0.1:8546:8546"
|
- "127.0.0.1:8546:8546"
|
||||||
|
|
||||||
|
statediff-migrations:
|
||||||
|
restart: on-failure
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
image: vulcanize/statediff-migrations:v0.4.0
|
||||||
|
environment:
|
||||||
|
DATABASE_USER: vdbm
|
||||||
|
DATABASE_NAME: vulcanize_public
|
||||||
|
DATABASE_HOSTNAME: db
|
||||||
|
DATABASE_PORT: 5432
|
||||||
|
DATABASE_PASSWORD: password
|
||||||
|
|
||||||
db:
|
db:
|
||||||
restart: always
|
restart: always
|
||||||
image: postgres:10.12-alpine
|
image: postgres:10.12-alpine
|
||||||
@@ -20,25 +40,8 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8077:5432"
|
- "127.0.0.1:8077:5432"
|
||||||
|
|
||||||
eth-indexer:
|
|
||||||
restart: unless-stopped
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
- dapptools
|
|
||||||
image: vulcanize/ipld-eth-indexer:v0.3.0-alpha
|
|
||||||
environment:
|
|
||||||
DATABASE_NAME: vulcanize_public
|
|
||||||
DATABASE_HOSTNAME: db
|
|
||||||
DATABASE_PORT: 5432
|
|
||||||
DATABASE_USER: vdbm
|
|
||||||
DATABASE_PASSWORD: password
|
|
||||||
ETH_WS_PATH: "dapptools:8546"
|
|
||||||
ETH_HTTP_PATH: "dapptools:8545"
|
|
||||||
ETH_CHAIN_ID: 4
|
|
||||||
ETH_NETWORK_ID: 4
|
|
||||||
VDB_COMMAND: sync
|
|
||||||
|
|
||||||
eth-server:
|
eth-server:
|
||||||
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
build:
|
build:
|
||||||
@@ -47,16 +50,22 @@ services:
|
|||||||
- alpine:latest
|
- alpine:latest
|
||||||
- golang:1.13-alpine
|
- golang:1.13-alpine
|
||||||
environment:
|
environment:
|
||||||
|
IPLD_SERVER_GRAPHQL: "true"
|
||||||
|
IPLD_POSTGRAPHILEPATH: http://graphql:5000
|
||||||
|
ETH_SERVER_HTTPPATH: 0.0.0.0:8081
|
||||||
VDB_COMMAND: "serve"
|
VDB_COMMAND: "serve"
|
||||||
|
ETH_CHAIN_CONFIG: "/tmp/chain.json"
|
||||||
DATABASE_NAME: "vulcanize_public"
|
DATABASE_NAME: "vulcanize_public"
|
||||||
DATABASE_HOSTNAME: "db"
|
DATABASE_HOSTNAME: "db"
|
||||||
DATABASE_PORT: 5432
|
DATABASE_PORT: 5432
|
||||||
DATABASE_USER: "vdbm"
|
DATABASE_USER: "vdbm"
|
||||||
DATABASE_PASSWORD: "password"
|
DATABASE_PASSWORD: "password"
|
||||||
SERVER_WS_PATH: "0.0.0.0:8081"
|
ETH_CHAIN_ID: 4
|
||||||
SERVER_HTTP_PATH: "0.0.0.0:8082"
|
volumes:
|
||||||
|
- type: bind
|
||||||
|
source: ./chain.json
|
||||||
|
target: /tmp/chain.json
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8080:8080"
|
|
||||||
- "127.0.0.1:8081:8081"
|
- "127.0.0.1:8081:8081"
|
||||||
|
|
||||||
graphql:
|
graphql:
|
||||||
|
|||||||
@@ -4,26 +4,29 @@ go 1.13
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ethereum/go-ethereum v1.9.25
|
github.com/ethereum/go-ethereum v1.9.25
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20201003130358-c5bdf3b1108e
|
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29
|
||||||
github.com/ipfs/go-block-format v0.0.2
|
github.com/ipfs/go-block-format v0.0.2
|
||||||
github.com/ipfs/go-cid v0.0.7
|
github.com/ipfs/go-cid v0.0.7
|
||||||
github.com/ipfs/go-ipfs-blockstore v1.0.1
|
github.com/ipfs/go-ipfs-blockstore v1.0.1
|
||||||
github.com/ipfs/go-ipfs-ds-help v1.0.0
|
github.com/ipfs/go-ipfs-ds-help v1.0.0
|
||||||
github.com/ipfs/go-ipld-format v0.2.0
|
github.com/ipfs/go-ipld-format v0.2.0
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/lib/pq v1.8.0
|
github.com/lib/pq v1.10.2
|
||||||
|
github.com/machinebox/graphql v0.2.2
|
||||||
github.com/multiformats/go-multihash v0.0.14
|
github.com/multiformats/go-multihash v0.0.14
|
||||||
github.com/onsi/ginkgo v1.15.0
|
github.com/onsi/ginkgo v1.16.2
|
||||||
github.com/onsi/gomega v1.10.1
|
github.com/onsi/gomega v1.10.1
|
||||||
github.com/prometheus/client_golang v1.5.1
|
github.com/prometheus/client_golang v1.5.1
|
||||||
github.com/sirupsen/logrus v1.6.0
|
github.com/shirou/gopsutil v3.21.5+incompatible // indirect
|
||||||
github.com/spf13/cobra v1.0.0
|
github.com/sirupsen/logrus v1.7.0
|
||||||
|
github.com/spf13/cobra v1.1.1
|
||||||
github.com/spf13/viper v1.7.0
|
github.com/spf13/viper v1.7.0
|
||||||
github.com/vulcanize/ipld-eth-indexer v0.7.1-alpha
|
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||||
|
github.com/vulcanize/gap-filler v0.3.1
|
||||||
github.com/vulcanize/ipfs-ethdb v0.0.2-alpha
|
github.com/vulcanize/ipfs-ethdb v0.0.2-alpha
|
||||||
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b // indirect
|
github.com/vulcanize/ipld-eth-indexer v0.7.1-alpha.0.20210805022537-b4692fa49849
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/ethereum/go-ethereum v1.9.25 => github.com/vulcanize/go-ethereum v1.9.25-statediff-0.0.15
|
replace github.com/ethereum/go-ethereum v1.9.25 => github.com/vulcanize/go-ethereum v1.10.4-statediff-0.0.25
|
||||||
|
|
||||||
replace github.com/vulcanize/ipfs-ethdb v0.0.2-alpha => github.com/vulcanize/pg-ipfs-ethdb v0.0.2-alpha
|
replace github.com/vulcanize/ipfs-ethdb v0.0.2-alpha => github.com/vulcanize/pg-ipfs-ethdb v0.0.2-alpha
|
||||||
+142
-31
@@ -18,27 +18,27 @@ package eth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/statediff"
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
|
||||||
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -48,6 +48,7 @@ const APIName = "eth"
|
|||||||
// APIVersion is the version of the watcher's eth api
|
// APIVersion is the version of the watcher's eth api
|
||||||
const APIVersion = "0.0.1"
|
const APIVersion = "0.0.1"
|
||||||
|
|
||||||
|
// PublicEthAPI is the eth namespace API
|
||||||
type PublicEthAPI struct {
|
type PublicEthAPI struct {
|
||||||
// Local db backend
|
// Local db backend
|
||||||
B *Backend
|
B *Backend
|
||||||
@@ -166,6 +167,21 @@ func (pea *PublicEthAPI) GetBlockByHash(ctx context.Context, hash common.Hash, f
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
|
||||||
|
func (pea *PublicEthAPI) ChainId() hexutil.Uint64 {
|
||||||
|
chainID := new(big.Int)
|
||||||
|
block, err := pea.B.CurrentBlock()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("ChainId failed with err %s", err.Error())
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if config := pea.B.Config.ChainConfig; config.IsEIP155(block.Number()) {
|
||||||
|
chainID = config.ChainID
|
||||||
|
}
|
||||||
|
return (hexutil.Uint64)(chainID.Uint64())
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Uncles
|
Uncles
|
||||||
@@ -376,7 +392,12 @@ func (pea *PublicEthAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Contex
|
|||||||
func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
||||||
tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash)
|
tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash)
|
||||||
if tx != nil && err == nil {
|
if tx != nil && err == nil {
|
||||||
return NewRPCTransaction(tx, blockHash, blockNumber, index), nil
|
header, err := pea.B.HeaderByHash(ctx, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee), nil
|
||||||
}
|
}
|
||||||
if pea.rpc != nil {
|
if pea.rpc != nil {
|
||||||
var tx *RPCTransaction
|
var tx *RPCTransaction
|
||||||
@@ -439,6 +460,14 @@ func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash co
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
block, err := pea.B.BlockByHash(ctx, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = receipts.DeriveFields(pea.B.Config.ChainConfig, blockHash, blockNumber, block.Transactions())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if len(receipts) <= int(index) {
|
if len(receipts) <= int(index) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -505,30 +534,30 @@ func (pea *PublicEthAPI) remoteGetTransactionReceipt(ctx context.Context, hash c
|
|||||||
// GetLogs returns logs matching the given argument that are stored within the state.
|
// GetLogs returns logs matching the given argument that are stored within the state.
|
||||||
//
|
//
|
||||||
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
||||||
func (pea *PublicEthAPI) GetLogs(ctx context.Context, crit ethereum.FilterQuery) ([]*types.Log, error) {
|
func (pea *PublicEthAPI) GetLogs(ctx context.Context, crit filters.FilterCriteria) ([]*types.Log, error) {
|
||||||
logs, err := pea.localGetLogs(ctx, crit)
|
logs, err := pea.localGetLogs(crit)
|
||||||
if err != nil && pea.rpc != nil {
|
if err != nil && pea.rpc != nil {
|
||||||
if arg, err := toFilterArg(crit); err == nil {
|
var res []*types.Log
|
||||||
var res []*types.Log
|
if err := pea.rpc.CallContext(ctx, &res, "eth_getLogs", crit); err == nil {
|
||||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getLogs", arg); err == nil {
|
go pea.writeStateDiffWithCriteria(crit)
|
||||||
go pea.writeStateDiffWithCriteria(crit)
|
return res, nil
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pea *PublicEthAPI) localGetLogs(ctx context.Context, crit ethereum.FilterQuery) ([]*types.Log, error) {
|
func (pea *PublicEthAPI) localGetLogs(crit filters.FilterCriteria) ([]*types.Log, error) {
|
||||||
// TODO: this can be optimized away from using the old cid retriever and ipld fetcher interfaces
|
// TODO: this can be optimized away from using the old cid retriever and ipld fetcher interfaces
|
||||||
// Convert FilterQuery into ReceiptFilter
|
// Convert FilterQuery into ReceiptFilter
|
||||||
addrStrs := make([]string, len(crit.Addresses))
|
addrStrs := make([]string, len(crit.Addresses))
|
||||||
for i, addr := range crit.Addresses {
|
for i, addr := range crit.Addresses {
|
||||||
addrStrs[i] = addr.String()
|
addrStrs[i] = addr.String()
|
||||||
}
|
}
|
||||||
topicStrSets := make([][]string, 4)
|
|
||||||
|
topicStrSets := make([][]string, len(crit.Topics))
|
||||||
for i, topicSet := range crit.Topics {
|
for i, topicSet := range crit.Topics {
|
||||||
if i > 3 {
|
if i > 3 {
|
||||||
|
topicStrSets = topicStrSets[:4]
|
||||||
// don't allow more than 4 topics
|
// don't allow more than 4 topics
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -570,8 +599,13 @@ func (pea *PublicEthAPI) localGetLogs(ctx context.Context, crit ethereum.FilterQ
|
|||||||
if err := tx.Commit(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return extractLogsOfInterest(rctIPLDs, filter.Topics)
|
block, err := pea.B.BlockByHash(context.Background(), *crit.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return extractLogsOfInterest(pea.B.Config.ChainConfig, *crit.BlockHash, block.NumberU64(), block.Transactions(), rctIPLDs, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, create block range from criteria
|
// Otherwise, create block range from criteria
|
||||||
// nil values are filled in; to request a single block have both ToBlock and FromBlock equal that number
|
// nil values are filled in; to request a single block have both ToBlock and FromBlock equal that number
|
||||||
startingBlock := crit.FromBlock
|
startingBlock := crit.FromBlock
|
||||||
@@ -579,6 +613,7 @@ func (pea *PublicEthAPI) localGetLogs(ctx context.Context, crit ethereum.FilterQ
|
|||||||
if startingBlock == nil {
|
if startingBlock == nil {
|
||||||
startingBlock = common.Big0
|
startingBlock = common.Big0
|
||||||
}
|
}
|
||||||
|
|
||||||
if endingBlock == nil {
|
if endingBlock == nil {
|
||||||
endingBlockInt, err := pea.B.Retriever.RetrieveLastBlockNumber()
|
endingBlockInt, err := pea.B.Retriever.RetrieveLastBlockNumber()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -586,24 +621,38 @@ func (pea *PublicEthAPI) localGetLogs(ctx context.Context, crit ethereum.FilterQ
|
|||||||
}
|
}
|
||||||
endingBlock = big.NewInt(endingBlockInt)
|
endingBlock = big.NewInt(endingBlockInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
start := startingBlock.Int64()
|
start := startingBlock.Int64()
|
||||||
end := endingBlock.Int64()
|
end := endingBlock.Int64()
|
||||||
allRctCIDs := make([]eth.ReceiptModel, 0)
|
var logs []*types.Log
|
||||||
for i := start; i <= end; i++ {
|
for i := start; i <= end; i++ {
|
||||||
rctCIDs, err := pea.B.Retriever.RetrieveRctCIDs(tx, filter, i, nil, nil)
|
rctCIDs, err := pea.B.Retriever.RetrieveRctCIDs(tx, filter, i, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
allRctCIDs = append(allRctCIDs, rctCIDs...)
|
|
||||||
}
|
block, err := pea.B.BlockByNumber(context.Background(), rpc.BlockNumber(i))
|
||||||
rctIPLDs, err := pea.B.Fetcher.FetchRcts(tx, allRctCIDs)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
|
|
||||||
|
rctIPLDs, err := pea.B.Fetcher.FetchRcts(tx, rctCIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log, err := extractLogsOfInterest(pea.B.Config.ChainConfig, block.Hash(), uint64(i), block.Transactions(), rctIPLDs, filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logs = append(logs, log...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Commit(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
logs, err := extractLogsOfInterest(rctIPLDs, filter.Topics)
|
|
||||||
return logs, err // need to return err variable so that we return the err = tx.Commit() assignment in the defer
|
return logs, err // need to return err variable so that we return the err = tx.Commit() assignment in the defer
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,6 +677,10 @@ func (pea *PublicEthAPI) GetBalance(ctx context.Context, address common.Address,
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return (*hexutil.Big)(big.NewInt(0)), nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,7 +698,17 @@ func (pea *PublicEthAPI) localGetBalance(ctx context.Context, address common.Add
|
|||||||
func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
||||||
storageVal, err := pea.B.GetStorageByNumberOrHash(ctx, address, common.HexToHash(key), blockNrOrHash)
|
storageVal, err := pea.B.GetStorageByNumberOrHash(ctx, address, common.HexToHash(key), blockNrOrHash)
|
||||||
if storageVal != nil && err == nil {
|
if storageVal != nil && err == nil {
|
||||||
return storageVal, nil
|
var value common.Hash
|
||||||
|
_, content, _, err := rlp.Split(storageVal)
|
||||||
|
if err == io.ErrUnexpectedEOF {
|
||||||
|
return hexutil.Bytes{}, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
value.SetBytes(content)
|
||||||
|
|
||||||
|
return value[:], nil
|
||||||
}
|
}
|
||||||
if pea.rpc != nil {
|
if pea.rpc != nil {
|
||||||
var res hexutil.Bytes
|
var res hexutil.Bytes
|
||||||
@@ -654,6 +717,9 @@ func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Addres
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return make([]byte, 32), nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,6 +736,10 @@ func (pea *PublicEthAPI) GetCode(ctx context.Context, address common.Address, bl
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,13 +883,47 @@ func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.Bl
|
|||||||
if args.Gas != nil {
|
if args.Gas != nil {
|
||||||
gas = uint64(*args.Gas)
|
gas = uint64(*args.Gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalGasCap != nil && globalGasCap.Uint64() < gas {
|
if globalGasCap != nil && globalGasCap.Uint64() < gas {
|
||||||
logrus.Warnf("Caller gas above allowance, capping; requested: %d, cap: %d", gas, globalGasCap)
|
logrus.Warnf("Caller gas above allowance, capping; requested: %d, cap: %d", gas, globalGasCap)
|
||||||
gas = globalGasCap.Uint64()
|
gas = globalGasCap.Uint64()
|
||||||
}
|
}
|
||||||
gasPrice := new(big.Int).SetUint64(params.GWei)
|
|
||||||
if args.GasPrice != nil {
|
var (
|
||||||
gasPrice = args.GasPrice.ToInt()
|
gasPrice *big.Int
|
||||||
|
gasFeeCap *big.Int
|
||||||
|
gasTipCap *big.Int
|
||||||
|
)
|
||||||
|
|
||||||
|
if header.BaseFee == nil {
|
||||||
|
// If there's no basefee, then it must be a non-1559 execution
|
||||||
|
gasPrice = new(big.Int)
|
||||||
|
if args.GasPrice != nil {
|
||||||
|
gasPrice = args.GasPrice.ToInt()
|
||||||
|
}
|
||||||
|
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||||
|
} else {
|
||||||
|
// A basefee is provided, necessitating 1559-type execution
|
||||||
|
if args.GasPrice != nil {
|
||||||
|
// User specified the legacy gas field, convert to 1559 gas typing
|
||||||
|
gasPrice = args.GasPrice.ToInt()
|
||||||
|
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||||
|
} else {
|
||||||
|
// User specified 1559 gas feilds (or none), use those
|
||||||
|
gasFeeCap = new(big.Int)
|
||||||
|
if args.MaxFeePerGas != nil {
|
||||||
|
gasFeeCap = args.MaxFeePerGas.ToInt()
|
||||||
|
}
|
||||||
|
gasTipCap = new(big.Int)
|
||||||
|
if args.MaxPriorityFeePerGas != nil {
|
||||||
|
gasTipCap = args.MaxPriorityFeePerGas.ToInt()
|
||||||
|
}
|
||||||
|
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
|
||||||
|
gasPrice = new(big.Int)
|
||||||
|
if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
|
||||||
|
gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, header.BaseFee), gasFeeCap)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value := new(big.Int)
|
value := new(big.Int)
|
||||||
@@ -828,12 +932,19 @@ func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.Bl
|
|||||||
}
|
}
|
||||||
|
|
||||||
var data []byte
|
var data []byte
|
||||||
if args.Data != nil {
|
if args.Input != nil {
|
||||||
data = []byte(*args.Data)
|
data = *args.Input
|
||||||
|
} else if args.Data != nil {
|
||||||
|
data = *args.Data
|
||||||
|
}
|
||||||
|
|
||||||
|
var accessList types.AccessList
|
||||||
|
if args.AccessList != nil {
|
||||||
|
accessList = *args.AccessList
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new call message
|
// Create new call message
|
||||||
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false)
|
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, false)
|
||||||
|
|
||||||
// Setup context so it may be cancelled the call has completed
|
// Setup context so it may be cancelled the call has completed
|
||||||
// or, in case of unmetered gas, setup a context with a timeout.
|
// or, in case of unmetered gas, setup a context with a timeout.
|
||||||
@@ -889,7 +1000,7 @@ func (pea *PublicEthAPI) writeStateDiffAtOrFor(blockNrOrHash rpc.BlockNumberOrHa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// writeStateDiffWithCriteria calls out to the proxy statediffing geth client to fill in a gap in the index
|
// writeStateDiffWithCriteria calls out to the proxy statediffing geth client to fill in a gap in the index
|
||||||
func (pea *PublicEthAPI) writeStateDiffWithCriteria(crit ethereum.FilterQuery) {
|
func (pea *PublicEthAPI) writeStateDiffWithCriteria(crit filters.FilterCriteria) {
|
||||||
// short circuit right away if the proxy doesn't support diffing
|
// short circuit right away if the proxy doesn't support diffing
|
||||||
if !pea.supportsStateDiff {
|
if !pea.supportsStateDiff {
|
||||||
return
|
return
|
||||||
|
|||||||
+127
-64
@@ -18,13 +18,16 @@ package eth_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
@@ -39,13 +42,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f")
|
randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f")
|
||||||
randomHash = crypto.Keccak256Hash(randomAddr.Bytes())
|
randomHash = crypto.Keccak256Hash(randomAddr.Bytes())
|
||||||
number = rpc.BlockNumber(test_helpers.BlockNumber.Int64())
|
number = rpc.BlockNumber(test_helpers.BlockNumber.Int64())
|
||||||
wrongNumber = rpc.BlockNumber(number + 1)
|
londonBlockNum = rpc.BlockNumber(test_helpers.LondonBlockNum.Int64())
|
||||||
blockHash = test_helpers.MockBlock.Header().Hash()
|
wrongNumber = rpc.BlockNumber(number + 1)
|
||||||
ctx = context.Background()
|
blockHash = test_helpers.MockBlock.Header().Hash()
|
||||||
expectedBlock = map[string]interface{}{
|
londonBlockHash = test_helpers.MockLondonBlock.Header().Hash()
|
||||||
|
baseFee = test_helpers.MockLondonBlock.BaseFee()
|
||||||
|
ctx = context.Background()
|
||||||
|
expectedBlock = map[string]interface{}{
|
||||||
"number": (*hexutil.Big)(test_helpers.MockBlock.Number()),
|
"number": (*hexutil.Big)(test_helpers.MockBlock.Number()),
|
||||||
"hash": test_helpers.MockBlock.Hash(),
|
"hash": test_helpers.MockBlock.Hash(),
|
||||||
"parentHash": test_helpers.MockBlock.ParentHash(),
|
"parentHash": test_helpers.MockBlock.ParentHash(),
|
||||||
@@ -125,13 +131,14 @@ var (
|
|||||||
"receiptsRoot": test_helpers.MockUncles[1].ReceiptHash,
|
"receiptsRoot": test_helpers.MockUncles[1].ReceiptHash,
|
||||||
"uncles": []common.Hash{},
|
"uncles": []common.Hash{},
|
||||||
}
|
}
|
||||||
expectedTransaction = eth.NewRPCTransaction(test_helpers.MockTransactions[0], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 0)
|
expectedTransaction = eth.NewRPCTransaction(test_helpers.MockTransactions[0], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 0, test_helpers.MockBlock.BaseFee())
|
||||||
expectedTransaction2 = eth.NewRPCTransaction(test_helpers.MockTransactions[1], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 1)
|
expectedTransaction2 = eth.NewRPCTransaction(test_helpers.MockTransactions[1], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 1, test_helpers.MockBlock.BaseFee())
|
||||||
expectedTransaction3 = eth.NewRPCTransaction(test_helpers.MockTransactions[2], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 2)
|
expectedTransaction3 = eth.NewRPCTransaction(test_helpers.MockTransactions[2], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 2, test_helpers.MockBlock.BaseFee())
|
||||||
expectRawTx, _ = rlp.EncodeToBytes(test_helpers.MockTransactions[0])
|
expectedLondonTransaction = eth.NewRPCTransaction(test_helpers.MockLondonTransactions[0], test_helpers.MockLondonBlock.Hash(), test_helpers.MockLondonBlock.NumberU64(), 0, test_helpers.MockLondonBlock.BaseFee())
|
||||||
expectRawTx2, _ = rlp.EncodeToBytes(test_helpers.MockTransactions[1])
|
expectRawTx, _ = rlp.EncodeToBytes(test_helpers.MockTransactions[0])
|
||||||
expectRawTx3, _ = rlp.EncodeToBytes(test_helpers.MockTransactions[2])
|
expectRawTx2, _ = rlp.EncodeToBytes(test_helpers.MockTransactions[1])
|
||||||
expectedReceipt = map[string]interface{}{
|
expectRawTx3, _ = rlp.EncodeToBytes(test_helpers.MockTransactions[2])
|
||||||
|
expectedReceipt = map[string]interface{}{
|
||||||
"blockHash": blockHash,
|
"blockHash": blockHash,
|
||||||
"blockNumber": hexutil.Uint64(uint64(number.Int64())),
|
"blockNumber": hexutil.Uint64(uint64(number.Int64())),
|
||||||
"transactionHash": expectedTransaction.Hash,
|
"transactionHash": expectedTransaction.Hash,
|
||||||
@@ -168,7 +175,7 @@ var (
|
|||||||
"to": expectedTransaction3.To,
|
"to": expectedTransaction3.To,
|
||||||
"gasUsed": hexutil.Uint64(test_helpers.MockReceipts[2].GasUsed),
|
"gasUsed": hexutil.Uint64(test_helpers.MockReceipts[2].GasUsed),
|
||||||
"cumulativeGasUsed": hexutil.Uint64(test_helpers.MockReceipts[2].CumulativeGasUsed),
|
"cumulativeGasUsed": hexutil.Uint64(test_helpers.MockReceipts[2].CumulativeGasUsed),
|
||||||
"contractAddress": nil,
|
"contractAddress": test_helpers.ContractAddress,
|
||||||
"logs": test_helpers.MockReceipts[2].Logs,
|
"logs": test_helpers.MockReceipts[2].Logs,
|
||||||
"logsBloom": test_helpers.MockReceipts[2].Bloom,
|
"logsBloom": test_helpers.MockReceipts[2].Bloom,
|
||||||
"root": hexutil.Bytes(test_helpers.MockReceipts[2].PostState),
|
"root": hexutil.Bytes(test_helpers.MockReceipts[2].PostState),
|
||||||
@@ -177,8 +184,9 @@ var (
|
|||||||
|
|
||||||
var _ = Describe("API", func() {
|
var _ = Describe("API", func() {
|
||||||
var (
|
var (
|
||||||
db *postgres.DB
|
db *postgres.DB
|
||||||
api *eth.PublicEthAPI
|
api *eth.PublicEthAPI
|
||||||
|
chainConfig = params.TestChainConfig
|
||||||
)
|
)
|
||||||
// Test db setup, rather than using BeforeEach we only need to setup once since the tests do not mutate the database
|
// Test db setup, rather than using BeforeEach we only need to setup once since the tests do not mutate the database
|
||||||
// Note: if you focus one of the tests be sure to focus this and the defered It()
|
// Note: if you focus one of the tests be sure to focus this and the defered It()
|
||||||
@@ -187,7 +195,11 @@ var _ = Describe("API", func() {
|
|||||||
db, err = shared.SetupDB()
|
db, err = shared.SetupDB()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
indexAndPublisher := eth2.NewIPLDPublisher(db)
|
indexAndPublisher := eth2.NewIPLDPublisher(db)
|
||||||
backend, err := eth.NewEthBackend(db, ð.Config{})
|
backend, err := eth.NewEthBackend(db, ð.Config{
|
||||||
|
ChainConfig: chainConfig,
|
||||||
|
VmConfig: vm.Config{},
|
||||||
|
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
|
||||||
|
})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
api = eth.NewPublicEthAPI(backend, nil, false)
|
api = eth.NewPublicEthAPI(backend, nil, false)
|
||||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
||||||
@@ -200,7 +212,11 @@ var _ = Describe("API", func() {
|
|||||||
uncleHashes[i] = uncle.Hash()
|
uncleHashes[i] = uncle.Hash()
|
||||||
}
|
}
|
||||||
expectedBlock["uncles"] = uncleHashes
|
expectedBlock["uncles"] = uncleHashes
|
||||||
|
|
||||||
|
err = indexAndPublisher.Publish(test_helpers.MockConvertedLondonPayload)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
// Single test db tear down at end of all tests
|
// Single test db tear down at end of all tests
|
||||||
defer It("test teardown", func() { eth.TearDownDB(db) })
|
defer It("test teardown", func() { eth.TearDownDB(db) })
|
||||||
/*
|
/*
|
||||||
@@ -242,7 +258,7 @@ var _ = Describe("API", func() {
|
|||||||
bn := api.BlockNumber()
|
bn := api.BlockNumber()
|
||||||
ubn := (uint64)(bn)
|
ubn := (uint64)(bn)
|
||||||
subn := strconv.FormatUint(ubn, 10)
|
subn := strconv.FormatUint(ubn, 10)
|
||||||
Expect(subn).To(Equal(test_helpers.BlockNumber.String()))
|
Expect(subn).To(Equal(test_helpers.LondonBlockNum.String()))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -271,10 +287,20 @@ var _ = Describe("API", func() {
|
|||||||
Expect(val).To(Equal(block[key]))
|
Expect(val).To(Equal(block[key]))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
It("Throws an error if a block cannot be found", func() {
|
It("Returns `nil` if a block cannot be found", func() {
|
||||||
_, err := api.GetBlockByNumber(ctx, wrongNumber, false)
|
block, err := api.GetBlockByNumber(ctx, wrongNumber, false)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(block).To(BeNil())
|
||||||
|
})
|
||||||
|
It("Fetch BaseFee from london block by block number, returns `nil` for legacy block", func() {
|
||||||
|
block, err := api.GetBlockByNumber(ctx, number, false)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
_, ok := block["baseFee"]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
block, err = api.GetBlockByNumber(ctx, londonBlockNum, false)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(block["baseFee"].(*big.Int)).To(Equal(baseFee))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -303,10 +329,20 @@ var _ = Describe("API", func() {
|
|||||||
Expect(val).To(Equal(block[key]))
|
Expect(val).To(Equal(block[key]))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
It("Throws an error if a block cannot be found", func() {
|
It("Returns `nil` if a block cannot be found", func() {
|
||||||
_, err := api.GetBlockByHash(ctx, randomHash, false)
|
block, err := api.GetBlockByHash(ctx, randomHash, false)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(block).To(BeZero())
|
||||||
|
})
|
||||||
|
It("Fetch BaseFee from london block by block hash, returns `nil` for legacy block", func() {
|
||||||
|
block, err := api.GetBlockByHash(ctx, test_helpers.MockBlock.Hash(), true)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
_, ok := block["baseFee"]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
block, err = api.GetBlockByHash(ctx, londonBlockHash, false)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(block["baseFee"].(*big.Int)).To(Equal(baseFee))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -325,10 +361,10 @@ var _ = Describe("API", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(uncle2).To(Equal(expectedUncle2))
|
Expect(uncle2).To(Equal(expectedUncle2))
|
||||||
})
|
})
|
||||||
It("Throws an error if an block for blocknumber cannot be found", func() {
|
It("Returns `nil` if an block for block number cannot be found", func() {
|
||||||
_, err := api.GetUncleByBlockNumberAndIndex(ctx, wrongNumber, 0)
|
block, err := api.GetUncleByBlockNumberAndIndex(ctx, wrongNumber, 0)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(block).To(BeNil())
|
||||||
})
|
})
|
||||||
It("Returns `nil` if an uncle at the provided index does not exist for the block found for the provided block number", func() {
|
It("Returns `nil` if an uncle at the provided index does not exist for the block found for the provided block number", func() {
|
||||||
uncle, err := api.GetUncleByBlockNumberAndIndex(ctx, number, 2)
|
uncle, err := api.GetUncleByBlockNumberAndIndex(ctx, number, 2)
|
||||||
@@ -346,10 +382,10 @@ var _ = Describe("API", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(uncle2).To(Equal(expectedUncle2))
|
Expect(uncle2).To(Equal(expectedUncle2))
|
||||||
})
|
})
|
||||||
It("Throws an error if an block for blockhash cannot be found", func() {
|
It("Returns `nil` if a block for blockhash cannot be found", func() {
|
||||||
_, err := api.GetUncleByBlockHashAndIndex(ctx, randomHash, 0)
|
block, err := api.GetUncleByBlockHashAndIndex(ctx, randomHash, 0)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(block).To(BeNil())
|
||||||
})
|
})
|
||||||
It("Returns `nil` if an uncle at the provided index does not exist for the block with the provided hash", func() {
|
It("Returns `nil` if an uncle at the provided index does not exist for the block with the provided hash", func() {
|
||||||
uncle, err := api.GetUncleByBlockHashAndIndex(ctx, blockHash, 2)
|
uncle, err := api.GetUncleByBlockHashAndIndex(ctx, blockHash, 2)
|
||||||
@@ -361,6 +397,7 @@ var _ = Describe("API", func() {
|
|||||||
Describe("eth_getUncleCountByBlockNumber", func() {
|
Describe("eth_getUncleCountByBlockNumber", func() {
|
||||||
It("Retrieves the number of uncles for the canonical block with the provided number", func() {
|
It("Retrieves the number of uncles for the canonical block with the provided number", func() {
|
||||||
count := api.GetUncleCountByBlockNumber(ctx, number)
|
count := api.GetUncleCountByBlockNumber(ctx, number)
|
||||||
|
Expect(*count).NotTo(Equal(nil))
|
||||||
Expect(uint64(*count)).To(Equal(uint64(2)))
|
Expect(uint64(*count)).To(Equal(uint64(2)))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -368,6 +405,7 @@ var _ = Describe("API", func() {
|
|||||||
Describe("eth_getUncleCountByBlockHash", func() {
|
Describe("eth_getUncleCountByBlockHash", func() {
|
||||||
It("Retrieves the number of uncles for the block with the provided hash", func() {
|
It("Retrieves the number of uncles for the block with the provided hash", func() {
|
||||||
count := api.GetUncleCountByBlockHash(ctx, blockHash)
|
count := api.GetUncleCountByBlockHash(ctx, blockHash)
|
||||||
|
Expect(*count).NotTo(Equal(nil))
|
||||||
Expect(uint64(*count)).To(Equal(uint64(2)))
|
Expect(uint64(*count)).To(Equal(uint64(2)))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -427,6 +465,13 @@ var _ = Describe("API", func() {
|
|||||||
Expect(tx).ToNot(BeNil())
|
Expect(tx).ToNot(BeNil())
|
||||||
Expect(tx).To(Equal(expectedTransaction3))
|
Expect(tx).To(Equal(expectedTransaction3))
|
||||||
})
|
})
|
||||||
|
It("Retrieves the GasFeeCap and GasTipCap for dynamic transaction from the london block hash", func() {
|
||||||
|
tx := api.GetTransactionByBlockNumberAndIndex(ctx, londonBlockNum, 0)
|
||||||
|
Expect(tx).ToNot(BeNil())
|
||||||
|
Expect(tx.GasFeeCap).To(Equal((*hexutil.Big)(test_helpers.MockLondonTransactions[0].GasFeeCap())))
|
||||||
|
Expect(tx.GasTipCap).To(Equal((*hexutil.Big)(test_helpers.MockLondonTransactions[0].GasTipCap())))
|
||||||
|
Expect(tx).To(Equal(expectedLondonTransaction))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("eth_getTransactionByBlockHashAndIndex", func() {
|
Describe("eth_getTransactionByBlockHashAndIndex", func() {
|
||||||
@@ -443,6 +488,14 @@ var _ = Describe("API", func() {
|
|||||||
Expect(tx).ToNot(BeNil())
|
Expect(tx).ToNot(BeNil())
|
||||||
Expect(tx).To(Equal(expectedTransaction3))
|
Expect(tx).To(Equal(expectedTransaction3))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("Retrieves the GasFeeCap and GasTipCap for dynamic transaction from the london block hash", func() {
|
||||||
|
tx := api.GetTransactionByBlockHashAndIndex(ctx, londonBlockHash, 0)
|
||||||
|
Expect(tx).ToNot(BeNil())
|
||||||
|
Expect(tx.GasFeeCap).To(Equal((*hexutil.Big)(test_helpers.MockLondonTransactions[0].GasFeeCap())))
|
||||||
|
Expect(tx.GasTipCap).To(Equal((*hexutil.Big)(test_helpers.MockLondonTransactions[0].GasTipCap())))
|
||||||
|
Expect(tx).To(Equal(expectedLondonTransaction))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("eth_getRawTransactionByBlockNumberAndIndex", func() {
|
Describe("eth_getRawTransactionByBlockNumberAndIndex", func() {
|
||||||
@@ -554,7 +607,7 @@ var _ = Describe("API", func() {
|
|||||||
|
|
||||||
Describe("eth_getLogs", func() {
|
Describe("eth_getLogs", func() {
|
||||||
It("Retrieves receipt logs that match the provided topics within the provided range", func() {
|
It("Retrieves receipt logs that match the provided topics within the provided range", func() {
|
||||||
crit := ethereum.FilterQuery{
|
crit := filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
common.HexToHash("0x04"),
|
common.HexToHash("0x04"),
|
||||||
@@ -568,7 +621,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
common.HexToHash("0x04"),
|
common.HexToHash("0x04"),
|
||||||
@@ -583,7 +636,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(2))
|
Expect(len(logs)).To(Equal(2))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
common.HexToHash("0x04"),
|
common.HexToHash("0x04"),
|
||||||
@@ -598,7 +651,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
common.HexToHash("0x04"),
|
common.HexToHash("0x04"),
|
||||||
@@ -614,7 +667,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(len(logs)).To(Equal(0))
|
Expect(len(logs)).To(Equal(0))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
common.HexToHash("0x04"),
|
common.HexToHash("0x04"),
|
||||||
@@ -631,7 +684,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
common.HexToHash("0x05"),
|
common.HexToHash("0x05"),
|
||||||
@@ -648,7 +701,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
common.HexToHash("0x05"),
|
common.HexToHash("0x05"),
|
||||||
@@ -666,7 +719,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
common.HexToHash("0x04"),
|
common.HexToHash("0x04"),
|
||||||
@@ -685,7 +738,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(2))
|
Expect(len(logs)).To(Equal(2))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -700,7 +753,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -715,7 +768,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
Topics: [][]common.Hash{},
|
Topics: [][]common.Hash{},
|
||||||
FromBlock: test_helpers.MockBlock.Number(),
|
FromBlock: test_helpers.MockBlock.Number(),
|
||||||
ToBlock: test_helpers.MockBlock.Number(),
|
ToBlock: test_helpers.MockBlock.Number(),
|
||||||
@@ -728,7 +781,7 @@ var _ = Describe("API", func() {
|
|||||||
|
|
||||||
It("Uses the provided blockhash if one is provided", func() {
|
It("Uses the provided blockhash if one is provided", func() {
|
||||||
hash := test_helpers.MockBlock.Hash()
|
hash := test_helpers.MockBlock.Hash()
|
||||||
crit := ethereum.FilterQuery{
|
crit := filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{},
|
{},
|
||||||
@@ -742,7 +795,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
@@ -758,7 +811,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{},
|
{},
|
||||||
@@ -772,7 +825,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
@@ -788,7 +841,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
@@ -803,7 +856,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(len(logs)).To(Equal(0))
|
Expect(len(logs)).To(Equal(0))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
@@ -820,7 +873,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(1))
|
Expect(len(logs)).To(Equal(1))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
@@ -834,7 +887,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(2))
|
Expect(len(logs)).To(Equal(2))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{
|
Topics: [][]common.Hash{
|
||||||
{
|
{
|
||||||
@@ -852,7 +905,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(len(logs)).To(Equal(2))
|
Expect(len(logs)).To(Equal(2))
|
||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
||||||
|
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Topics: [][]common.Hash{},
|
Topics: [][]common.Hash{},
|
||||||
}
|
}
|
||||||
@@ -864,7 +917,7 @@ var _ = Describe("API", func() {
|
|||||||
|
|
||||||
It("Filters on contract address if any are provided", func() {
|
It("Filters on contract address if any are provided", func() {
|
||||||
hash := test_helpers.MockBlock.Hash()
|
hash := test_helpers.MockBlock.Hash()
|
||||||
crit := ethereum.FilterQuery{
|
crit := filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Addresses: []common.Address{
|
Addresses: []common.Address{
|
||||||
test_helpers.Address,
|
test_helpers.Address,
|
||||||
@@ -886,7 +939,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
||||||
|
|
||||||
hash = test_helpers.MockBlock.Hash()
|
hash = test_helpers.MockBlock.Hash()
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Addresses: []common.Address{
|
Addresses: []common.Address{
|
||||||
test_helpers.Address,
|
test_helpers.Address,
|
||||||
@@ -909,7 +962,7 @@ var _ = Describe("API", func() {
|
|||||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
||||||
|
|
||||||
hash = test_helpers.MockBlock.Hash()
|
hash = test_helpers.MockBlock.Hash()
|
||||||
crit = ethereum.FilterQuery{
|
crit = filters.FilterCriteria{
|
||||||
BlockHash: &hash,
|
BlockHash: &hash,
|
||||||
Addresses: []common.Address{
|
Addresses: []common.Address{
|
||||||
test_helpers.Address,
|
test_helpers.Address,
|
||||||
@@ -948,8 +1001,17 @@ var _ = Describe("API", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
})
|
})
|
||||||
It("Throws an error for an account it cannot find the balance for", func() {
|
It("Retrieves the eth balance for the non-existing account address at the block with the provided hash", func() {
|
||||||
_, err := api.GetBalance(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true))
|
bal, err := api.GetBalance(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
|
})
|
||||||
|
It("Throws an error for an account of a non-existing block hash", func() {
|
||||||
|
_, err := api.GetBalance(ctx, test_helpers.AccountAddresss, rpc.BlockNumberOrHashWithHash(randomHash, true))
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
It("Throws an error for an account of a non-existing block number", func() {
|
||||||
|
_, err := api.GetBalance(ctx, test_helpers.AccountAddresss, rpc.BlockNumberOrHashWithNumber(wrongNumber))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -965,9 +1027,10 @@ var _ = Describe("API", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(code).To(Equal((hexutil.Bytes)(test_helpers.ContractCode)))
|
Expect(code).To(Equal((hexutil.Bytes)(test_helpers.ContractCode)))
|
||||||
})
|
})
|
||||||
It("Throws an error for an account it cannot find the code for", func() {
|
It("Returns `nil` for an account it cannot find the code for", func() {
|
||||||
_, err := api.GetCode(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true))
|
code, err := api.GetCode(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(code).To(BeEmpty())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+190
-51
@@ -18,6 +18,7 @@ package eth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
@@ -40,7 +41,8 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
|
||||||
"github.com/vulcanize/ipfs-ethdb"
|
ipfsethdb "github.com/vulcanize/ipfs-ethdb"
|
||||||
|
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||||
shared2 "github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
shared2 "github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||||
|
|
||||||
@@ -50,6 +52,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
errPendingBlockNumber = errors.New("pending block number not supported")
|
errPendingBlockNumber = errors.New("pending block number not supported")
|
||||||
errNegativeBlockNumber = errors.New("negative block number not supported")
|
errNegativeBlockNumber = errors.New("negative block number not supported")
|
||||||
|
errHeaderHashNotFound = errors.New("header for hash not found")
|
||||||
|
errHeaderNotFound = errors.New("header not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -174,7 +178,11 @@ func (b *Backend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.Bl
|
|||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errors.New("header for hash not found")
|
return nil, errors.New("header for hash not found")
|
||||||
}
|
}
|
||||||
if blockNrOrHash.RequireCanonical && b.GetCanonicalHash(header.Number.Uint64()) != hash {
|
canonicalHash, err := b.GetCanonicalHash(header.Number.Uint64())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if blockNrOrHash.RequireCanonical && canonicalHash != hash {
|
||||||
return nil, errors.New("hash is not currently canonical")
|
return nil, errors.New("hash is not currently canonical")
|
||||||
}
|
}
|
||||||
return header, nil
|
return header, nil
|
||||||
@@ -197,9 +205,9 @@ func (b *Backend) GetTd(blockHash common.Hash) (*big.Int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CurrentBlock returns the current block
|
// CurrentBlock returns the current block
|
||||||
func (b *Backend) CurrentBlock() *types.Block {
|
func (b *Backend) CurrentBlock() (*types.Block, error) {
|
||||||
block, _ := b.BlockByNumber(context.Background(), rpc.LatestBlockNumber)
|
block, err := b.BlockByNumber(context.Background(), rpc.LatestBlockNumber)
|
||||||
return block
|
return block, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockByNumberOrHash returns block by number or hash
|
// BlockByNumberOrHash returns block by number or hash
|
||||||
@@ -215,7 +223,11 @@ func (b *Backend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.Blo
|
|||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errors.New("header for hash not found")
|
return nil, errors.New("header for hash not found")
|
||||||
}
|
}
|
||||||
if blockNrOrHash.RequireCanonical && b.GetCanonicalHash(header.Number.Uint64()) != hash {
|
canonicalHash, err := b.GetCanonicalHash(header.Number.Uint64())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if blockNrOrHash.RequireCanonical && canonicalHash != hash {
|
||||||
return nil, errors.New("hash is not currently canonical")
|
return nil, errors.New("hash is not currently canonical")
|
||||||
}
|
}
|
||||||
block, err := b.BlockByHash(ctx, hash)
|
block, err := b.BlockByHash(ctx, hash)
|
||||||
@@ -253,14 +265,20 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
|||||||
return nil, errNegativeBlockNumber
|
return nil, errNegativeBlockNumber
|
||||||
}
|
}
|
||||||
// Get the canonical hash
|
// Get the canonical hash
|
||||||
canonicalHash := b.GetCanonicalHash(uint64(number))
|
canonicalHash, err := b.GetCanonicalHash(uint64(number))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Retrieve all the CIDs for the block
|
// Retrieve all the CIDs for the block
|
||||||
// TODO: optimize this by retrieving iplds directly rather than the cids first (this is remanent from when we fetched iplds through ipfs blockservice interface)
|
// TODO: optimize this by retrieving iplds directly rather than the cids first (this is remanent from when we fetched iplds through ipfs blockservice interface)
|
||||||
headerCID, uncleCIDs, txCIDs, rctCIDs, err := b.Retriever.RetrieveBlockByHash(canonicalHash)
|
headerCID, uncleCIDs, txCIDs, rctCIDs, err := b.Retriever.RetrieveBlockByHash(canonicalHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,49 +299,60 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Fetch and decode the header IPLD
|
// Fetch and decode the header IPLD
|
||||||
headerIPLD, err := b.Fetcher.FetchHeader(tx, headerCID)
|
var headerIPLD ipfs.BlockModel
|
||||||
|
headerIPLD, err = b.Fetcher.FetchHeader(tx, headerCID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var header types.Header
|
var header types.Header
|
||||||
if err := rlp.DecodeBytes(headerIPLD.Data, &header); err != nil {
|
err = rlp.DecodeBytes(headerIPLD.Data, &header)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Fetch and decode the uncle IPLDs
|
// Fetch and decode the uncle IPLDs
|
||||||
uncleIPLDs, err := b.Fetcher.FetchUncles(tx, uncleCIDs)
|
var uncleIPLDs []ipfs.BlockModel
|
||||||
|
uncleIPLDs, err = b.Fetcher.FetchUncles(tx, uncleCIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var uncles []*types.Header
|
var uncles []*types.Header
|
||||||
for _, uncleIPLD := range uncleIPLDs {
|
for _, uncleIPLD := range uncleIPLDs {
|
||||||
var uncle types.Header
|
var uncle types.Header
|
||||||
if err := rlp.DecodeBytes(uncleIPLD.Data, &uncle); err != nil {
|
err = rlp.DecodeBytes(uncleIPLD.Data, &uncle)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
uncles = append(uncles, &uncle)
|
uncles = append(uncles, &uncle)
|
||||||
}
|
}
|
||||||
// Fetch and decode the transaction IPLDs
|
// Fetch and decode the transaction IPLDs
|
||||||
txIPLDs, err := b.Fetcher.FetchTrxs(tx, txCIDs)
|
var txIPLDs []ipfs.BlockModel
|
||||||
|
txIPLDs, err = b.Fetcher.FetchTrxs(tx, txCIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var transactions []*types.Transaction
|
var transactions []*types.Transaction
|
||||||
for _, txIPLD := range txIPLDs {
|
for _, txIPLD := range txIPLDs {
|
||||||
var transaction types.Transaction
|
var transaction types.Transaction
|
||||||
if err := rlp.DecodeBytes(txIPLD.Data, &transaction); err != nil {
|
err = transaction.UnmarshalBinary(txIPLD.Data)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
transactions = append(transactions, &transaction)
|
transactions = append(transactions, &transaction)
|
||||||
}
|
}
|
||||||
// Fetch and decode the receipt IPLDs
|
// Fetch and decode the receipt IPLDs
|
||||||
rctIPLDs, err := b.Fetcher.FetchRcts(tx, rctCIDs)
|
var rctIPLDs []ipfs.BlockModel
|
||||||
|
rctIPLDs, err = b.Fetcher.FetchRcts(tx, rctCIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var receipts []*types.Receipt
|
var receipts []*types.Receipt
|
||||||
for _, rctIPLD := range rctIPLDs {
|
for _, rctIPLD := range rctIPLDs {
|
||||||
var receipt types.Receipt
|
var receipt types.Receipt
|
||||||
if err := rlp.DecodeBytes(rctIPLD.Data, &receipt); err != nil {
|
err = receipt.UnmarshalBinary(rctIPLD.Data)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
receipts = append(receipts, &receipt)
|
receipts = append(receipts, &receipt)
|
||||||
@@ -338,6 +367,9 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
|||||||
// Retrieve all the CIDs for the block
|
// Retrieve all the CIDs for the block
|
||||||
headerCID, uncleCIDs, txCIDs, rctCIDs, err := b.Retriever.RetrieveBlockByHash(hash)
|
headerCID, uncleCIDs, txCIDs, rctCIDs, err := b.Retriever.RetrieveBlockByHash(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,49 +390,69 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Fetch and decode the header IPLD
|
// Fetch and decode the header IPLD
|
||||||
headerIPLD, err := b.Fetcher.FetchHeader(tx, headerCID)
|
var headerIPLD ipfs.BlockModel
|
||||||
|
headerIPLD, err = b.Fetcher.FetchHeader(tx, headerCID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var header types.Header
|
var header types.Header
|
||||||
if err := rlp.DecodeBytes(headerIPLD.Data, &header); err != nil {
|
err = rlp.DecodeBytes(headerIPLD.Data, &header)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Fetch and decode the uncle IPLDs
|
// Fetch and decode the uncle IPLDs
|
||||||
uncleIPLDs, err := b.Fetcher.FetchUncles(tx, uncleCIDs)
|
var uncleIPLDs []ipfs.BlockModel
|
||||||
|
uncleIPLDs, err = b.Fetcher.FetchUncles(tx, uncleCIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var uncles []*types.Header
|
var uncles []*types.Header
|
||||||
for _, uncleIPLD := range uncleIPLDs {
|
for _, uncleIPLD := range uncleIPLDs {
|
||||||
var uncle types.Header
|
var uncle types.Header
|
||||||
if err := rlp.DecodeBytes(uncleIPLD.Data, &uncle); err != nil {
|
err = rlp.DecodeBytes(uncleIPLD.Data, &uncle)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
uncles = append(uncles, &uncle)
|
uncles = append(uncles, &uncle)
|
||||||
}
|
}
|
||||||
// Fetch and decode the transaction IPLDs
|
// Fetch and decode the transaction IPLDs
|
||||||
txIPLDs, err := b.Fetcher.FetchTrxs(tx, txCIDs)
|
var txIPLDs []ipfs.BlockModel
|
||||||
|
txIPLDs, err = b.Fetcher.FetchTrxs(tx, txCIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var transactions []*types.Transaction
|
var transactions []*types.Transaction
|
||||||
for _, txIPLD := range txIPLDs {
|
for _, txIPLD := range txIPLDs {
|
||||||
var transaction types.Transaction
|
var transaction types.Transaction
|
||||||
if err := rlp.DecodeBytes(txIPLD.Data, &transaction); err != nil {
|
err = transaction.UnmarshalBinary(txIPLD.Data)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
transactions = append(transactions, &transaction)
|
transactions = append(transactions, &transaction)
|
||||||
}
|
}
|
||||||
// Fetch and decode the receipt IPLDs
|
// Fetch and decode the receipt IPLDs
|
||||||
rctIPLDs, err := b.Fetcher.FetchRcts(tx, rctCIDs)
|
var rctIPLDs []ipfs.BlockModel
|
||||||
|
rctIPLDs, err = b.Fetcher.FetchRcts(tx, rctCIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var receipts []*types.Receipt
|
var receipts []*types.Receipt
|
||||||
for _, rctIPLD := range rctIPLDs {
|
for _, rctIPLD := range rctIPLDs {
|
||||||
var receipt types.Receipt
|
var receipt types.Receipt
|
||||||
if err := rlp.DecodeBytes(rctIPLD.Data, &receipt); err != nil {
|
err = receipt.UnmarshalBinary(rctIPLD.Data)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
receipts = append(receipts, &receipt)
|
receipts = append(receipts, &receipt)
|
||||||
@@ -422,7 +474,7 @@ func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (*type
|
|||||||
return nil, common.Hash{}, 0, 0, err
|
return nil, common.Hash{}, 0, 0, err
|
||||||
}
|
}
|
||||||
var transaction types.Transaction
|
var transaction types.Transaction
|
||||||
if err := rlp.DecodeBytes(tempTxStruct.Data, &transaction); err != nil {
|
if err := transaction.UnmarshalBinary(tempTxStruct.Data); err != nil {
|
||||||
return nil, common.Hash{}, 0, 0, err
|
return nil, common.Hash{}, 0, 0, err
|
||||||
}
|
}
|
||||||
return &transaction, common.HexToHash(tempTxStruct.BlockHash), tempTxStruct.BlockNumber, tempTxStruct.Index, nil
|
return &transaction, common.HexToHash(tempTxStruct.BlockHash), tempTxStruct.BlockNumber, tempTxStruct.Index, nil
|
||||||
@@ -430,16 +482,17 @@ func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (*type
|
|||||||
|
|
||||||
// GetReceipts retrieves receipts for provided block hash
|
// GetReceipts retrieves receipts for provided block hash
|
||||||
func (b *Backend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
func (b *Backend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
||||||
_, receiptBytes, err := b.IPLDRetriever.RetrieveReceiptsByBlockHash(hash)
|
_, receiptBytes, txs, err := b.IPLDRetriever.RetrieveReceiptsByBlockHash(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rcts := make(types.Receipts, len(receiptBytes))
|
rcts := make(types.Receipts, len(receiptBytes))
|
||||||
for i, rctBytes := range receiptBytes {
|
for i, rctBytes := range receiptBytes {
|
||||||
rct := new(types.Receipt)
|
rct := new(types.Receipt)
|
||||||
if err := rlp.DecodeBytes(rctBytes, rct); err != nil {
|
if err := rct.UnmarshalBinary(rctBytes); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
rct.TxHash = txs[i]
|
||||||
rcts[i] = rct
|
rcts[i] = rct
|
||||||
}
|
}
|
||||||
return rcts, nil
|
return rcts, nil
|
||||||
@@ -447,7 +500,7 @@ func (b *Backend) GetReceipts(ctx context.Context, hash common.Hash) (types.Rece
|
|||||||
|
|
||||||
// GetLogs returns all the logs for the given block hash
|
// GetLogs returns all the logs for the given block hash
|
||||||
func (b *Backend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
|
func (b *Backend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
|
||||||
_, receiptBytes, err := b.IPLDRetriever.RetrieveReceiptsByBlockHash(hash)
|
_, receiptBytes, txs, err := b.IPLDRetriever.RetrieveReceiptsByBlockHash(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -457,6 +510,11 @@ func (b *Backend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log
|
|||||||
if err := rlp.DecodeBytes(rctBytes, &rct); err != nil {
|
if err := rlp.DecodeBytes(rctBytes, &rct); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, log := range rct.Logs {
|
||||||
|
log.TxHash = txs[i]
|
||||||
|
}
|
||||||
|
|
||||||
logs[i] = rct.Logs
|
logs[i] = rct.Logs
|
||||||
}
|
}
|
||||||
return logs, nil
|
return logs, nil
|
||||||
@@ -475,7 +533,11 @@ func (b *Backend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHas
|
|||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, nil, errors.New("header for hash not found")
|
return nil, nil, errors.New("header for hash not found")
|
||||||
}
|
}
|
||||||
if blockNrOrHash.RequireCanonical && b.GetCanonicalHash(header.Number.Uint64()) != hash {
|
canonicalHash, err := b.GetCanonicalHash(header.Number.Uint64())
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if blockNrOrHash.RequireCanonical && canonicalHash != hash {
|
||||||
return nil, nil, errors.New("hash is not currently canonical")
|
return nil, nil, errors.New("hash is not currently canonical")
|
||||||
}
|
}
|
||||||
stateDb, err := state.New(header.Root, b.StateDatabase, nil)
|
stateDb, err := state.New(header.Root, b.StateDatabase, nil)
|
||||||
@@ -503,12 +565,12 @@ func (b *Backend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCanonicalHash gets the canonical hash for the provided number, if there is one
|
// GetCanonicalHash gets the canonical hash for the provided number, if there is one
|
||||||
func (b *Backend) GetCanonicalHash(number uint64) common.Hash {
|
func (b *Backend) GetCanonicalHash(number uint64) (common.Hash, error) {
|
||||||
var hashResult string
|
var hashResult string
|
||||||
if err := b.DB.Get(&hashResult, RetrieveCanonicalBlockHashByNumber, number); err != nil {
|
if err := b.DB.Get(&hashResult, RetrieveCanonicalBlockHashByNumber, number); err != nil {
|
||||||
return common.Hash{}
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
return common.HexToHash(hashResult)
|
return common.HexToHash(hashResult), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type rowResult struct {
|
type rowResult struct {
|
||||||
@@ -533,7 +595,7 @@ func (b *Backend) GetEVM(ctx context.Context, msg core.Message, state *state.Sta
|
|||||||
// GetAccountByNumberOrHash returns the account object for the provided address at the block corresponding to the provided number or hash
|
// GetAccountByNumberOrHash returns the account object for the provided address at the block corresponding to the provided number or hash
|
||||||
func (b *Backend) GetAccountByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*state.Account, error) {
|
func (b *Backend) GetAccountByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*state.Account, error) {
|
||||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||||
return b.GetAccountByNumber(ctx, address, uint64(blockNr.Int64()))
|
return b.GetAccountByNumber(ctx, address, blockNr)
|
||||||
}
|
}
|
||||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||||
return b.GetAccountByHash(ctx, address, hash)
|
return b.GetAccountByHash(ctx, address, hash)
|
||||||
@@ -542,20 +604,48 @@ func (b *Backend) GetAccountByNumberOrHash(ctx context.Context, address common.A
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetAccountByNumber returns the account object for the provided address at the canonical block at the provided height
|
// GetAccountByNumber returns the account object for the provided address at the canonical block at the provided height
|
||||||
func (b *Backend) GetAccountByNumber(ctx context.Context, address common.Address, number uint64) (*state.Account, error) {
|
func (b *Backend) GetAccountByNumber(ctx context.Context, address common.Address, blockNumber rpc.BlockNumber) (*state.Account, error) {
|
||||||
hash := b.GetCanonicalHash(number)
|
var err error
|
||||||
if hash == (common.Hash{}) {
|
number := blockNumber.Int64()
|
||||||
return nil, fmt.Errorf("no canoncial block hash found for provided height (%d)", number)
|
if blockNumber == rpc.LatestBlockNumber {
|
||||||
|
number, err = b.Retriever.RetrieveLastBlockNumber()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if blockNumber == rpc.EarliestBlockNumber {
|
||||||
|
number, err = b.Retriever.RetrieveFirstBlockNumber()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if blockNumber == rpc.PendingBlockNumber {
|
||||||
|
return nil, errPendingBlockNumber
|
||||||
|
}
|
||||||
|
hash, err := b.GetCanonicalHash(uint64(number))
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, errHeaderNotFound
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return b.GetAccountByHash(ctx, address, hash)
|
return b.GetAccountByHash(ctx, address, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAccountByHash returns the account object for the provided address at the block with the provided hash
|
// GetAccountByHash returns the account object for the provided address at the block with the provided hash
|
||||||
func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address, hash common.Hash) (*state.Account, error) {
|
func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address, hash common.Hash) (*state.Account, error) {
|
||||||
|
_, err := b.HeaderByHash(context.Background(), hash)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, errHeaderHashNotFound
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
_, accountRlp, err := b.IPLDRetriever.RetrieveAccountByAddressAndBlockHash(address, hash)
|
_, accountRlp, err := b.IPLDRetriever.RetrieveAccountByAddressAndBlockHash(address, hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
acct := new(state.Account)
|
acct := new(state.Account)
|
||||||
return acct, rlp.DecodeBytes(accountRlp, acct)
|
return acct, rlp.DecodeBytes(accountRlp, acct)
|
||||||
}
|
}
|
||||||
@@ -563,7 +653,7 @@ func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address,
|
|||||||
// GetCodeByNumberOrHash returns the byte code for the contract deployed at the provided address at the block with the provided hash or block number
|
// GetCodeByNumberOrHash returns the byte code for the contract deployed at the provided address at the block with the provided hash or block number
|
||||||
func (b *Backend) GetCodeByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) ([]byte, error) {
|
func (b *Backend) GetCodeByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) ([]byte, error) {
|
||||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||||
return b.GetCodeByNumber(ctx, address, uint64(blockNr.Int64()))
|
return b.GetCodeByNumber(ctx, address, blockNr)
|
||||||
}
|
}
|
||||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||||
return b.GetCodeByHash(ctx, address, hash)
|
return b.GetCodeByHash(ctx, address, hash)
|
||||||
@@ -572,8 +662,28 @@ func (b *Backend) GetCodeByNumberOrHash(ctx context.Context, address common.Addr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCodeByNumber returns the byte code for the contract deployed at the provided address at the canonical block with the provided block number
|
// GetCodeByNumber returns the byte code for the contract deployed at the provided address at the canonical block with the provided block number
|
||||||
func (b *Backend) GetCodeByNumber(ctx context.Context, address common.Address, number uint64) ([]byte, error) {
|
func (b *Backend) GetCodeByNumber(ctx context.Context, address common.Address, blockNumber rpc.BlockNumber) ([]byte, error) {
|
||||||
hash := b.GetCanonicalHash(number)
|
var err error
|
||||||
|
number := blockNumber.Int64()
|
||||||
|
if blockNumber == rpc.LatestBlockNumber {
|
||||||
|
number, err = b.Retriever.RetrieveLastBlockNumber()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if blockNumber == rpc.EarliestBlockNumber {
|
||||||
|
number, err = b.Retriever.RetrieveFirstBlockNumber()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if blockNumber == rpc.PendingBlockNumber {
|
||||||
|
return nil, errPendingBlockNumber
|
||||||
|
}
|
||||||
|
hash, err := b.GetCanonicalHash(uint64(number))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if hash == (common.Hash{}) {
|
if hash == (common.Hash{}) {
|
||||||
return nil, fmt.Errorf("no canoncial block hash found for provided height (%d)", number)
|
return nil, fmt.Errorf("no canoncial block hash found for provided height (%d)", number)
|
||||||
}
|
}
|
||||||
@@ -599,10 +709,12 @@ func (b *Backend) GetCodeByHash(ctx context.Context, address common.Address, has
|
|||||||
err = tx.Commit()
|
err = tx.Commit()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err := tx.Get(&codeHash, RetrieveCodeHashByLeafKeyAndBlockHash, leafKey.Hex(), hash.Hex()); err != nil {
|
err = tx.Get(&codeHash, RetrieveCodeHashByLeafKeyAndBlockHash, leafKey.Hex(), hash.Hex())
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mhKey, err := shared2.MultihashKeyFromKeccak256(common.BytesToHash(codeHash))
|
var mhKey string
|
||||||
|
mhKey, err = shared2.MultihashKeyFromKeccak256(common.BytesToHash(codeHash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -612,28 +724,55 @@ func (b *Backend) GetCodeByHash(ctx context.Context, address common.Address, has
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetStorageByNumberOrHash returns the storage value for the provided contract address an storage key at the block corresponding to the provided number or hash
|
// GetStorageByNumberOrHash returns the storage value for the provided contract address an storage key at the block corresponding to the provided number or hash
|
||||||
func (b *Backend) GetStorageByNumberOrHash(ctx context.Context, address common.Address, storageLeafKey common.Hash, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
func (b *Backend) GetStorageByNumberOrHash(ctx context.Context, address common.Address, key common.Hash, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
||||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||||
return b.GetStorageByNumber(ctx, address, storageLeafKey, uint64(blockNr.Int64()))
|
return b.GetStorageByNumber(ctx, address, key, blockNr)
|
||||||
}
|
}
|
||||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||||
return b.GetStorageByHash(ctx, address, storageLeafKey, hash)
|
return b.GetStorageByHash(ctx, address, key, hash)
|
||||||
}
|
}
|
||||||
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStorageByNumber returns the storage value for the provided contract address an storage key at the block corresponding to the provided number
|
// GetStorageByNumber returns the storage value for the provided contract address an storage key at the block corresponding to the provided number
|
||||||
func (b *Backend) GetStorageByNumber(ctx context.Context, address common.Address, storageLeafKey common.Hash, number uint64) (hexutil.Bytes, error) {
|
func (b *Backend) GetStorageByNumber(ctx context.Context, address common.Address, key common.Hash, blockNumber rpc.BlockNumber) (hexutil.Bytes, error) {
|
||||||
hash := b.GetCanonicalHash(number)
|
var err error
|
||||||
if hash == (common.Hash{}) {
|
number := blockNumber.Int64()
|
||||||
return nil, fmt.Errorf("no canoncial block hash found for provided height (%d)", number)
|
if blockNumber == rpc.LatestBlockNumber {
|
||||||
|
number, err = b.Retriever.RetrieveLastBlockNumber()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return b.GetStorageByHash(ctx, address, storageLeafKey, hash)
|
if blockNumber == rpc.EarliestBlockNumber {
|
||||||
|
number, err = b.Retriever.RetrieveFirstBlockNumber()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if blockNumber == rpc.PendingBlockNumber {
|
||||||
|
return nil, errPendingBlockNumber
|
||||||
|
}
|
||||||
|
hash, err := b.GetCanonicalHash(uint64(number))
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, errHeaderNotFound
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.GetStorageByHash(ctx, address, key, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStorageByHash returns the storage value for the provided contract address an storage key at the block corresponding to the provided hash
|
// GetStorageByHash returns the storage value for the provided contract address an storage key at the block corresponding to the provided hash
|
||||||
func (b *Backend) GetStorageByHash(ctx context.Context, address common.Address, storageLeafKey, hash common.Hash) (hexutil.Bytes, error) {
|
func (b *Backend) GetStorageByHash(ctx context.Context, address common.Address, key, hash common.Hash) (hexutil.Bytes, error) {
|
||||||
_, storageRlp, err := b.IPLDRetriever.RetrieveStorageAtByAddressAndStorageKeyAndBlockHash(address, storageLeafKey, hash)
|
_, err := b.HeaderByHash(context.Background(), hash)
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, errHeaderHashNotFound
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, storageRlp, err := b.IPLDRetriever.RetrieveStorageAtByAddressAndStorageSlotAndBlockHash(address, key, hash)
|
||||||
return storageRlp, err
|
return storageRlp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+114
-18
@@ -23,12 +23,13 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||||
)
|
)
|
||||||
@@ -36,7 +37,7 @@ import (
|
|||||||
// RPCMarshalHeader converts the given header to the RPC output.
|
// RPCMarshalHeader converts the given header to the RPC output.
|
||||||
// This function is eth/internal so we have to make our own version here...
|
// This function is eth/internal so we have to make our own version here...
|
||||||
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
||||||
return map[string]interface{}{
|
headerMap := map[string]interface{}{
|
||||||
"number": (*hexutil.Big)(head.Number),
|
"number": (*hexutil.Big)(head.Number),
|
||||||
"hash": head.Hash(),
|
"hash": head.Hash(),
|
||||||
"parentHash": head.ParentHash,
|
"parentHash": head.ParentHash,
|
||||||
@@ -55,6 +56,11 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
|||||||
"transactionsRoot": head.TxHash,
|
"transactionsRoot": head.TxHash,
|
||||||
"receiptsRoot": head.ReceiptHash,
|
"receiptsRoot": head.ReceiptHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if head.BaseFee != nil {
|
||||||
|
headerMap["baseFee"] = head.BaseFee
|
||||||
|
}
|
||||||
|
return headerMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
|
// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
|
||||||
@@ -134,14 +140,15 @@ func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransa
|
|||||||
|
|
||||||
// NewRPCTransaction returns a transaction that will serialize to the RPC
|
// NewRPCTransaction returns a transaction that will serialize to the RPC
|
||||||
// representation, with the given location metadata set (if available).
|
// representation, with the given location metadata set (if available).
|
||||||
func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction {
|
func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *RPCTransaction {
|
||||||
var signer types.Signer = types.FrontierSigner{}
|
var signer types.Signer
|
||||||
if tx.Protected() {
|
if tx.Protected() {
|
||||||
signer = types.NewEIP155Signer(tx.ChainId())
|
signer = types.LatestSignerForChainID(tx.ChainId())
|
||||||
|
} else {
|
||||||
|
signer = types.HomesteadSigner{}
|
||||||
}
|
}
|
||||||
from, _ := types.Sender(signer, tx)
|
from, _ := types.Sender(signer, tx)
|
||||||
v, r, s := tx.RawSignatureValues()
|
v, r, s := tx.RawSignatureValues()
|
||||||
|
|
||||||
result := &RPCTransaction{
|
result := &RPCTransaction{
|
||||||
From: from,
|
From: from,
|
||||||
Gas: hexutil.Uint64(tx.Gas()),
|
Gas: hexutil.Uint64(tx.Gas()),
|
||||||
@@ -151,6 +158,7 @@ func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
|||||||
Nonce: hexutil.Uint64(tx.Nonce()),
|
Nonce: hexutil.Uint64(tx.Nonce()),
|
||||||
To: tx.To(),
|
To: tx.To(),
|
||||||
Value: (*hexutil.Big)(tx.Value()),
|
Value: (*hexutil.Big)(tx.Value()),
|
||||||
|
Type: hexutil.Uint64(tx.Type()),
|
||||||
V: (*hexutil.Big)(v),
|
V: (*hexutil.Big)(v),
|
||||||
R: (*hexutil.Big)(r),
|
R: (*hexutil.Big)(r),
|
||||||
S: (*hexutil.Big)(s),
|
S: (*hexutil.Big)(s),
|
||||||
@@ -160,6 +168,26 @@ func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
|||||||
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
|
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
|
||||||
result.TransactionIndex = (*hexutil.Uint64)(&index)
|
result.TransactionIndex = (*hexutil.Uint64)(&index)
|
||||||
}
|
}
|
||||||
|
switch tx.Type() {
|
||||||
|
case types.AccessListTxType:
|
||||||
|
al := tx.AccessList()
|
||||||
|
result.Accesses = &al
|
||||||
|
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||||
|
case types.DynamicFeeTxType:
|
||||||
|
al := tx.AccessList()
|
||||||
|
result.Accesses = &al
|
||||||
|
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||||
|
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
|
||||||
|
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
|
||||||
|
// if the transaction has been mined, compute the effective gas price
|
||||||
|
if baseFee != nil && blockHash != (common.Hash{}) {
|
||||||
|
// price = min(tip, gasFeeCap - baseFee) + baseFee
|
||||||
|
price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap())
|
||||||
|
result.GasPrice = (*hexutil.Big)(price)
|
||||||
|
} else {
|
||||||
|
result.GasPrice = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,27 +268,95 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransacti
|
|||||||
if index >= uint64(len(txs)) {
|
if index >= uint64(len(txs)) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index)
|
return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee())
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractLogsOfInterest returns logs from the receipt IPLD
|
// extractLogsOfInterest returns logs from the receipt IPLD
|
||||||
func extractLogsOfInterest(rctIPLDs []ipfs.BlockModel, wantedTopics [][]string) ([]*types.Log, error) {
|
func extractLogsOfInterest(config *params.ChainConfig, blockHash common.Hash, blockNumber uint64,
|
||||||
var logs []*types.Log
|
txs types.Transactions, rctIPLDs []ipfs.BlockModel, filter ReceiptFilter) ([]*types.Log, error) {
|
||||||
for _, rctIPLD := range rctIPLDs {
|
receipts := make(types.Receipts, len(rctIPLDs))
|
||||||
rctRLP := rctIPLD
|
|
||||||
var rct types.Receipt
|
for i, rctBytes := range rctIPLDs {
|
||||||
if err := rlp.DecodeBytes(rctRLP.Data, &rct); err != nil {
|
rct := new(types.Receipt)
|
||||||
|
if err := rct.UnmarshalBinary(rctBytes.Data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, log := range rct.Logs {
|
receipts[i] = rct
|
||||||
if wanted := wantedLog(wantedTopics, log.Topics); wanted == true {
|
}
|
||||||
logs = append(logs, log)
|
|
||||||
}
|
err := receipts.DeriveFields(config, blockHash, blockNumber, txs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var unfilteredLogs []*types.Log
|
||||||
|
for _, receipt := range receipts {
|
||||||
|
unfilteredLogs = append(unfilteredLogs, receipt.Logs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
adders := make([]common.Address, len(filter.LogAddresses))
|
||||||
|
for i, addr := range filter.LogAddresses {
|
||||||
|
adders[i] = common.HexToAddress(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
topics := make([][]common.Hash, len(filter.Topics))
|
||||||
|
for i, v := range filter.Topics {
|
||||||
|
topics[i] = make([]common.Hash, len(v))
|
||||||
|
for j, topic := range v {
|
||||||
|
topics[i][j] = common.HexToHash(topic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logs := filterLogs(unfilteredLogs, nil, nil, adders, topics)
|
||||||
return logs, nil
|
return logs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func includes(addresses []common.Address, a common.Address) bool {
|
||||||
|
for _, addr := range addresses {
|
||||||
|
if addr == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// filterLogs creates a slice of logs matching the given criteria.
|
||||||
|
func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*types.Log {
|
||||||
|
var ret []*types.Log
|
||||||
|
Logs:
|
||||||
|
for _, log := range logs {
|
||||||
|
if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addresses) > 0 && !includes(addresses, log.Address) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// If the to filtered topics is greater than the amount of topics in logs, skip.
|
||||||
|
if len(topics) > len(log.Topics) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i, sub := range topics {
|
||||||
|
match := len(sub) == 0 // empty rule set == wildcard
|
||||||
|
for _, topic := range sub {
|
||||||
|
if log.Topics[i] == topic {
|
||||||
|
match = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
continue Logs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = append(ret, log)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// returns true if the log matches on the filter
|
// returns true if the log matches on the filter
|
||||||
func wantedLog(wantedTopics [][]string, actualTopics []common.Hash) bool {
|
func wantedLog(wantedTopics [][]string, actualTopics []common.Hash) bool {
|
||||||
// actualTopics will always have length <= 4
|
// actualTopics will always have length <= 4
|
||||||
|
|||||||
+29
-10
@@ -86,7 +86,8 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Retrieve cached header CIDs at this block height
|
// Retrieve cached header CIDs at this block height
|
||||||
headers, err := ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
var headers []eth.HeaderModel
|
||||||
|
headers, err = ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("header cid retrieval error")
|
log.Error("header cid retrieval error")
|
||||||
return nil, true, err
|
return nil, true, err
|
||||||
@@ -101,7 +102,8 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
|||||||
empty = false
|
empty = false
|
||||||
if filter.HeaderFilter.Uncles {
|
if filter.HeaderFilter.Uncles {
|
||||||
// Retrieve uncle cids for this header id
|
// Retrieve uncle cids for this header id
|
||||||
uncleCIDs, err := ecr.RetrieveUncleCIDsByHeaderID(tx, header.ID)
|
var uncleCIDs []eth.UncleModel
|
||||||
|
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, header.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("uncle cid retrieval error")
|
log.Error("uncle cid retrieval error")
|
||||||
return nil, true, err
|
return nil, true, err
|
||||||
@@ -310,6 +312,14 @@ func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, b
|
|||||||
args = append(args, blockHash.String())
|
args = append(args, blockHash.String())
|
||||||
id++
|
id++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add the below filters when we have log index in DB.
|
||||||
|
if true {
|
||||||
|
pgStr += ` ORDER BY transaction_cids.index`
|
||||||
|
receiptCids := make([]eth.ReceiptModel, 0)
|
||||||
|
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
||||||
|
}
|
||||||
|
|
||||||
if len(rctFilter.LogAddresses) > 0 {
|
if len(rctFilter.LogAddresses) > 0 {
|
||||||
// Filter on log contract addresses if there are any
|
// Filter on log contract addresses if there are any
|
||||||
pgStr += fmt.Sprintf(` AND ((receipt_cids.log_contracts && $%d::VARCHAR(66)[]`, id)
|
pgStr += fmt.Sprintf(` AND ((receipt_cids.log_contracts && $%d::VARCHAR(66)[]`, id)
|
||||||
@@ -371,6 +381,7 @@ func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, b
|
|||||||
args = append(args, pq.Array(trxIds))
|
args = append(args, pq.Array(trxIds))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pgStr += ` ORDER BY transaction_cids.index`
|
pgStr += ` ORDER BY transaction_cids.index`
|
||||||
receiptCids := make([]eth.ReceiptModel, 0)
|
receiptCids := make([]eth.ReceiptModel, 0)
|
||||||
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
||||||
@@ -463,17 +474,20 @@ func (ecr *CIDRetriever) RetrieveBlockByHash(blockHash common.Hash) (eth.HeaderM
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
headerCID, err := ecr.RetrieveHeaderCIDByHash(tx, blockHash)
|
var headerCID eth.HeaderModel
|
||||||
|
headerCID, err = ecr.RetrieveHeaderCIDByHash(tx, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("header cid retrieval error")
|
log.Error("header cid retrieval error")
|
||||||
return eth.HeaderModel{}, nil, nil, nil, err
|
return eth.HeaderModel{}, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
uncleCIDs, err := ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID.ID)
|
var uncleCIDs []eth.UncleModel
|
||||||
|
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("uncle cid retrieval error")
|
log.Error("uncle cid retrieval error")
|
||||||
return eth.HeaderModel{}, nil, nil, nil, err
|
return eth.HeaderModel{}, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
txCIDs, err := ecr.RetrieveTxCIDsByHeaderID(tx, headerCID.ID)
|
var txCIDs []eth.TxModel
|
||||||
|
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("tx cid retrieval error")
|
log.Error("tx cid retrieval error")
|
||||||
return eth.HeaderModel{}, nil, nil, nil, err
|
return eth.HeaderModel{}, nil, nil, nil, err
|
||||||
@@ -482,7 +496,8 @@ func (ecr *CIDRetriever) RetrieveBlockByHash(blockHash common.Hash) (eth.HeaderM
|
|||||||
for i, txCID := range txCIDs {
|
for i, txCID := range txCIDs {
|
||||||
txIDs[i] = txCID.ID
|
txIDs[i] = txCID.ID
|
||||||
}
|
}
|
||||||
rctCIDs, err := ecr.RetrieveReceiptCIDsByTxIDs(tx, txIDs)
|
var rctCIDs []eth.ReceiptModel
|
||||||
|
rctCIDs, err = ecr.RetrieveReceiptCIDsByTxIDs(tx, txIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("rct cid retrieval error")
|
log.Error("rct cid retrieval error")
|
||||||
}
|
}
|
||||||
@@ -509,7 +524,8 @@ func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (eth.HeaderMod
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
headerCID, err := ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
var headerCID []eth.HeaderModel
|
||||||
|
headerCID, err = ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("header cid retrieval error")
|
log.Error("header cid retrieval error")
|
||||||
return eth.HeaderModel{}, nil, nil, nil, err
|
return eth.HeaderModel{}, nil, nil, nil, err
|
||||||
@@ -517,12 +533,14 @@ func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (eth.HeaderMod
|
|||||||
if len(headerCID) < 1 {
|
if len(headerCID) < 1 {
|
||||||
return eth.HeaderModel{}, nil, nil, nil, fmt.Errorf("header cid retrieval error, no header CIDs found at block %d", blockNumber)
|
return eth.HeaderModel{}, nil, nil, nil, fmt.Errorf("header cid retrieval error, no header CIDs found at block %d", blockNumber)
|
||||||
}
|
}
|
||||||
uncleCIDs, err := ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID[0].ID)
|
var uncleCIDs []eth.UncleModel
|
||||||
|
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID[0].ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("uncle cid retrieval error")
|
log.Error("uncle cid retrieval error")
|
||||||
return eth.HeaderModel{}, nil, nil, nil, err
|
return eth.HeaderModel{}, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
txCIDs, err := ecr.RetrieveTxCIDsByHeaderID(tx, headerCID[0].ID)
|
var txCIDs []eth.TxModel
|
||||||
|
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID[0].ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("tx cid retrieval error")
|
log.Error("tx cid retrieval error")
|
||||||
return eth.HeaderModel{}, nil, nil, nil, err
|
return eth.HeaderModel{}, nil, nil, nil, err
|
||||||
@@ -531,7 +549,8 @@ func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (eth.HeaderMod
|
|||||||
for i, txCID := range txCIDs {
|
for i, txCID := range txCIDs {
|
||||||
txIDs[i] = txCID.ID
|
txIDs[i] = txCID.ID
|
||||||
}
|
}
|
||||||
rctCIDs, err := ecr.RetrieveReceiptCIDsByTxIDs(tx, txIDs)
|
var rctCIDs []eth.ReceiptModel
|
||||||
|
rctCIDs, err = ecr.RetrieveReceiptCIDsByTxIDs(tx, txIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("rct cid retrieval error")
|
log.Error("rct cid retrieval error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,6 +237,7 @@ var _ = Describe("Retriever", func() {
|
|||||||
Expect(empty).ToNot(BeTrue())
|
Expect(empty).ToNot(BeTrue())
|
||||||
Expect(len(cids)).To(Equal(1))
|
Expect(len(cids)).To(Equal(1))
|
||||||
Expect(cids[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
Expect(cids[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||||
|
|
||||||
expectedHeaderCID := test_helpers.MockCIDWrapper.Header
|
expectedHeaderCID := test_helpers.MockCIDWrapper.Header
|
||||||
expectedHeaderCID.ID = cids[0].Header.ID
|
expectedHeaderCID.ID = cids[0].Header.ID
|
||||||
expectedHeaderCID.NodeID = cids[0].Header.NodeID
|
expectedHeaderCID.NodeID = cids[0].Header.NodeID
|
||||||
@@ -250,6 +251,7 @@ var _ = Describe("Retriever", func() {
|
|||||||
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, test_helpers.MockCIDWrapper.Receipts[1].CID)).To(BeTrue())
|
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, test_helpers.MockCIDWrapper.Receipts[1].CID)).To(BeTrue())
|
||||||
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, test_helpers.MockCIDWrapper.Receipts[2].CID)).To(BeTrue())
|
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, test_helpers.MockCIDWrapper.Receipts[2].CID)).To(BeTrue())
|
||||||
Expect(len(cids[0].StateNodes)).To(Equal(2))
|
Expect(len(cids[0].StateNodes)).To(Equal(2))
|
||||||
|
|
||||||
for _, stateNode := range cids[0].StateNodes {
|
for _, stateNode := range cids[0].StateNodes {
|
||||||
if stateNode.CID == test_helpers.State1CID.String() {
|
if stateNode.CID == test_helpers.State1CID.String() {
|
||||||
Expect(stateNode.StateKey).To(Equal(common.BytesToHash(test_helpers.ContractLeafKey).Hex()))
|
Expect(stateNode.StateKey).To(Equal(common.BytesToHash(test_helpers.ContractLeafKey).Hex()))
|
||||||
|
|||||||
+105
-58
@@ -38,7 +38,6 @@ import (
|
|||||||
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||||
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
||||||
)
|
)
|
||||||
@@ -60,6 +59,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _ = Describe("eth state reading tests", func() {
|
var _ = Describe("eth state reading tests", func() {
|
||||||
|
const chainLength = 5
|
||||||
var (
|
var (
|
||||||
blocks []*types.Block
|
blocks []*types.Block
|
||||||
receipts []types.Receipts
|
receipts []types.Receipts
|
||||||
@@ -80,13 +80,13 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
backend, err = eth.NewEthBackend(db, ð.Config{
|
backend, err = eth.NewEthBackend(db, ð.Config{
|
||||||
ChainConfig: chainConfig,
|
ChainConfig: chainConfig,
|
||||||
VmConfig: vm.Config{},
|
VmConfig: vm.Config{},
|
||||||
RPCGasCap: big.NewInt(10000000000),
|
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
|
||||||
})
|
})
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
api = eth.NewPublicEthAPI(backend, nil, false)
|
api = eth.NewPublicEthAPI(backend, nil, false)
|
||||||
|
|
||||||
// make the test blockchain (and state)
|
// make the test blockchain (and state)
|
||||||
blocks, receipts, chain = test_helpers.MakeChain(5, test_helpers.Genesis, test_helpers.TestChainGen)
|
blocks, receipts, chain = test_helpers.MakeChain(chainLength, test_helpers.Genesis, test_helpers.TestChainGen)
|
||||||
params := statediff.Params{
|
params := statediff.Params{
|
||||||
IntermediateStateNodes: true,
|
IntermediateStateNodes: true,
|
||||||
IntermediateStorageNodes: true,
|
IntermediateStorageNodes: true,
|
||||||
@@ -234,12 +234,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(1))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(1))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||||
_, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(1))
|
|
||||||
Expect(err).To(HaveOccurred())
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(1))
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(1))
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(1))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(1))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(1))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock1))
|
Expect(bal).To(Equal(expectedBankBalanceBlock1))
|
||||||
@@ -247,12 +250,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(2))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(2))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(2))
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(2))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock2))
|
Expect(bal).To(Equal(expectedAcct2BalanceBlock2))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(2))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(2))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedContractBalance))
|
Expect(bal).To(Equal(expectedContractBalance))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(2))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(2))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
||||||
@@ -260,12 +266,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(3))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(3))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(3))
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(3))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock3))
|
Expect(bal).To(Equal(expectedAcct2BalanceBlock3))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(3))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(3))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedContractBalance))
|
Expect(bal).To(Equal(expectedContractBalance))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(3))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(3))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
||||||
@@ -273,12 +282,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(4))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(4))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(4))
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(4))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(4))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(4))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedContractBalance))
|
Expect(bal).To(Equal(expectedContractBalance))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(4))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(4))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
||||||
@@ -286,12 +298,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(5))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(5))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock5))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock5))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(5))
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(5))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(5))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(5))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedContractBalance))
|
Expect(bal).To(Equal(expectedContractBalance))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(5))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(5))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
||||||
@@ -304,12 +319,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||||
_, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
|
||||||
Expect(err).To(HaveOccurred())
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
|
|
||||||
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock1))
|
Expect(bal).To(Equal(expectedBankBalanceBlock1))
|
||||||
@@ -317,12 +335,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock2))
|
Expect(bal).To(Equal(expectedAcct2BalanceBlock2))
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedContractBalance))
|
Expect(bal).To(Equal(expectedContractBalance))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
||||||
@@ -330,12 +351,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock3))
|
Expect(bal).To(Equal(expectedAcct2BalanceBlock3))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedContractBalance))
|
Expect(bal).To(Equal(expectedContractBalance))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
||||||
@@ -343,12 +367,15 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedContractBalance))
|
Expect(bal).To(Equal(expectedContractBalance))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
||||||
@@ -356,37 +383,45 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock5))
|
Expect(bal).To(Equal(expectedAcct1BalanceBlock5))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedContractBalance))
|
Expect(bal).To(Equal(expectedContractBalance))
|
||||||
|
|
||||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
Expect(bal).To(Equal(expectedBankBalanceBlock2))
|
||||||
})
|
})
|
||||||
It("Throws an error for an account it cannot find the balance for an account at the provided block number", func() {
|
It("Returns `0` for an account it cannot find the balance for an account at the provided block number", func() {
|
||||||
_, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(0))
|
bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(0))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
_, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(0))
|
|
||||||
Expect(err).To(HaveOccurred())
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(0))
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0))
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
})
|
})
|
||||||
It("Throws an error for an account it cannot find the balance for an account at the provided block hash", func() {
|
It("Returns `0` for an error for an account it cannot find the balance for an account at the provided block hash", func() {
|
||||||
_, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
_, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
|
||||||
Expect(err).To(HaveOccurred())
|
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(err).ToNot(HaveOccurred())
|
||||||
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -409,52 +444,64 @@ var _ = Describe("eth state reading tests", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(code).To(Equal((hexutil.Bytes)(test_helpers.ContractCode)))
|
Expect(code).To(Equal((hexutil.Bytes)(test_helpers.ContractCode)))
|
||||||
})
|
})
|
||||||
It("Throws an error for an account it cannot find the code for", func() {
|
It("Returns `nil` for an account it cannot find the code for", func() {
|
||||||
_, err := api.GetCode(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
code, err := api.GetCode(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(code).To(BeEmpty())
|
||||||
})
|
})
|
||||||
It("Throws an error for a contract that doesn't exist at this hieght", func() {
|
It("Returns `nil` for a contract that doesn't exist at this height", func() {
|
||||||
_, err := api.GetCode(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0))
|
code, err := api.GetCode(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(code).To(BeEmpty())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("eth_getStorageAt", func() {
|
Describe("eth_getStorageAt", func() {
|
||||||
It("Throws an error if it tries to access a contract which does not exist", func() {
|
It("Returns empty slice if it tries to access a contract which does not exist", func() {
|
||||||
_, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(0))
|
storage, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(0))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(storage).To(Equal(hexutil.Bytes(make([]byte, 32))))
|
||||||
|
|
||||||
_, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(1))
|
storage, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(1))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(storage).To(Equal(hexutil.Bytes(make([]byte, 32))))
|
||||||
})
|
})
|
||||||
It("Throws an error if it tries to access a contract slot which does not exist", func() {
|
It("Returns empty slice if it tries to access a contract slot which does not exist", func() {
|
||||||
_, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, randomHash.Hex(), rpc.BlockNumberOrHashWithNumber(2))
|
storage, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, randomHash.Hex(), rpc.BlockNumberOrHashWithNumber(2))
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
Expect(storage).To(Equal(hexutil.Bytes(make([]byte, 32))))
|
||||||
})
|
})
|
||||||
It("Retrieves the storage value at the provided contract address and storage leaf key at the block with the provided hash or number", func() {
|
It("Retrieves the storage value at the provided contract address and storage leaf key at the block with the provided hash or number", func() {
|
||||||
// After deployment
|
// After deployment
|
||||||
val, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(2))
|
val, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.IndexOne, rpc.BlockNumberOrHashWithNumber(2))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
expectedRes := hexutil.Bytes(common.Hex2Bytes("01"))
|
expectedRes := hexutil.Bytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||||
Expect(val).To(Equal(expectedRes))
|
Expect(val).To(Equal(expectedRes))
|
||||||
|
|
||||||
val, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(3))
|
val, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.IndexOne, rpc.BlockNumberOrHashWithNumber(3))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
expectedRes = hexutil.Bytes(common.Hex2Bytes("03"))
|
expectedRes = hexutil.Bytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003"))
|
||||||
Expect(val).To(Equal(expectedRes))
|
Expect(val).To(Equal(expectedRes))
|
||||||
|
|
||||||
val, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(4))
|
val, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.IndexOne, rpc.BlockNumberOrHashWithNumber(4))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
expectedRes = hexutil.Bytes(common.Hex2Bytes("09"))
|
expectedRes = hexutil.Bytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009"))
|
||||||
Expect(val).To(Equal(expectedRes))
|
Expect(val).To(Equal(expectedRes))
|
||||||
|
|
||||||
val, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(5))
|
val, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.IndexOne, rpc.BlockNumberOrHashWithNumber(5))
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(val).To(Equal(hexutil.Bytes{}))
|
Expect(val).To(Equal(hexutil.Bytes{}))
|
||||||
})
|
})
|
||||||
|
It("Throws an error for a non-existing block hash", func() {
|
||||||
|
_, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.IndexOne, rpc.BlockNumberOrHashWithHash(randomHash, true))
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError("header for hash not found"))
|
||||||
|
})
|
||||||
|
It("Throws an error for a non-existing block number", func() {
|
||||||
|
_, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.IndexOne, rpc.BlockNumberOrHashWithNumber(chainLength+1))
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError("header not found"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("eth_getHeaderByNumber", func() {
|
Describe("eth_getHeaderByNumber", func() {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestETHWatcher(t *testing.T) {
|
func TestETHSuite(t *testing.T) {
|
||||||
RegisterFailHandler(Fail)
|
RegisterFailHandler(Fail)
|
||||||
RunSpecs(t, "eth ipld server eth suite test")
|
RunSpecs(t, "eth ipld server eth suite test")
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -50,13 +50,13 @@ var _ = Describe("Filterer", func() {
|
|||||||
var expectedEmptyUncles []ipfs.BlockModel
|
var expectedEmptyUncles []ipfs.BlockModel
|
||||||
Expect(iplds.Uncles).To(Equal(expectedEmptyUncles))
|
Expect(iplds.Uncles).To(Equal(expectedEmptyUncles))
|
||||||
Expect(len(iplds.Transactions)).To(Equal(3))
|
Expect(len(iplds.Transactions)).To(Equal(3))
|
||||||
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.MockTransactions.GetRlp(0))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.Tx1)).To(BeTrue())
|
||||||
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.MockTransactions.GetRlp(1))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.Tx2)).To(BeTrue())
|
||||||
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.MockTransactions.GetRlp(2))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.Tx3)).To(BeTrue())
|
||||||
Expect(len(iplds.Receipts)).To(Equal(3))
|
Expect(len(iplds.Receipts)).To(Equal(3))
|
||||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.MockReceipts.GetRlp(0))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct1)).To(BeTrue())
|
||||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.MockReceipts.GetRlp(1))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct2)).To(BeTrue())
|
||||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.MockReceipts.GetRlp(2))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct3)).To(BeTrue())
|
||||||
Expect(len(iplds.StateNodes)).To(Equal(2))
|
Expect(len(iplds.StateNodes)).To(Equal(2))
|
||||||
for _, stateNode := range iplds.StateNodes {
|
for _, stateNode := range iplds.StateNodes {
|
||||||
Expect(stateNode.Type).To(Equal(sdtypes.Leaf))
|
Expect(stateNode.Type).To(Equal(sdtypes.Leaf))
|
||||||
@@ -144,15 +144,15 @@ var _ = Describe("Filterer", func() {
|
|||||||
Expect(iplds5.Header).To(Equal(ipfs.BlockModel{}))
|
Expect(iplds5.Header).To(Equal(ipfs.BlockModel{}))
|
||||||
Expect(len(iplds5.Uncles)).To(Equal(0))
|
Expect(len(iplds5.Uncles)).To(Equal(0))
|
||||||
Expect(len(iplds5.Transactions)).To(Equal(3))
|
Expect(len(iplds5.Transactions)).To(Equal(3))
|
||||||
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.MockTransactions.GetRlp(0))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.Tx1)).To(BeTrue())
|
||||||
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.MockTransactions.GetRlp(1))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.Tx2)).To(BeTrue())
|
||||||
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.MockTransactions.GetRlp(2))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.Tx3)).To(BeTrue())
|
||||||
Expect(len(iplds5.StorageNodes)).To(Equal(0))
|
Expect(len(iplds5.StorageNodes)).To(Equal(0))
|
||||||
Expect(len(iplds5.StateNodes)).To(Equal(0))
|
Expect(len(iplds5.StateNodes)).To(Equal(0))
|
||||||
Expect(len(iplds5.Receipts)).To(Equal(3))
|
Expect(len(iplds5.Receipts)).To(Equal(3))
|
||||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.MockReceipts.GetRlp(0))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct1)).To(BeTrue())
|
||||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.MockReceipts.GetRlp(1))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct2)).To(BeTrue())
|
||||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.MockReceipts.GetRlp(2))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct3)).To(BeTrue())
|
||||||
|
|
||||||
iplds6, err := filterer.Filter(rctsForSelectCollectedTrxs, test_helpers.MockConvertedPayload)
|
iplds6, err := filterer.Filter(rctsForSelectCollectedTrxs, test_helpers.MockConvertedPayload)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@@ -161,7 +161,7 @@ var _ = Describe("Filterer", func() {
|
|||||||
Expect(iplds6.Header).To(Equal(ipfs.BlockModel{}))
|
Expect(iplds6.Header).To(Equal(ipfs.BlockModel{}))
|
||||||
Expect(len(iplds6.Uncles)).To(Equal(0))
|
Expect(len(iplds6.Uncles)).To(Equal(0))
|
||||||
Expect(len(iplds6.Transactions)).To(Equal(1))
|
Expect(len(iplds6.Transactions)).To(Equal(1))
|
||||||
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.MockTransactions.GetRlp(1))).To(BeTrue())
|
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.Tx2)).To(BeTrue())
|
||||||
Expect(len(iplds6.StorageNodes)).To(Equal(0))
|
Expect(len(iplds6.StorageNodes)).To(Equal(0))
|
||||||
Expect(len(iplds6.StateNodes)).To(Equal(0))
|
Expect(len(iplds6.StateNodes)).To(Equal(0))
|
||||||
Expect(len(iplds6.Receipts)).To(Equal(1))
|
Expect(len(iplds6.Receipts)).To(Equal(1))
|
||||||
|
|||||||
@@ -17,7 +17,11 @@
|
|||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"os"
|
||||||
|
|
||||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||||
|
|
||||||
@@ -39,6 +43,28 @@ func ResolveToNodeType(nodeType int) sdtypes.NodeType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadConfig loads chain config from json file
|
||||||
|
func LoadConfig(chainConfigPath string) (*params.ChainConfig, error) {
|
||||||
|
file, err := os.Open(chainConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read chain config file: %v", err)
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
chainConfig := new(params.ChainConfig)
|
||||||
|
if err := json.NewDecoder(file).Decode(chainConfig); err != nil {
|
||||||
|
utils.Fatalf("invalid chain config file: %v", err)
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Using chain config from %s file. Content %+v", chainConfigPath, chainConfig)
|
||||||
|
|
||||||
|
return chainConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ChainConfig returns the appropriate ethereum chain config for the provided chain id
|
// ChainConfig returns the appropriate ethereum chain config for the provided chain id
|
||||||
func ChainConfig(chainID uint64) (*params.ChainConfig, error) {
|
func ChainConfig(chainID uint64) (*params.ChainConfig, error) {
|
||||||
switch chainID {
|
switch chainID {
|
||||||
|
|||||||
+24
-17
@@ -29,15 +29,15 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
RetrieveHeadersByHashesPgStr = `SELECT cid, data
|
RetrieveHeadersByHashesPgStr = `SELECT cid, data
|
||||||
FROM eth.header_cids
|
FROM eth.header_cids
|
||||||
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
||||||
WHERE block_hash = ANY($1::VARCHAR(66)[])`
|
WHERE block_hash = ANY($1::VARCHAR(66)[])`
|
||||||
RetrieveHeadersByBlockNumberPgStr = `SELECT cid, data
|
RetrieveHeadersByBlockNumberPgStr = `SELECT cid, data
|
||||||
FROM eth.header_cids
|
FROM eth.header_cids
|
||||||
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
||||||
WHERE block_number = $1`
|
WHERE block_number = $1`
|
||||||
RetrieveHeaderByHashPgStr = `SELECT cid, data
|
RetrieveHeaderByHashPgStr = `SELECT cid, data
|
||||||
FROM eth.header_cids
|
FROM eth.header_cids
|
||||||
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
||||||
WHERE block_hash = $1`
|
WHERE block_hash = $1`
|
||||||
RetrieveUnclesByHashesPgStr = `SELECT cid, data
|
RetrieveUnclesByHashesPgStr = `SELECT cid, data
|
||||||
@@ -83,7 +83,7 @@ const (
|
|||||||
INNER JOIN eth.transaction_cids ON (receipt_cids.tx_id = transaction_cids.id)
|
INNER JOIN eth.transaction_cids ON (receipt_cids.tx_id = transaction_cids.id)
|
||||||
INNER JOIN public.blocks ON (receipt_cids.mh_key = blocks.key)
|
INNER JOIN public.blocks ON (receipt_cids.mh_key = blocks.key)
|
||||||
WHERE tx_hash = ANY($1::VARCHAR(66)[])`
|
WHERE tx_hash = ANY($1::VARCHAR(66)[])`
|
||||||
RetrieveReceiptsByBlockHashPgStr = `SELECT receipt_cids.cid, data
|
RetrieveReceiptsByBlockHashPgStr = `SELECT receipt_cids.cid, data, eth.transaction_cids.tx_hash
|
||||||
FROM eth.receipt_cids
|
FROM eth.receipt_cids
|
||||||
INNER JOIN eth.transaction_cids ON (receipt_cids.tx_id = transaction_cids.id)
|
INNER JOIN eth.transaction_cids ON (receipt_cids.tx_id = transaction_cids.id)
|
||||||
INNER JOIN eth.header_cids ON (transaction_cids.header_id = header_cids.id)
|
INNER JOIN eth.header_cids ON (transaction_cids.header_id = header_cids.id)
|
||||||
@@ -161,9 +161,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ipldResult struct {
|
type ipldResult struct {
|
||||||
CID string `db:"cid"`
|
CID string `db:"cid"`
|
||||||
Data []byte `db:"data"`
|
Data []byte `db:"data"`
|
||||||
|
TxHash string `db:"tx_hash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IPLDRetriever struct {
|
type IPLDRetriever struct {
|
||||||
db *postgres.DB
|
db *postgres.DB
|
||||||
}
|
}
|
||||||
@@ -345,18 +347,22 @@ func (r *IPLDRetriever) RetrieveReceiptsByTxHashes(hashes []common.Hash) ([]stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RetrieveReceiptsByBlockHash returns the cids and rlp bytes for the receipts corresponding to the provided block hash
|
// RetrieveReceiptsByBlockHash returns the cids and rlp bytes for the receipts corresponding to the provided block hash
|
||||||
func (r *IPLDRetriever) RetrieveReceiptsByBlockHash(hash common.Hash) ([]string, [][]byte, error) {
|
func (r *IPLDRetriever) RetrieveReceiptsByBlockHash(hash common.Hash) ([]string, [][]byte, []common.Hash, error) {
|
||||||
rctResults := make([]ipldResult, 0)
|
rctResults := make([]ipldResult, 0)
|
||||||
if err := r.db.Select(&rctResults, RetrieveReceiptsByBlockHashPgStr, hash.Hex()); err != nil {
|
if err := r.db.Select(&rctResults, RetrieveReceiptsByBlockHashPgStr, hash.Hex()); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
cids := make([]string, len(rctResults))
|
cids := make([]string, len(rctResults))
|
||||||
rcts := make([][]byte, len(rctResults))
|
rcts := make([][]byte, len(rctResults))
|
||||||
|
txs := make([]common.Hash, len(rctResults))
|
||||||
|
|
||||||
for i, res := range rctResults {
|
for i, res := range rctResults {
|
||||||
cids[i] = res.CID
|
cids[i] = res.CID
|
||||||
rcts[i] = res.Data
|
rcts[i] = res.Data
|
||||||
|
txs[i] = common.HexToHash(res.TxHash)
|
||||||
}
|
}
|
||||||
return cids, rcts, nil
|
|
||||||
|
return cids, rcts, txs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetrieveReceiptsByBlockNumber returns the cids and rlp bytes for the receipts corresponding to the provided block hash
|
// RetrieveReceiptsByBlockNumber returns the cids and rlp bytes for the receipts corresponding to the provided block hash
|
||||||
@@ -428,25 +434,26 @@ func (r *IPLDRetriever) RetrieveAccountByAddressAndBlockNumber(address common.Ad
|
|||||||
return accountResult.CID, i[1].([]byte), nil
|
return accountResult.CID, i[1].([]byte), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetrieveStorageAtByAddressAndStorageKeyAndBlockHash returns the cid and rlp bytes for the storage value corresponding to the provided address, storage key, and block hash
|
// RetrieveStorageAtByAddressAndStorageSlotAndBlockHash returns the cid and rlp bytes for the storage value corresponding to the provided address, storage slot, and block hash
|
||||||
func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageKeyAndBlockHash(address common.Address, storageLeafKey, hash common.Hash) (string, []byte, error) {
|
func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageSlotAndBlockHash(address common.Address, key, hash common.Hash) (string, []byte, []byte, error) {
|
||||||
storageResult := new(nodeInfo)
|
storageResult := new(nodeInfo)
|
||||||
stateLeafKey := crypto.Keccak256Hash(address.Bytes())
|
stateLeafKey := crypto.Keccak256Hash(address.Bytes())
|
||||||
if err := r.db.Get(storageResult, RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr, stateLeafKey.Hex(), storageLeafKey.Hex(), hash.Hex()); err != nil {
|
storageHash := crypto.Keccak256Hash(key.Bytes())
|
||||||
return "", nil, err
|
if err := r.db.Get(storageResult, RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr, stateLeafKey.Hex(), storageHash.Hex(), hash.Hex()); err != nil {
|
||||||
|
return "", nil, nil, err
|
||||||
}
|
}
|
||||||
if storageResult.Removed {
|
if storageResult.Removed {
|
||||||
return "", []byte{}, nil
|
return "", []byte{}, []byte{}, nil
|
||||||
}
|
}
|
||||||
var i []interface{}
|
var i []interface{}
|
||||||
if err := rlp.DecodeBytes(storageResult.Data, &i); err != nil {
|
if err := rlp.DecodeBytes(storageResult.Data, &i); err != nil {
|
||||||
err = fmt.Errorf("error decoding storage leaf node rlp: %s", err.Error())
|
err = fmt.Errorf("error decoding storage leaf node rlp: %s", err.Error())
|
||||||
return "", nil, err
|
return "", nil, nil, err
|
||||||
}
|
}
|
||||||
if len(i) != 2 {
|
if len(i) != 2 {
|
||||||
return "", nil, fmt.Errorf("eth IPLDRetriever expected storage leaf node rlp to decode into two elements")
|
return "", nil, nil, fmt.Errorf("eth IPLDRetriever expected storage leaf node rlp to decode into two elements")
|
||||||
}
|
}
|
||||||
return storageResult.CID, i[1].([]byte), nil
|
return storageResult.CID, storageResult.Data, i[1].([]byte), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetrieveStorageAtByAddressAndStorageKeyAndBlockNumber returns the cid and rlp bytes for the storage value corresponding to the provided address, storage key, and block number
|
// RetrieveStorageAtByAddressAndStorageKeyAndBlockNumber returns the cid and rlp bytes for the storage value corresponding to the provided address, storage key, and block number
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ data function sig: 73d4a13a
|
|||||||
// the returned hash chain is ordered head->parent.
|
// the returned hash chain is ordered head->parent.
|
||||||
func MakeChain(n int, parent *types.Block, chainGen func(int, *core.BlockGen)) ([]*types.Block, []types.Receipts, *core.BlockChain) {
|
func MakeChain(n int, parent *types.Block, chainGen func(int, *core.BlockGen)) ([]*types.Block, []types.Receipts, *core.BlockChain) {
|
||||||
config := params.TestChainConfig
|
config := params.TestChainConfig
|
||||||
|
config.LondonBlock = big.NewInt(100)
|
||||||
blocks, receipts := core.GenerateChain(config, parent, ethash.NewFaker(), Testdb, n, chainGen)
|
blocks, receipts := core.GenerateChain(config, parent, ethash.NewFaker(), Testdb, n, chainGen)
|
||||||
chain, _ := core.NewBlockChain(Testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(Testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||||
return append([]*types.Block{parent}, blocks...), receipts, chain
|
return append([]*types.Block{parent}, blocks...), receipts, chain
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package test_helpers
|
package test_helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@@ -34,7 +35,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/statediff/testhelpers"
|
"github.com/ethereum/go-ethereum/statediff/testhelpers"
|
||||||
"github.com/ipfs/go-block-format"
|
blocks "github.com/ipfs/go-block-format"
|
||||||
"github.com/multiformats/go-multihash"
|
"github.com/multiformats/go-multihash"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ var (
|
|||||||
Difficulty: big.NewInt(5000000),
|
Difficulty: big.NewInt(5000000),
|
||||||
Extra: []byte{},
|
Extra: []byte{},
|
||||||
}
|
}
|
||||||
MockTransactions, MockReceipts, SenderAddr = createTransactionsAndReceipts()
|
MockTransactions, MockReceipts, SenderAddr = createLegacyTransactionsAndReceipts()
|
||||||
MockUncles = []*types.Header{
|
MockUncles = []*types.Header{
|
||||||
{
|
{
|
||||||
Time: 1,
|
Time: 1,
|
||||||
@@ -80,7 +81,7 @@ var (
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
ReceiptsRlp, _ = rlp.EncodeToBytes(MockReceipts)
|
ReceiptsRlp, _ = rlp.EncodeToBytes(MockReceipts)
|
||||||
MockBlock = types.NewBlock(&MockHeader, MockTransactions, MockUncles, MockReceipts, new(trie.Trie))
|
MockBlock = createNewBlock(&MockHeader, MockTransactions, MockUncles, MockReceipts, new(trie.Trie))
|
||||||
MockHeaderRlp, _ = rlp.EncodeToBytes(MockBlock.Header())
|
MockHeaderRlp, _ = rlp.EncodeToBytes(MockBlock.Header())
|
||||||
MockChildHeader = types.Header{
|
MockChildHeader = types.Header{
|
||||||
Time: 0,
|
Time: 0,
|
||||||
@@ -104,28 +105,43 @@ var (
|
|||||||
mockTopic21 = common.HexToHash("0x05")
|
mockTopic21 = common.HexToHash("0x05")
|
||||||
mockTopic22 = common.HexToHash("0x07")
|
mockTopic22 = common.HexToHash("0x07")
|
||||||
MockLog1 = &types.Log{
|
MockLog1 = &types.Log{
|
||||||
Address: Address,
|
Address: Address,
|
||||||
Topics: []common.Hash{mockTopic11, mockTopic12},
|
Topics: []common.Hash{mockTopic11, mockTopic12},
|
||||||
Data: []byte{},
|
Data: []byte{},
|
||||||
|
BlockNumber: BlockNumber.Uint64(),
|
||||||
|
TxIndex: 0,
|
||||||
|
Index: 0,
|
||||||
}
|
}
|
||||||
MockLog2 = &types.Log{
|
MockLog2 = &types.Log{
|
||||||
Address: AnotherAddress,
|
Address: AnotherAddress,
|
||||||
Topics: []common.Hash{mockTopic21, mockTopic22},
|
Topics: []common.Hash{mockTopic21, mockTopic22},
|
||||||
Data: []byte{},
|
Data: []byte{},
|
||||||
|
BlockNumber: BlockNumber.Uint64(),
|
||||||
|
TxIndex: 1,
|
||||||
|
Index: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tx1 = GetTxnRlp(0, MockTransactions)
|
||||||
|
Tx2 = GetTxnRlp(1, MockTransactions)
|
||||||
|
Tx3 = GetTxnRlp(2, MockTransactions)
|
||||||
|
|
||||||
|
Rct1 = GetRctRlp(0, MockReceipts)
|
||||||
|
Rct2 = GetRctRlp(1, MockReceipts)
|
||||||
|
Rct3 = GetRctRlp(2, MockReceipts)
|
||||||
|
|
||||||
HeaderCID, _ = ipld.RawdataToCid(ipld.MEthHeader, MockHeaderRlp, multihash.KECCAK_256)
|
HeaderCID, _ = ipld.RawdataToCid(ipld.MEthHeader, MockHeaderRlp, multihash.KECCAK_256)
|
||||||
HeaderMhKey = shared.MultihashKeyFromCID(HeaderCID)
|
HeaderMhKey = shared.MultihashKeyFromCID(HeaderCID)
|
||||||
Trx1CID, _ = ipld.RawdataToCid(ipld.MEthTx, MockTransactions.GetRlp(0), multihash.KECCAK_256)
|
Trx1CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx1, multihash.KECCAK_256)
|
||||||
Trx1MhKey = shared.MultihashKeyFromCID(Trx1CID)
|
Trx1MhKey = shared.MultihashKeyFromCID(Trx1CID)
|
||||||
Trx2CID, _ = ipld.RawdataToCid(ipld.MEthTx, MockTransactions.GetRlp(1), multihash.KECCAK_256)
|
Trx2CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx2, multihash.KECCAK_256)
|
||||||
Trx2MhKey = shared.MultihashKeyFromCID(Trx2CID)
|
Trx2MhKey = shared.MultihashKeyFromCID(Trx2CID)
|
||||||
Trx3CID, _ = ipld.RawdataToCid(ipld.MEthTx, MockTransactions.GetRlp(2), multihash.KECCAK_256)
|
Trx3CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx3, multihash.KECCAK_256)
|
||||||
Trx3MhKey = shared.MultihashKeyFromCID(Trx3CID)
|
Trx3MhKey = shared.MultihashKeyFromCID(Trx3CID)
|
||||||
Rct1CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, MockReceipts.GetRlp(0), multihash.KECCAK_256)
|
Rct1CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, Rct1, multihash.KECCAK_256)
|
||||||
Rct1MhKey = shared.MultihashKeyFromCID(Rct1CID)
|
Rct1MhKey = shared.MultihashKeyFromCID(Rct1CID)
|
||||||
Rct2CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, MockReceipts.GetRlp(1), multihash.KECCAK_256)
|
Rct2CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, Rct2, multihash.KECCAK_256)
|
||||||
Rct2MhKey = shared.MultihashKeyFromCID(Rct2CID)
|
Rct2MhKey = shared.MultihashKeyFromCID(Rct2CID)
|
||||||
Rct3CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, MockReceipts.GetRlp(2), multihash.KECCAK_256)
|
Rct3CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, Rct3, multihash.KECCAK_256)
|
||||||
Rct3MhKey = shared.MultihashKeyFromCID(Rct3CID)
|
Rct3MhKey = shared.MultihashKeyFromCID(Rct3CID)
|
||||||
State1CID, _ = ipld.RawdataToCid(ipld.MEthStateTrie, ContractLeafNode, multihash.KECCAK_256)
|
State1CID, _ = ipld.RawdataToCid(ipld.MEthStateTrie, ContractLeafNode, multihash.KECCAK_256)
|
||||||
State1MhKey = shared.MultihashKeyFromCID(State1CID)
|
State1MhKey = shared.MultihashKeyFromCID(State1CID)
|
||||||
@@ -375,6 +391,8 @@ var (
|
|||||||
StateNodes: MockStateNodes,
|
StateNodes: MockStateNodes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reward = eth.CalcEthBlockReward(MockBlock.Header(), MockBlock.Uncles(), MockBlock.Transactions(), MockReceipts)
|
||||||
|
|
||||||
MockCIDWrapper = ð2.CIDWrapper{
|
MockCIDWrapper = ð2.CIDWrapper{
|
||||||
BlockNumber: new(big.Int).Set(BlockNumber),
|
BlockNumber: new(big.Int).Set(BlockNumber),
|
||||||
Header: eth.HeaderModel{
|
Header: eth.HeaderModel{
|
||||||
@@ -384,7 +402,7 @@ var (
|
|||||||
CID: HeaderCID.String(),
|
CID: HeaderCID.String(),
|
||||||
MhKey: HeaderMhKey,
|
MhKey: HeaderMhKey,
|
||||||
TotalDifficulty: MockBlock.Difficulty().String(),
|
TotalDifficulty: MockBlock.Difficulty().String(),
|
||||||
Reward: "5312500000000000000",
|
Reward: Reward.String(),
|
||||||
StateRoot: MockBlock.Root().String(),
|
StateRoot: MockBlock.Root().String(),
|
||||||
RctRoot: MockBlock.ReceiptHash().String(),
|
RctRoot: MockBlock.ReceiptHash().String(),
|
||||||
TxRoot: MockBlock.TxHash().String(),
|
TxRoot: MockBlock.TxHash().String(),
|
||||||
@@ -410,12 +428,12 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
HeaderIPLD, _ = blocks.NewBlockWithCid(MockHeaderRlp, HeaderCID)
|
HeaderIPLD, _ = blocks.NewBlockWithCid(MockHeaderRlp, HeaderCID)
|
||||||
Trx1IPLD, _ = blocks.NewBlockWithCid(MockTransactions.GetRlp(0), Trx1CID)
|
Trx1IPLD, _ = blocks.NewBlockWithCid(Tx1, Trx1CID)
|
||||||
Trx2IPLD, _ = blocks.NewBlockWithCid(MockTransactions.GetRlp(1), Trx2CID)
|
Trx2IPLD, _ = blocks.NewBlockWithCid(Tx2, Trx2CID)
|
||||||
Trx3IPLD, _ = blocks.NewBlockWithCid(MockTransactions.GetRlp(2), Trx3CID)
|
Trx3IPLD, _ = blocks.NewBlockWithCid(Tx3, Trx3CID)
|
||||||
Rct1IPLD, _ = blocks.NewBlockWithCid(MockReceipts.GetRlp(0), Rct1CID)
|
Rct1IPLD, _ = blocks.NewBlockWithCid(Rct1, Rct1CID)
|
||||||
Rct2IPLD, _ = blocks.NewBlockWithCid(MockReceipts.GetRlp(1), Rct2CID)
|
Rct2IPLD, _ = blocks.NewBlockWithCid(Rct2, Rct2CID)
|
||||||
Rct3IPLD, _ = blocks.NewBlockWithCid(MockReceipts.GetRlp(2), Rct3CID)
|
Rct3IPLD, _ = blocks.NewBlockWithCid(Rct3, Rct3CID)
|
||||||
State1IPLD, _ = blocks.NewBlockWithCid(ContractLeafNode, State1CID)
|
State1IPLD, _ = blocks.NewBlockWithCid(ContractLeafNode, State1CID)
|
||||||
State2IPLD, _ = blocks.NewBlockWithCid(AccountLeafNode, State2CID)
|
State2IPLD, _ = blocks.NewBlockWithCid(AccountLeafNode, State2CID)
|
||||||
StorageIPLD, _ = blocks.NewBlockWithCid(StorageLeafNode, StorageCID)
|
StorageIPLD, _ = blocks.NewBlockWithCid(StorageLeafNode, StorageCID)
|
||||||
@@ -487,10 +505,119 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LondonBlockNum = new(big.Int).Add(BlockNumber, big.NewInt(2))
|
||||||
|
MockLondonHeader = types.Header{
|
||||||
|
Time: 0,
|
||||||
|
Number: LondonBlockNum,
|
||||||
|
Root: common.HexToHash("0x00"),
|
||||||
|
Difficulty: big.NewInt(5000000),
|
||||||
|
Extra: []byte{},
|
||||||
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
|
}
|
||||||
|
|
||||||
|
MockLondonTransactions, MockLondonReceipts, SenderAdd = createDynamicTransactionsAndReceipts(LondonBlockNum)
|
||||||
|
MockLondonBlock = createNewBlock(&MockLondonHeader, MockLondonTransactions, nil, MockLondonReceipts, new(trie.Trie))
|
||||||
|
MockLondonTrxMeta = []eth.TxModel{
|
||||||
|
{
|
||||||
|
CID: "", // This is empty until we go to publish to ipfs
|
||||||
|
MhKey: "",
|
||||||
|
Src: SenderAdd.Hex(),
|
||||||
|
Dst: Address.String(),
|
||||||
|
Index: 0,
|
||||||
|
TxHash: MockLondonTransactions[0].Hash().String(),
|
||||||
|
Data: []byte{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
MockLondonRctMeta = []eth.ReceiptModel{
|
||||||
|
{
|
||||||
|
CID: "",
|
||||||
|
MhKey: "",
|
||||||
|
Topic0s: []string{
|
||||||
|
mockTopic11.String(),
|
||||||
|
},
|
||||||
|
Topic1s: []string{
|
||||||
|
mockTopic12.String(),
|
||||||
|
},
|
||||||
|
Contract: "",
|
||||||
|
ContractHash: "",
|
||||||
|
LogContracts: []string{
|
||||||
|
Address.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
MockConvertedLondonPayload = eth.ConvertedPayload{
|
||||||
|
TotalDifficulty: MockLondonBlock.Difficulty(),
|
||||||
|
Block: MockLondonBlock,
|
||||||
|
Receipts: MockLondonReceipts,
|
||||||
|
TxMetaData: MockLondonTrxMeta,
|
||||||
|
ReceiptMetaData: MockLondonRctMeta,
|
||||||
|
StorageNodes: MockStorageNodes,
|
||||||
|
StateNodes: MockStateNodes,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// createTransactionsAndReceipts is a helper function to generate signed mock transactions and mock receipts with mock logs
|
func createNewBlock(header *types.Header, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, hasher types.TrieHasher) *types.Block {
|
||||||
func createTransactionsAndReceipts() (types.Transactions, types.Receipts, common.Address) {
|
block := types.NewBlock(header, txs, uncles, receipts, hasher)
|
||||||
|
bHash := block.Hash()
|
||||||
|
for _, r := range receipts {
|
||||||
|
for _, l := range r.Logs {
|
||||||
|
l.BlockHash = bHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
|
// createDynamicTransactionsAndReceipts is a helper function to generate signed mock transactions and mock receipts with mock logs
|
||||||
|
func createDynamicTransactionsAndReceipts(blockNumber *big.Int) (types.Transactions, types.Receipts, common.Address) {
|
||||||
|
// make transactions
|
||||||
|
config := params.TestChainConfig
|
||||||
|
config.LondonBlock = blockNumber
|
||||||
|
trx1 := types.NewTx(&types.DynamicFeeTx{
|
||||||
|
ChainID: config.ChainID,
|
||||||
|
Nonce: 1,
|
||||||
|
GasTipCap: big.NewInt(50),
|
||||||
|
GasFeeCap: big.NewInt(100),
|
||||||
|
Gas: 50,
|
||||||
|
To: &Address,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Data: []byte{},
|
||||||
|
})
|
||||||
|
|
||||||
|
transactionSigner := types.MakeSigner(config, blockNumber)
|
||||||
|
mockCurve := elliptic.P256()
|
||||||
|
mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
signedTrx1, err := types.SignTx(trx1, transactionSigner, mockPrvKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
senderAddr, err := types.Sender(transactionSigner, signedTrx1) // same for both trx
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// make receipts
|
||||||
|
// TODO: Change the receipt type to DynamicFeeTxType once this PR is merged.
|
||||||
|
// https://github.com/ethereum/go-ethereum/pull/22806
|
||||||
|
mockReceipt1 := &types.Receipt{
|
||||||
|
Type: types.AccessListTxType,
|
||||||
|
PostState: common.HexToHash("0x1").Bytes(),
|
||||||
|
Status: types.ReceiptStatusSuccessful,
|
||||||
|
CumulativeGasUsed: 50,
|
||||||
|
Logs: []*types.Log{},
|
||||||
|
TxHash: signedTrx1.Hash(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.Transactions{signedTrx1}, types.Receipts{mockReceipt1}, senderAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// createLegacyTransactionsAndReceipts is a helper function to generate signed mock transactions and mock receipts with mock logs
|
||||||
|
func createLegacyTransactionsAndReceipts() (types.Transactions, types.Receipts, common.Address) {
|
||||||
// make transactions
|
// make transactions
|
||||||
trx1 := types.NewTransaction(0, Address, big.NewInt(1000), 50, big.NewInt(100), []byte{})
|
trx1 := types.NewTransaction(0, Address, big.NewInt(1000), 50, big.NewInt(100), []byte{})
|
||||||
trx2 := types.NewTransaction(1, AnotherAddress, big.NewInt(2000), 100, big.NewInt(200), []byte{})
|
trx2 := types.NewTransaction(1, AnotherAddress, big.NewInt(2000), 100, big.NewInt(200), []byte{})
|
||||||
@@ -519,13 +646,44 @@ func createTransactionsAndReceipts() (types.Transactions, types.Receipts, common
|
|||||||
}
|
}
|
||||||
// make receipts
|
// make receipts
|
||||||
mockReceipt1 := types.NewReceipt(common.HexToHash("0x0").Bytes(), false, 50)
|
mockReceipt1 := types.NewReceipt(common.HexToHash("0x0").Bytes(), false, 50)
|
||||||
|
|
||||||
|
hash1 := signedTrx1.Hash()
|
||||||
|
MockLog1.TxHash = hash1
|
||||||
|
|
||||||
mockReceipt1.Logs = []*types.Log{MockLog1}
|
mockReceipt1.Logs = []*types.Log{MockLog1}
|
||||||
mockReceipt1.TxHash = signedTrx1.Hash()
|
mockReceipt1.TxHash = hash1
|
||||||
|
mockReceipt1.GasUsed = mockReceipt1.CumulativeGasUsed
|
||||||
|
|
||||||
mockReceipt2 := types.NewReceipt(common.HexToHash("0x1").Bytes(), false, 100)
|
mockReceipt2 := types.NewReceipt(common.HexToHash("0x1").Bytes(), false, 100)
|
||||||
|
hash2 := signedTrx2.Hash()
|
||||||
|
MockLog2.TxHash = hash2
|
||||||
|
|
||||||
mockReceipt2.Logs = []*types.Log{MockLog2}
|
mockReceipt2.Logs = []*types.Log{MockLog2}
|
||||||
mockReceipt2.TxHash = signedTrx2.Hash()
|
mockReceipt2.TxHash = hash2
|
||||||
mockReceipt3 := types.NewReceipt(common.HexToHash("0x2").Bytes(), false, 75)
|
mockReceipt2.GasUsed = mockReceipt2.CumulativeGasUsed - mockReceipt1.CumulativeGasUsed
|
||||||
|
|
||||||
|
mockReceipt3 := types.NewReceipt(common.HexToHash("0x2").Bytes(), false, 175)
|
||||||
mockReceipt3.Logs = []*types.Log{}
|
mockReceipt3.Logs = []*types.Log{}
|
||||||
mockReceipt3.TxHash = signedTrx3.Hash()
|
mockReceipt3.TxHash = signedTrx3.Hash()
|
||||||
|
mockReceipt3.GasUsed = mockReceipt3.CumulativeGasUsed - mockReceipt2.CumulativeGasUsed
|
||||||
|
|
||||||
return types.Transactions{signedTrx1, signedTrx2, signedTrx3}, types.Receipts{mockReceipt1, mockReceipt2, mockReceipt3}, SenderAddr
|
return types.Transactions{signedTrx1, signedTrx2, signedTrx3}, types.Receipts{mockReceipt1, mockReceipt2, mockReceipt3}, SenderAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetTxnRlp(num int, txs types.Transactions) []byte {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
txs.EncodeIndex(num, buf)
|
||||||
|
tx := make([]byte, buf.Len())
|
||||||
|
copy(tx, buf.Bytes())
|
||||||
|
buf.Reset()
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRctRlp(num int, rcts types.Receipts) []byte {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
rcts.EncodeIndex(num, buf)
|
||||||
|
rct := make([]byte, buf.Len())
|
||||||
|
copy(rct, buf.Bytes())
|
||||||
|
buf.Reset()
|
||||||
|
return rct
|
||||||
|
}
|
||||||
|
|||||||
+29
-20
@@ -29,20 +29,25 @@ import (
|
|||||||
|
|
||||||
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
||||||
type RPCTransaction struct {
|
type RPCTransaction struct {
|
||||||
BlockHash *common.Hash `json:"blockHash"`
|
BlockHash *common.Hash `json:"blockHash"`
|
||||||
BlockNumber *hexutil.Big `json:"blockNumber"`
|
BlockNumber *hexutil.Big `json:"blockNumber"`
|
||||||
From common.Address `json:"from"`
|
From common.Address `json:"from"`
|
||||||
Gas hexutil.Uint64 `json:"gas"`
|
Gas hexutil.Uint64 `json:"gas"`
|
||||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||||
Hash common.Hash `json:"hash"`
|
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
|
||||||
Input hexutil.Bytes `json:"input"`
|
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
|
||||||
Nonce hexutil.Uint64 `json:"nonce"`
|
Hash common.Hash `json:"hash"`
|
||||||
To *common.Address `json:"to"`
|
Input hexutil.Bytes `json:"input"`
|
||||||
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
|
Nonce hexutil.Uint64 `json:"nonce"`
|
||||||
Value *hexutil.Big `json:"value"`
|
To *common.Address `json:"to"`
|
||||||
V *hexutil.Big `json:"v"`
|
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
|
||||||
R *hexutil.Big `json:"r"`
|
Value *hexutil.Big `json:"value"`
|
||||||
S *hexutil.Big `json:"s"`
|
Type hexutil.Uint64 `json:"type"`
|
||||||
|
Accesses *types.AccessList `json:"accessList,omitempty"`
|
||||||
|
ChainID *hexutil.Big `json:"chainId,omitempty"`
|
||||||
|
V *hexutil.Big `json:"v"`
|
||||||
|
R *hexutil.Big `json:"r"`
|
||||||
|
S *hexutil.Big `json:"s"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RPCReceipt represents a receipt that will serialize to the RPC representation of a receipt
|
// RPCReceipt represents a receipt that will serialize to the RPC representation of a receipt
|
||||||
@@ -82,12 +87,16 @@ type StorageResult struct {
|
|||||||
|
|
||||||
// CallArgs represents the arguments for a call.
|
// CallArgs represents the arguments for a call.
|
||||||
type CallArgs struct {
|
type CallArgs struct {
|
||||||
From *common.Address `json:"from"`
|
From *common.Address `json:"from"`
|
||||||
To *common.Address `json:"to"`
|
To *common.Address `json:"to"`
|
||||||
Gas *hexutil.Uint64 `json:"gas"`
|
Gas *hexutil.Uint64 `json:"gas"`
|
||||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||||
Value *hexutil.Big `json:"value"`
|
MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"`
|
||||||
Data *hexutil.Bytes `json:"data"`
|
MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"`
|
||||||
|
Value *hexutil.Big `json:"value"`
|
||||||
|
Data *hexutil.Bytes `json:"data"`
|
||||||
|
AccessList *types.AccessList `json:"accessList,omitempty"`
|
||||||
|
Input *hexutil.Bytes `json:"input"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// account indicates the overriding fields of account during the execution of
|
// account indicates the overriding fields of account during the execution of
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
gqlclient "github.com/machinebox/graphql"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StorageResponse struct {
|
||||||
|
Cid string `json:"cid"`
|
||||||
|
Value common.Hash `json:"value"`
|
||||||
|
IpldBlock hexutil.Bytes `json:"ipldBlock"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetStorageAt struct {
|
||||||
|
Response StorageResponse `json:"getStorageAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogResponse struct {
|
||||||
|
Topics []common.Hash `json:"topics"`
|
||||||
|
Data hexutil.Bytes `json:"data"`
|
||||||
|
Transaction TransactionResp `json:"transaction"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionResp struct {
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetLogs struct {
|
||||||
|
Responses []LogResponse `json:"getLogs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
client *gqlclient.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(endpoint string) *Client {
|
||||||
|
client := gqlclient.NewClient(endpoint)
|
||||||
|
return &Client{client: client}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetLogs(ctx context.Context, hash common.Hash, address common.Address) ([]LogResponse, error) {
|
||||||
|
getLogsQuery := fmt.Sprintf(`
|
||||||
|
query{
|
||||||
|
getLogs(blockHash: "%s", contract: "%s") {
|
||||||
|
data
|
||||||
|
topics
|
||||||
|
transaction {
|
||||||
|
hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, hash.String(), address.String())
|
||||||
|
|
||||||
|
req := gqlclient.NewRequest(getLogsQuery)
|
||||||
|
req.Header.Set("Cache-Control", "no-cache")
|
||||||
|
|
||||||
|
var respData map[string]interface{}
|
||||||
|
err := c.client.Run(ctx, req, &respData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonStr, err := json.Marshal(respData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs GetLogs
|
||||||
|
err = json.Unmarshal(jsonStr, &logs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return logs.Responses, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetStorageAt(ctx context.Context, hash common.Hash, address common.Address, slot string) (*StorageResponse, error) {
|
||||||
|
getLogsQuery := fmt.Sprintf(`
|
||||||
|
query{
|
||||||
|
getStorageAt(blockHash: "%s", contract: "%s",slot: "%s") {
|
||||||
|
cid
|
||||||
|
value
|
||||||
|
ipldBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, hash.String(), address.String(), common.HexToHash(slot))
|
||||||
|
|
||||||
|
req := gqlclient.NewRequest(getLogsQuery)
|
||||||
|
req.Header.Set("Cache-Control", "no-cache")
|
||||||
|
|
||||||
|
var respData map[string]interface{}
|
||||||
|
err := c.client.Run(ctx, req, &respData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonStr, err := json.Marshal(respData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var storageAt GetStorageAt
|
||||||
|
err = json.Unmarshal(jsonStr, &storageAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &storageAt.Response, nil
|
||||||
|
}
|
||||||
+105
-1
@@ -19,6 +19,7 @@ package graphql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||||
@@ -91,6 +93,8 @@ type Log struct {
|
|||||||
backend *eth.Backend
|
backend *eth.Backend
|
||||||
transaction *Transaction
|
transaction *Transaction
|
||||||
log *types.Log
|
log *types.Log
|
||||||
|
cid string
|
||||||
|
ipldBlock []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Log) Transaction(ctx context.Context) *Transaction {
|
func (l *Log) Transaction(ctx context.Context) *Transaction {
|
||||||
@@ -117,6 +121,14 @@ func (l *Log) Data(ctx context.Context) hexutil.Bytes {
|
|||||||
return hexutil.Bytes(l.log.Data)
|
return hexutil.Bytes(l.log.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Log) Cid(ctx context.Context) string {
|
||||||
|
return l.cid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Log) IpldBlock(ctx context.Context) hexutil.Bytes {
|
||||||
|
return hexutil.Bytes(l.ipldBlock)
|
||||||
|
}
|
||||||
|
|
||||||
// Transaction represents an Ethereum transaction.
|
// Transaction represents an Ethereum transaction.
|
||||||
// backend and hash are mandatory; all others will be fetched when required.
|
// backend and hash are mandatory; all others will be fetched when required.
|
||||||
type Transaction struct {
|
type Transaction struct {
|
||||||
@@ -867,7 +879,11 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
|
|||||||
if args.To != nil {
|
if args.To != nil {
|
||||||
to = rpc.BlockNumber(*args.To)
|
to = rpc.BlockNumber(*args.To)
|
||||||
} else {
|
} else {
|
||||||
to = rpc.BlockNumber(r.backend.CurrentBlock().Number().Int64())
|
block, err := r.backend.CurrentBlock()
|
||||||
|
if err != nil {
|
||||||
|
return []*Block{}, nil
|
||||||
|
}
|
||||||
|
to = rpc.BlockNumber(block.Number().Int64())
|
||||||
}
|
}
|
||||||
if to < from {
|
if to < from {
|
||||||
return []*Block{}, nil
|
return []*Block{}, nil
|
||||||
@@ -940,3 +956,91 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria
|
|||||||
filter := filters.NewRangeFilter(filters.Backend(r.backend), begin, end, addresses, topics)
|
filter := filters.NewRangeFilter(filters.Backend(r.backend), begin, end, addresses, topics)
|
||||||
return runFilter(ctx, r.backend, filter)
|
return runFilter(ctx, r.backend, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StorageResult represents a storage slot value. All arguments are mandatory.
|
||||||
|
type StorageResult struct {
|
||||||
|
value []byte
|
||||||
|
cid string
|
||||||
|
ipldBlock []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageResult) Value(ctx context.Context) common.Hash {
|
||||||
|
return common.BytesToHash(s.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageResult) Cid(ctx context.Context) string {
|
||||||
|
return s.cid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StorageResult) IpldBlock(ctx context.Context) hexutil.Bytes {
|
||||||
|
return hexutil.Bytes(s.ipldBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) GetStorageAt(ctx context.Context, args struct {
|
||||||
|
BlockHash common.Hash
|
||||||
|
Contract common.Address
|
||||||
|
Slot common.Hash
|
||||||
|
}) (*StorageResult, error) {
|
||||||
|
cid, ipldBlock, rlpValue, err := r.backend.IPLDRetriever.RetrieveStorageAtByAddressAndStorageSlotAndBlockHash(args.Contract, args.Slot, args.BlockHash)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
ret := StorageResult{value: []byte{}, cid: "", ipldBlock: []byte{}}
|
||||||
|
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var value interface{}
|
||||||
|
err = rlp.DecodeBytes(rlpValue, &value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := StorageResult{value: value.([]byte), cid: cid, ipldBlock: ipldBlock}
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) GetLogs(ctx context.Context, args struct {
|
||||||
|
BlockHash common.Hash
|
||||||
|
Contract *common.Address
|
||||||
|
}) (*[]*Log, error) {
|
||||||
|
ret := make([]*Log, 0, 10)
|
||||||
|
|
||||||
|
receiptCIDs, receiptsBytes, txs, err := r.backend.IPLDRetriever.RetrieveReceiptsByBlockHash(args.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var logIndexInBlock uint = 0
|
||||||
|
receipts := make(types.Receipts, len(receiptsBytes))
|
||||||
|
for index, receiptBytes := range receiptsBytes {
|
||||||
|
receiptCID := receiptCIDs[index]
|
||||||
|
receipt := new(types.Receipt)
|
||||||
|
if err := rlp.DecodeBytes(receiptBytes, receipt); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
receipts[index] = receipt
|
||||||
|
for _, log := range receipt.Logs {
|
||||||
|
log.Index = logIndexInBlock
|
||||||
|
logIndexInBlock++
|
||||||
|
|
||||||
|
if args.Contract == nil || *args.Contract == log.Address {
|
||||||
|
ret = append(ret, &Log{
|
||||||
|
backend: r.backend,
|
||||||
|
log: log,
|
||||||
|
cid: receiptCID,
|
||||||
|
ipldBlock: receiptBytes,
|
||||||
|
transaction: &Transaction{
|
||||||
|
hash: txs[index],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|||||||
+201
-2
@@ -17,15 +17,214 @@
|
|||||||
package graphql_test
|
package graphql_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||||
|
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||||
|
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||||
|
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||||
|
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
||||||
"github.com/vulcanize/ipld-eth-server/pkg/graphql"
|
"github.com/vulcanize/ipld-eth-server/pkg/graphql"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("GraphQL", func() {
|
var _ = Describe("GraphQL", func() {
|
||||||
It("Builds the schema and creates a new handler", func() {
|
const (
|
||||||
_, err := graphql.NewHandler(nil)
|
gqlEndPoint = "127.0.0.1:8083"
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f")
|
||||||
|
randomHash = crypto.Keccak256Hash(randomAddr.Bytes())
|
||||||
|
blocks []*types.Block
|
||||||
|
receipts []types.Receipts
|
||||||
|
chain *core.BlockChain
|
||||||
|
db *postgres.DB
|
||||||
|
blockHashes []common.Hash
|
||||||
|
backend *eth.Backend
|
||||||
|
graphQLServer *graphql.Service
|
||||||
|
chainConfig = params.TestChainConfig
|
||||||
|
mockTD = big.NewInt(1337)
|
||||||
|
client = graphql.NewClient(fmt.Sprintf("http://%s/graphql", gqlEndPoint))
|
||||||
|
ctx = context.Background()
|
||||||
|
blockHash common.Hash
|
||||||
|
contractAddress common.Address
|
||||||
|
)
|
||||||
|
|
||||||
|
It("test init", func() {
|
||||||
|
var err error
|
||||||
|
db, err = shared.SetupDB()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
transformer := eth2.NewStateDiffTransformer(chainConfig, db)
|
||||||
|
backend, err = eth.NewEthBackend(db, ð.Config{
|
||||||
|
ChainConfig: chainConfig,
|
||||||
|
VmConfig: vm.Config{},
|
||||||
|
RPCGasCap: big.NewInt(10000000000),
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// make the test blockchain (and state)
|
||||||
|
blocks, receipts, chain = test_helpers.MakeChain(5, test_helpers.Genesis, test_helpers.TestChainGen)
|
||||||
|
params := statediff.Params{
|
||||||
|
IntermediateStateNodes: true,
|
||||||
|
IntermediateStorageNodes: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate over the blocks, generating statediff payloads, and transforming the data into Postgres
|
||||||
|
builder := statediff.NewBuilder(chain.StateCache())
|
||||||
|
for i, block := range blocks {
|
||||||
|
blockHashes = append(blockHashes, block.Hash())
|
||||||
|
var args statediff.Args
|
||||||
|
var rcts types.Receipts
|
||||||
|
if i == 0 {
|
||||||
|
args = statediff.Args{
|
||||||
|
OldStateRoot: common.Hash{},
|
||||||
|
NewStateRoot: block.Root(),
|
||||||
|
BlockNumber: block.Number(),
|
||||||
|
BlockHash: block.Hash(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args = statediff.Args{
|
||||||
|
OldStateRoot: blocks[i-1].Root(),
|
||||||
|
NewStateRoot: block.Root(),
|
||||||
|
BlockNumber: block.Number(),
|
||||||
|
BlockHash: block.Hash(),
|
||||||
|
}
|
||||||
|
rcts = receipts[i-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
var diff statediff.StateObject
|
||||||
|
diff, err = builder.BuildStateDiffObject(args, params)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
diffRlp, err := rlp.EncodeToBytes(diff)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
blockRlp, err := rlp.EncodeToBytes(block)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
receiptsRlp, err := rlp.EncodeToBytes(rcts)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
payload := statediff.Payload{
|
||||||
|
StateObjectRlp: diffRlp,
|
||||||
|
BlockRlp: blockRlp,
|
||||||
|
ReceiptsRlp: receiptsRlp,
|
||||||
|
TotalDifficulty: mockTD,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = transformer.Transform(0, payload)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert some non-canonical data into the database so that we test our ability to discern canonicity
|
||||||
|
indexAndPublisher := eth2.NewIPLDPublisher(db)
|
||||||
|
blockHash = test_helpers.MockBlock.Hash()
|
||||||
|
contractAddress = test_helpers.ContractAddr
|
||||||
|
|
||||||
|
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// The non-canonical header has a child
|
||||||
|
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayloadForChild)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = publishCode(db, test_helpers.ContractCodeHash, test_helpers.ContractCode)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
graphQLServer, err = graphql.New(backend, gqlEndPoint, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = graphQLServer.Start(nil)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
defer It("test teardown", func() {
|
||||||
|
err := graphQLServer.Stop()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
eth.TearDownDB(db)
|
||||||
|
chain.Stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("eth_getLogs", func() {
|
||||||
|
It("Retrieves logs that matches the provided blockHash and contract address", func() {
|
||||||
|
logs, err := client.GetLogs(ctx, blockHash, contractAddress)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
expectedLogs := []graphql.LogResponse{
|
||||||
|
{
|
||||||
|
Topics: test_helpers.MockLog1.Topics,
|
||||||
|
Data: hexutil.Bytes(test_helpers.MockLog1.Data),
|
||||||
|
Transaction: graphql.TransactionResp{Hash: test_helpers.MockTransactions[0].Hash()},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Expect(logs).To(Equal(expectedLogs))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Retrieves logs with random hash", func() {
|
||||||
|
logs, err := client.GetLogs(ctx, randomHash, contractAddress)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(len(logs)).To(Equal(0))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("eth_getStorageAt", func() {
|
||||||
|
It("Retrieves the storage value at the provided contract address and storage leaf key at the block with the provided hash", func() {
|
||||||
|
storageRes, err := client.GetStorageAt(ctx, blockHashes[2], contractAddress, test_helpers.IndexOne)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(common.HexToHash("01")))
|
||||||
|
|
||||||
|
storageRes, err = client.GetStorageAt(ctx, blockHashes[3], contractAddress, test_helpers.IndexOne)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(common.HexToHash("03")))
|
||||||
|
|
||||||
|
storageRes, err = client.GetStorageAt(ctx, blockHashes[4], contractAddress, test_helpers.IndexOne)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(common.HexToHash("09")))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Retrieves empty data if it tries to access a contract at a blockHash which does not exist", func() {
|
||||||
|
storageRes, err := client.GetStorageAt(ctx, blockHashes[0], contractAddress, test_helpers.IndexOne)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(common.Hash{}))
|
||||||
|
|
||||||
|
storageRes, err = client.GetStorageAt(ctx, blockHashes[1], contractAddress, test_helpers.IndexOne)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(common.Hash{}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Retrieves empty data if it tries to access a contract slot which does not exist", func() {
|
||||||
|
storageRes, err := client.GetStorageAt(ctx, blockHashes[3], contractAddress, randomHash.Hex())
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(common.Hash{}))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func publishCode(db *postgres.DB, codeHash common.Hash, code []byte) error {
|
||||||
|
tx, err := db.Beginx()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mhKey, err := shared.MultihashKeyFromKeccak256(codeHash)
|
||||||
|
if err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := shared.PublishDirect(tx, mhKey, code); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Commit()
|
||||||
|
}
|
||||||
|
|||||||
+27
-1
@@ -65,7 +65,13 @@ const schema string = `
|
|||||||
# Data is unindexed data for this log.
|
# Data is unindexed data for this log.
|
||||||
data: Bytes!
|
data: Bytes!
|
||||||
# Transaction is the transaction that generated this log entry.
|
# Transaction is the transaction that generated this log entry.
|
||||||
transaction: Transaction!
|
transaction: Transaction
|
||||||
|
|
||||||
|
# CID for the Receipt IPLD block this Log exists in.
|
||||||
|
cid: String!
|
||||||
|
|
||||||
|
# IPLD block data for the Receipt this Log exists in.
|
||||||
|
ipldBlock: Bytes!
|
||||||
}
|
}
|
||||||
|
|
||||||
# Transaction is an Ethereum transaction.
|
# Transaction is an Ethereum transaction.
|
||||||
@@ -259,16 +265,36 @@ const schema string = `
|
|||||||
topics: [[Bytes32!]!]
|
topics: [[Bytes32!]!]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Storage trie value with IPLD data.
|
||||||
|
type StorageResult {
|
||||||
|
value: Bytes32!
|
||||||
|
|
||||||
|
# CID for the storage trie IPLD block.
|
||||||
|
cid: String!
|
||||||
|
|
||||||
|
# Storage trie IPLD block.
|
||||||
|
ipldBlock: Bytes!
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
# Block fetches an Ethereum block by number or by hash. If neither is
|
# Block fetches an Ethereum block by number or by hash. If neither is
|
||||||
# supplied, the most recent known block is returned.
|
# supplied, the most recent known block is returned.
|
||||||
block(number: Long, hash: Bytes32): Block
|
block(number: Long, hash: Bytes32): Block
|
||||||
|
|
||||||
# Blocks returns all the blocks between two numbers, inclusive. If
|
# Blocks returns all the blocks between two numbers, inclusive. If
|
||||||
# to is not supplied, it defaults to the most recent known block.
|
# to is not supplied, it defaults to the most recent known block.
|
||||||
blocks(from: Long!, to: Long): [Block!]!
|
blocks(from: Long!, to: Long): [Block!]!
|
||||||
|
|
||||||
# Transaction returns a transaction specified by its hash.
|
# Transaction returns a transaction specified by its hash.
|
||||||
transaction(hash: Bytes32!): Transaction
|
transaction(hash: Bytes32!): Transaction
|
||||||
|
|
||||||
# Logs returns log entries matching the provided filter.
|
# Logs returns log entries matching the provided filter.
|
||||||
logs(filter: FilterCriteria!): [Log!]!
|
logs(filter: FilterCriteria!): [Log!]!
|
||||||
|
|
||||||
|
# Get storage slot by block hash and contract address.
|
||||||
|
getStorageAt(blockHash: Bytes32!, contract: Address!, slot: Bytes32!): StorageResult
|
||||||
|
|
||||||
|
# Get contract logs by block hash and contract address.
|
||||||
|
getLogs(blockHash: Bytes32!, contract: Address): [Log!]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2021 Vulcanize
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// APIName is the namespace for the watcher's eth api
|
||||||
|
const APIName = "net"
|
||||||
|
|
||||||
|
// APIVersion is the version of the watcher's eth api
|
||||||
|
const APIVersion = "0.0.1"
|
||||||
|
|
||||||
|
// PublicNetAPI is the net nampespace API
|
||||||
|
type PublicNetAPI struct {
|
||||||
|
// Proxy node for forwarding cache misses
|
||||||
|
networkVersion uint64
|
||||||
|
rpc *rpc.Client
|
||||||
|
ethClient *ethclient.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPublicNetAPI creates a new PublicNetAPI with the provided underlying Backend
|
||||||
|
func NewPublicNetAPI(networkID uint64, client *rpc.Client) *PublicNetAPI {
|
||||||
|
var ethClient *ethclient.Client
|
||||||
|
if client != nil {
|
||||||
|
ethClient = ethclient.NewClient(client)
|
||||||
|
}
|
||||||
|
return &PublicNetAPI{
|
||||||
|
networkVersion: networkID,
|
||||||
|
rpc: client,
|
||||||
|
ethClient: ethClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listening returns an indication if the node is listening for network connections.
|
||||||
|
func (pna *PublicNetAPI) Listening() bool {
|
||||||
|
// in this case it is actually whether or not the proxied node is listening
|
||||||
|
if pna.rpc != nil {
|
||||||
|
var listening bool
|
||||||
|
if err := pna.rpc.Call(&listening, "net_listening"); err == nil {
|
||||||
|
return listening
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerCount returns the number of connected peers
|
||||||
|
func (pna *PublicNetAPI) PeerCount() hexutil.Uint {
|
||||||
|
// in this case it is actually the peer count of the proxied node
|
||||||
|
if pna.rpc != nil {
|
||||||
|
var num hexutil.Uint
|
||||||
|
if err := pna.rpc.Call(&num, "net_peerCount"); err == nil {
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hexutil.Uint(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns the current ethereum protocol version.
|
||||||
|
func (pna *PublicNetAPI) Version() string {
|
||||||
|
if pna.networkVersion != 0 {
|
||||||
|
return fmt.Sprintf("%d", pna.networkVersion)
|
||||||
|
}
|
||||||
|
if pna.rpc != nil {
|
||||||
|
var version string
|
||||||
|
if err := pna.rpc.Call(&version, "net_version"); err == nil {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2021 Vulcanize
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package net_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
"github.com/vulcanize/ipld-eth-server/pkg/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("API", func() {
|
||||||
|
var (
|
||||||
|
api *net.PublicNetAPI
|
||||||
|
)
|
||||||
|
BeforeEach(func() {
|
||||||
|
api = net.NewPublicNetAPI(1, nil)
|
||||||
|
})
|
||||||
|
Describe("net_listening", func() {
|
||||||
|
It("Retrieves whether or not the node is listening to the p2p network", func() {
|
||||||
|
listening := api.Listening()
|
||||||
|
Expect(listening).To(BeFalse())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("net_version", func() {
|
||||||
|
It("Retrieves the network id", func() {
|
||||||
|
version := api.Version()
|
||||||
|
Expect(version).To(Equal("1"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// TODO: test PeerCount with mock proxy node
|
||||||
|
})
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2021 Vulcanize
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package net_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNetSuite(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "eth ipld server net suite test")
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func() {
|
||||||
|
logrus.SetOutput(ioutil.Discard)
|
||||||
|
})
|
||||||
+1
-1
@@ -41,7 +41,7 @@ func StartHTTPEndpoint(endpoint string, apis []rpc.API, modules []string, cors [
|
|||||||
utils.Fatalf("Could not start RPC api: %v", err)
|
utils.Fatalf("Could not start RPC api: %v", err)
|
||||||
}
|
}
|
||||||
extapiURL := fmt.Sprintf("http://%v/", addr)
|
extapiURL := fmt.Sprintf("http://%v/", addr)
|
||||||
log.Info("HTTP endpoint opened", "url", extapiURL)
|
log.Infof("HTTP endpoint opened %s", extapiURL)
|
||||||
|
|
||||||
return srv, err
|
return srv, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,14 +19,12 @@ package serve
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||||
v "github.com/vulcanize/ipld-eth-server/version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// APIName is the namespace used for the state diffing service API
|
// APIName is the namespace used for the state diffing service API
|
||||||
@@ -90,32 +88,3 @@ func (api *PublicServerAPI) Stream(ctx context.Context, params eth.SubscriptionS
|
|||||||
func (api *PublicServerAPI) Chain() shared.ChainType {
|
func (api *PublicServerAPI) Chain() shared.ChainType {
|
||||||
return shared.Ethereum
|
return shared.Ethereum
|
||||||
}
|
}
|
||||||
|
|
||||||
// Struct for holding watcher meta data
|
|
||||||
type InfoAPI struct{}
|
|
||||||
|
|
||||||
// NewInfoAPI creates a new InfoAPI
|
|
||||||
func NewInfoAPI() *InfoAPI {
|
|
||||||
return &InfoAPI{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modules returns modules supported by this api
|
|
||||||
func (iapi *InfoAPI) Modules() map[string]string {
|
|
||||||
return map[string]string{
|
|
||||||
"vdb": "Stream",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeInfo gathers and returns a collection of metadata for the watcher
|
|
||||||
func (iapi *InfoAPI) NodeInfo() *p2p.NodeInfo {
|
|
||||||
return &p2p.NodeInfo{
|
|
||||||
// TODO: formalize this
|
|
||||||
ID: "vulcanizeDB",
|
|
||||||
Name: "ipld-eth-server",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version returns the version of the watcher
|
|
||||||
func (iapi *InfoAPI) Version() string {
|
|
||||||
return v.VersionWithMeta
|
|
||||||
}
|
|
||||||
|
|||||||
+107
-26
@@ -17,6 +17,7 @@
|
|||||||
package serve
|
package serve
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
@@ -48,19 +49,37 @@ const (
|
|||||||
|
|
||||||
ETH_DEFAULT_SENDER_ADDR = "ETH_DEFAULT_SENDER_ADDR"
|
ETH_DEFAULT_SENDER_ADDR = "ETH_DEFAULT_SENDER_ADDR"
|
||||||
ETH_RPC_GAS_CAP = "ETH_RPC_GAS_CAP"
|
ETH_RPC_GAS_CAP = "ETH_RPC_GAS_CAP"
|
||||||
|
ETH_CHAIN_CONFIG = "ETH_CHAIN_CONFIG"
|
||||||
ETH_SUPPORTS_STATEDIFF = "ETH_SUPPORTS_STATEDIFF"
|
ETH_SUPPORTS_STATEDIFF = "ETH_SUPPORTS_STATEDIFF"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config struct
|
// Config struct
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DB *postgres.DB
|
DB *postgres.DB
|
||||||
DBConfig postgres.Config
|
DBConfig postgres.Config
|
||||||
WSEndpoint string
|
|
||||||
HTTPEndpoint string
|
WSEnabled bool
|
||||||
IPCEndpoint string
|
WSEndpoint string
|
||||||
|
|
||||||
|
HTTPEnabled bool
|
||||||
|
HTTPEndpoint string
|
||||||
|
|
||||||
|
IPCEnabled bool
|
||||||
|
IPCEndpoint string
|
||||||
|
|
||||||
|
EthGraphqlEnabled bool
|
||||||
|
EthGraphqlEndpoint string
|
||||||
|
|
||||||
|
IpldGraphqlEnabled bool
|
||||||
|
IpldGraphqlEndpoint string
|
||||||
|
IpldPostgraphileEndpoint string
|
||||||
|
TracingHttpEndpoint string
|
||||||
|
TracingPostgraphileEndpoint string
|
||||||
|
|
||||||
ChainConfig *params.ChainConfig
|
ChainConfig *params.ChainConfig
|
||||||
DefaultSender *common.Address
|
DefaultSender *common.Address
|
||||||
RPCGasCap *big.Int
|
RPCGasCap *big.Int
|
||||||
|
EthHttpEndpoint string
|
||||||
Client *rpc.Client
|
Client *rpc.Client
|
||||||
SupportStateDiff bool
|
SupportStateDiff bool
|
||||||
}
|
}
|
||||||
@@ -70,43 +89,100 @@ type Config struct {
|
|||||||
func NewConfig() (*Config, error) {
|
func NewConfig() (*Config, error) {
|
||||||
c := new(Config)
|
c := new(Config)
|
||||||
|
|
||||||
viper.BindEnv("server.wsPath", SERVER_WS_PATH)
|
|
||||||
viper.BindEnv("server.ipcPath", SERVER_IPC_PATH)
|
|
||||||
viper.BindEnv("server.httpPath", SERVER_HTTP_PATH)
|
|
||||||
viper.BindEnv("ethereum.httpPath", shared.ETH_HTTP_PATH)
|
viper.BindEnv("ethereum.httpPath", shared.ETH_HTTP_PATH)
|
||||||
viper.BindEnv("ethereum.defaultSender", ETH_DEFAULT_SENDER_ADDR)
|
viper.BindEnv("ethereum.defaultSender", ETH_DEFAULT_SENDER_ADDR)
|
||||||
viper.BindEnv("ethereum.rpcGasCap", ETH_RPC_GAS_CAP)
|
viper.BindEnv("ethereum.rpcGasCap", ETH_RPC_GAS_CAP)
|
||||||
|
viper.BindEnv("ethereum.chainConfig", ETH_CHAIN_CONFIG)
|
||||||
viper.BindEnv("ethereum.supportsStateDiff", ETH_SUPPORTS_STATEDIFF)
|
viper.BindEnv("ethereum.supportsStateDiff", ETH_SUPPORTS_STATEDIFF)
|
||||||
|
|
||||||
c.DBConfig.Init()
|
c.DBConfig.Init()
|
||||||
|
|
||||||
ethHTTP := viper.GetString("ethereum.httpPath")
|
ethHTTP := viper.GetString("ethereum.httpPath")
|
||||||
nodeInfo, cli, err := shared.GetEthNodeAndClient(fmt.Sprintf("http://%s", ethHTTP))
|
ethHTTPEndpoint := fmt.Sprintf("http://%s", ethHTTP)
|
||||||
|
nodeInfo, cli, err := shared.GetEthNodeAndClient(ethHTTPEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.Client = cli
|
c.Client = cli
|
||||||
c.SupportStateDiff = viper.GetBool("ethereum.supportsStateDiff")
|
c.SupportStateDiff = viper.GetBool("ethereum.supportsStateDiff")
|
||||||
|
c.EthHttpEndpoint = ethHTTPEndpoint
|
||||||
|
|
||||||
wsPath := viper.GetString("server.wsPath")
|
// websocket server
|
||||||
if wsPath == "" {
|
wsEnabled := viper.GetBool("eth.server.ws")
|
||||||
wsPath = "127.0.0.1:8080"
|
if wsEnabled {
|
||||||
}
|
wsPath := viper.GetString("eth.server.wsPath")
|
||||||
c.WSEndpoint = wsPath
|
if wsPath == "" {
|
||||||
ipcPath := viper.GetString("server.ipcPath")
|
wsPath = "127.0.0.1:8080"
|
||||||
if ipcPath == "" {
|
|
||||||
home, err := os.UserHomeDir()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
ipcPath = filepath.Join(home, ".vulcanize/vulcanize.ipc")
|
c.WSEndpoint = wsPath
|
||||||
}
|
}
|
||||||
c.IPCEndpoint = ipcPath
|
c.WSEnabled = wsEnabled
|
||||||
httpPath := viper.GetString("server.httpPath")
|
|
||||||
if httpPath == "" {
|
// ipc server
|
||||||
httpPath = "127.0.0.1:8081"
|
ipcEnabled := viper.GetBool("eth.server.ipc")
|
||||||
|
if ipcEnabled {
|
||||||
|
ipcPath := viper.GetString("eth.server.ipcPath")
|
||||||
|
if ipcPath == "" {
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ipcPath = filepath.Join(home, ".vulcanize/vulcanize.ipc")
|
||||||
|
}
|
||||||
|
c.IPCEndpoint = ipcPath
|
||||||
}
|
}
|
||||||
c.HTTPEndpoint = httpPath
|
c.IPCEnabled = ipcEnabled
|
||||||
|
|
||||||
|
// http server
|
||||||
|
httpEnabled := viper.GetBool("eth.server.http")
|
||||||
|
if httpEnabled {
|
||||||
|
httpPath := viper.GetString("eth.server.httpPath")
|
||||||
|
if httpPath == "" {
|
||||||
|
httpPath = "127.0.0.1:8081"
|
||||||
|
}
|
||||||
|
c.HTTPEndpoint = httpPath
|
||||||
|
}
|
||||||
|
c.HTTPEnabled = httpEnabled
|
||||||
|
|
||||||
|
// eth graphql endpoint
|
||||||
|
ethGraphqlEnabled := viper.GetBool("eth.server.graphql")
|
||||||
|
if ethGraphqlEnabled {
|
||||||
|
ethGraphqlPath := viper.GetString("eth.server.graphqlPath")
|
||||||
|
if ethGraphqlPath == "" {
|
||||||
|
ethGraphqlPath = "127.0.0.1:8082"
|
||||||
|
}
|
||||||
|
c.EthGraphqlEndpoint = ethGraphqlPath
|
||||||
|
}
|
||||||
|
c.EthGraphqlEnabled = ethGraphqlEnabled
|
||||||
|
|
||||||
|
// ipld graphql endpoint
|
||||||
|
ipldGraphqlEnabled := viper.GetBool("ipld.server.graphql")
|
||||||
|
if ipldGraphqlEnabled {
|
||||||
|
ipldGraphqlPath := viper.GetString("ipld.server.graphqlPath")
|
||||||
|
if ipldGraphqlPath == "" {
|
||||||
|
ipldGraphqlPath = "127.0.0.1:8083"
|
||||||
|
}
|
||||||
|
c.IpldGraphqlEndpoint = ipldGraphqlPath
|
||||||
|
|
||||||
|
ipldPostgraphilePath := viper.GetString("ipld.postgraphilePath")
|
||||||
|
if ipldPostgraphilePath == "" {
|
||||||
|
return nil, errors.New("ipld-postgraphile-path parameter is empty")
|
||||||
|
}
|
||||||
|
c.IpldPostgraphileEndpoint = ipldPostgraphilePath
|
||||||
|
|
||||||
|
tracingHttpEndpoint := viper.GetString("tracing.httpPath")
|
||||||
|
tracingPostgraphilePath := viper.GetString("tracing.postgraphilePath")
|
||||||
|
|
||||||
|
// these two parameters either can be both empty or both set
|
||||||
|
if (tracingHttpEndpoint == "" && tracingPostgraphilePath != "") || (tracingHttpEndpoint != "" && tracingPostgraphilePath == "") {
|
||||||
|
return nil, errors.New("tracing.httpPath and tracing.postgraphilePath parameters either can be both empty or both set")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.TracingHttpEndpoint = tracingHttpEndpoint
|
||||||
|
c.TracingPostgraphileEndpoint = tracingPostgraphilePath
|
||||||
|
}
|
||||||
|
c.IpldGraphqlEnabled = ipldGraphqlEnabled
|
||||||
|
|
||||||
overrideDBConnConfig(&c.DBConfig)
|
overrideDBConnConfig(&c.DBConfig)
|
||||||
serveDB := utils.LoadPostgres(c.DBConfig, nodeInfo, false)
|
serveDB := utils.LoadPostgres(c.DBConfig, nodeInfo, false)
|
||||||
prom.RegisterDBCollector(c.DBConfig.Name, serveDB.DB)
|
prom.RegisterDBCollector(c.DBConfig.Name, serveDB.DB)
|
||||||
@@ -123,7 +199,12 @@ func NewConfig() (*Config, error) {
|
|||||||
c.RPCGasCap = rpcGasCap
|
c.RPCGasCap = rpcGasCap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.ChainConfig, err = eth.ChainConfig(nodeInfo.ChainID)
|
chainConfigPath := viper.GetString("ethereum.chainConfig")
|
||||||
|
if chainConfigPath != "" {
|
||||||
|
c.ChainConfig, err = eth.LoadConfig(chainConfigPath)
|
||||||
|
} else {
|
||||||
|
c.ChainConfig, err = eth.ChainConfig(nodeInfo.ChainID)
|
||||||
|
}
|
||||||
return c, err
|
return c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-16
@@ -18,8 +18,11 @@ package serve
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/vulcanize/ipld-eth-server/pkg/net"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@@ -115,7 +118,7 @@ func (sap *Service) Protocols() []p2p.Protocol {
|
|||||||
|
|
||||||
// APIs returns the RPC descriptors the watcher service offers
|
// APIs returns the RPC descriptors the watcher service offers
|
||||||
func (sap *Service) APIs() []rpc.API {
|
func (sap *Service) APIs() []rpc.API {
|
||||||
infoAPI := NewInfoAPI()
|
networkID, _ := strconv.ParseUint(sap.db.Node.NetworkID, 10, 64)
|
||||||
apis := []rpc.API{
|
apis := []rpc.API{
|
||||||
{
|
{
|
||||||
Namespace: APIName,
|
Namespace: APIName,
|
||||||
@@ -124,21 +127,9 @@ func (sap *Service) APIs() []rpc.API {
|
|||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: "rpc",
|
Namespace: net.APIName,
|
||||||
Version: APIVersion,
|
Version: net.APIVersion,
|
||||||
Service: infoAPI,
|
Service: net.NewPublicNetAPI(networkID, sap.client),
|
||||||
Public: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Namespace: "net",
|
|
||||||
Version: APIVersion,
|
|
||||||
Service: infoAPI,
|
|
||||||
Public: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Namespace: "admin",
|
|
||||||
Version: APIVersion,
|
|
||||||
Service: infoAPI,
|
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
set -e
|
||||||
|
set -o xtrace
|
||||||
|
|
||||||
|
# Clear up existing docker images and volume.
|
||||||
|
docker-compose down --remove-orphans --volumes
|
||||||
|
|
||||||
|
# Build and start the containers.
|
||||||
|
# Note: Build only if `ipld-eth-server` code is modified. Otherwise comment this line.
|
||||||
|
docker build -t ipld-eth-server_eth-server:latest .
|
||||||
|
docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server
|
||||||
|
|
||||||
|
export PGPASSWORD=password
|
||||||
|
export DATABASE_USER=vdbm
|
||||||
|
export DATABASE_PORT=8077
|
||||||
|
export DATABASE_PASSWORD=password
|
||||||
|
export DATABASE_HOSTNAME=127.0.0.1
|
||||||
|
|
||||||
|
# Wait for containers to be up and execute the integration test.
|
||||||
|
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8081)" != "200" ]; do echo "waiting for ipld-eth-server..." && sleep 5; done && \
|
||||||
|
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8545)" != "200" ]; do echo "waiting for geth-statediff..." && sleep 5; done && \
|
||||||
|
make integrationtest
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db
|
||||||
|
PGPASSWORD=password DATABASE_USER=vdbm DATABASE_PORT=8077 DATABASE_PASSWORD=password DATABASE_HOSTNAME=127.0.0.1 make test
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
Spin up services:
|
||||||
|
```
|
||||||
|
docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server
|
||||||
|
```
|
||||||
|
|
||||||
|
Running unit tests:
|
||||||
|
```bash
|
||||||
|
make test_local
|
||||||
|
```
|
||||||
|
|
||||||
|
Running integration test:
|
||||||
|
```bash
|
||||||
|
make integrationtest_local
|
||||||
|
```
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
artifacts
|
||||||
|
cache
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
|
||||||
|
#Hardhat files
|
||||||
|
cache
|
||||||
|
artifacts
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
FROM node:14
|
||||||
|
|
||||||
|
ARG ETH_ADDR
|
||||||
|
ENV ETH_ADDR $ETH_ADDR
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run compile && ls -lah
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENTRYPOINT ["npm", "start"]
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
pragma solidity ^0.8.0;
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||||
|
contract GLDToken is ERC20 {
|
||||||
|
constructor() ERC20("Gold", "GLD") {
|
||||||
|
_mint(msg.sender, 1000000000000000000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
require("@nomiclabs/hardhat-waffle");
|
||||||
|
|
||||||
|
// This is a sample Hardhat task. To learn how to create your own go to
|
||||||
|
// https://hardhat.org/guides/create-task.html
|
||||||
|
task("accounts", "Prints the list of accounts", async () => {
|
||||||
|
const accounts = await ethers.getSigners();
|
||||||
|
|
||||||
|
for (const account of accounts) {
|
||||||
|
console.log(account.address);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// You need to export an object to set up your config
|
||||||
|
// Go to https://hardhat.org/config/ to learn more
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type import('hardhat/config').HardhatUserConfig
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
solidity: "0.8.0",
|
||||||
|
networks: {
|
||||||
|
local: {
|
||||||
|
url: 'http://127.0.0.1:8545',
|
||||||
|
chainId: 4
|
||||||
|
},
|
||||||
|
docker: {
|
||||||
|
url: process.env.ETH_ADDR,
|
||||||
|
chainId: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Generated
+27700
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "contract",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"compile": "npx hardhat compile",
|
||||||
|
"start": "HARDHAT_NETWORK=docker node src/index.js",
|
||||||
|
"start:local": "ETH_ADDR=http://127.0.0.1:8545 npm run start",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@openzeppelin/contracts": "^4.0.0",
|
||||||
|
"fastify": "^3.14.2",
|
||||||
|
"hardhat": "^2.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||||
|
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||||
|
"chai": "^4.3.4",
|
||||||
|
"ethereum-waffle": "^3.3.0",
|
||||||
|
"ethers": "^5.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
const hre = require("hardhat");
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// await hre.run('compile');
|
||||||
|
// We get the contract to deploy
|
||||||
|
const GLDToken = await hre.ethers.getContractFactory("GLDToken");
|
||||||
|
const token = await GLDToken.deploy();
|
||||||
|
await token.deployed();
|
||||||
|
console.log("GLDToken deployed to:", token.address, token.deployTransaction.hash);
|
||||||
|
}
|
||||||
|
// We recommend this pattern to be able to use async/await everywhere
|
||||||
|
// and properly handle errors.
|
||||||
|
main()
|
||||||
|
.then(() => process.exit(0))
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// We require the Hardhat Runtime Environment explicitly here. This is optional
|
||||||
|
// but useful for running the script in a standalone fashion through `node <script>`.
|
||||||
|
//
|
||||||
|
// When running the script with `hardhat run <script>` you'll find the Hardhat
|
||||||
|
// Runtime Environment's members available in the global scope.
|
||||||
|
const hre = require("hardhat");
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// Hardhat always runs the compile task when running scripts with its command
|
||||||
|
// line interface.
|
||||||
|
//
|
||||||
|
// If this script is run directly using `node` you may want to call compile
|
||||||
|
// manually to make sure everything is compiled
|
||||||
|
// await hre.run('compile');
|
||||||
|
|
||||||
|
// We get the contract to deploy
|
||||||
|
const Greeter = await hre.ethers.getContractFactory("Greeter");
|
||||||
|
const greeter = await Greeter.deploy("Hello, Hardhat!");
|
||||||
|
|
||||||
|
await greeter.deployed();
|
||||||
|
|
||||||
|
console.log("Greeter deployed to:", greeter.address, "; tx hash: ", greeter.deployTransaction.hash);
|
||||||
|
|
||||||
|
const result = await greeter.setGreeting("Hello 123!");
|
||||||
|
|
||||||
|
console.log("Greeter updated", "; tx hash: ", result.hash, "; block hash: ", result.blockHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We recommend this pattern to be able to use async/await everywhere
|
||||||
|
// and properly handle errors.
|
||||||
|
main()
|
||||||
|
.then(() => process.exit(0))
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
const fastify = require('fastify')({ logger: true });
|
||||||
|
const hre = require("hardhat");
|
||||||
|
|
||||||
|
// readiness check
|
||||||
|
fastify.get('/v1/healthz', async (req, reply) => {
|
||||||
|
reply
|
||||||
|
.code(200)
|
||||||
|
.header('Content-Type', 'application/json; charset=utf-8')
|
||||||
|
.send({ success: true })
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.get('/v1/deployContract', async (req, reply) => {
|
||||||
|
const GLDToken = await hre.ethers.getContractFactory("GLDToken");
|
||||||
|
const token = await GLDToken.deploy();
|
||||||
|
await token.deployed();
|
||||||
|
|
||||||
|
return {
|
||||||
|
address: token.address,
|
||||||
|
txHash: token.deployTransaction.hash,
|
||||||
|
blockNumber: token.deployTransaction.blockNumber,
|
||||||
|
blockHash: token.deployTransaction.blockHash,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.get('/v1/sendEth', async (req, reply) => {
|
||||||
|
const to = req.query.to;
|
||||||
|
const value = req.query.value;
|
||||||
|
|
||||||
|
const [owner] = await hre.ethers.getSigners();
|
||||||
|
const tx = await owner.sendTransaction({
|
||||||
|
to,
|
||||||
|
value: hre.ethers.utils.parseEther(value)
|
||||||
|
});
|
||||||
|
await tx.wait(1)
|
||||||
|
|
||||||
|
// console.log(tx);
|
||||||
|
// const coinbaseBalance = await hre.ethers.provider.getBalance(owner.address);
|
||||||
|
// const receiverBalance = await hre.ethers.provider.getBalance(to);
|
||||||
|
// console.log(coinbaseBalance.toString(), receiverBalance.toString());
|
||||||
|
|
||||||
|
return {
|
||||||
|
from: tx.from,
|
||||||
|
to: tx.to,
|
||||||
|
//value: tx.value.toString(),
|
||||||
|
txHash: tx.hash,
|
||||||
|
blockNumber: tx.blockNumber,
|
||||||
|
blockHash: tx.blockHash,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
await fastify.listen(3000, '0.0.0.0');
|
||||||
|
} catch (err) {
|
||||||
|
fastify.log.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const { expect } = require("chai");
|
||||||
|
|
||||||
|
describe("Greeter", function() {
|
||||||
|
it("Should return the new greeting once it's changed", async function() {
|
||||||
|
const Greeter = await ethers.getContractFactory("Greeter");
|
||||||
|
const greeter = await Greeter.deploy("Hello, world!");
|
||||||
|
|
||||||
|
await greeter.deployed();
|
||||||
|
expect(await greeter.greet()).to.equal("Hello, world!");
|
||||||
|
|
||||||
|
await greeter.setGreeting("Hola, mundo!");
|
||||||
|
expect(await greeter.greet()).to.equal("Hola, mundo!");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContractDeployed struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
TransactionHash string `json:"txHash"`
|
||||||
|
BlockNumber int `json:"blockNumber"`
|
||||||
|
BlockHash string `json:"blockHash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tx struct {
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
Value *big.Int `json:"value"`
|
||||||
|
TransactionHash string `json:"txHash"`
|
||||||
|
BlockNumber int `json:"blockNumber"`
|
||||||
|
BlockHash string `json:"blockHash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const srvUrl = "http://localhost:3000"
|
||||||
|
|
||||||
|
func DeployContract() (*ContractDeployed, error) {
|
||||||
|
res, err := http.Get(fmt.Sprintf("%s/v1/deployContract", srvUrl))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var contract ContractDeployed
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(res.Body)
|
||||||
|
err = decoder.Decode(&contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &contract, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendEth(to string, value string) (*Tx, error) {
|
||||||
|
res, err := http.Get(fmt.Sprintf("%s/v1/sendEth?to=%s&value=%s", srvUrl, to, value))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var tx Tx
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(res.Body)
|
||||||
|
err = decoder.Decode(&tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tx, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package integration_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIntegration(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "integration test suite")
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func() {
|
||||||
|
logrus.SetOutput(ioutil.Discard)
|
||||||
|
})
|
||||||
@@ -0,0 +1,486 @@
|
|||||||
|
package integration_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
integration "github.com/vulcanize/ipld-eth-server/test"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
const nonExistingBlockHash = "0x111111111111111111111111111111111111111111111111111111111111111"
|
||||||
|
const nonExistingAddress = "0x1111111111111111111111111111111111111111"
|
||||||
|
|
||||||
|
var (
|
||||||
|
randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f")
|
||||||
|
randomHash = crypto.Keccak256Hash(randomAddr.Bytes())
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Integration test", func() {
|
||||||
|
gethHttpPath := "http://127.0.0.1:8545"
|
||||||
|
gethClient, err := ethclient.Dial(gethHttpPath)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldEthHttpPath := "http://127.0.0.1:8081"
|
||||||
|
ipldClient, err := ethclient.Dial(ipldEthHttpPath)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
var contract *integration.ContractDeployed
|
||||||
|
var erc20TotalSupply *big.Int
|
||||||
|
var tx *integration.Tx
|
||||||
|
var bigIntResult bool
|
||||||
|
var contractErr error
|
||||||
|
var txErr error
|
||||||
|
sleepInterval := 2 * time.Second
|
||||||
|
|
||||||
|
Describe("get Block", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
contract, contractErr = integration.DeployContract()
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("get not existing block by number", func() {
|
||||||
|
Expect(contractErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
blockNum := contract.BlockNumber + 100
|
||||||
|
|
||||||
|
gethBlock, err := gethClient.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
|
||||||
|
Expect(err).To(MatchError(ethereum.NotFound))
|
||||||
|
Expect(gethBlock).To(BeZero())
|
||||||
|
|
||||||
|
ipldBlock, err := ipldClient.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
|
||||||
|
Expect(err).To(MatchError(ethereum.NotFound))
|
||||||
|
Expect(ipldBlock).To(BeZero())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("get not existing block by hash", func() {
|
||||||
|
gethBlock, err := gethClient.BlockByHash(ctx, common.HexToHash(nonExistingBlockHash))
|
||||||
|
Expect(err).To(MatchError(ethereum.NotFound))
|
||||||
|
Expect(gethBlock).To(BeZero())
|
||||||
|
|
||||||
|
ipldBlock, err := ipldClient.BlockByHash(ctx, common.HexToHash(nonExistingBlockHash))
|
||||||
|
Expect(err).To(MatchError(ethereum.NotFound))
|
||||||
|
Expect(ipldBlock).To(BeZero())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("get block by number", func() {
|
||||||
|
Expect(contractErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
blockNum := contract.BlockNumber
|
||||||
|
|
||||||
|
gethBlock, err := gethClient.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldBlock, err := ipldClient.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// check headers are equals
|
||||||
|
Expect(gethBlock.Header()).To(Equal(ipldBlock.Header()))
|
||||||
|
|
||||||
|
gethTxs := gethBlock.Transactions()
|
||||||
|
ipldTxs := ipldBlock.Transactions()
|
||||||
|
|
||||||
|
Expect(gethTxs.Len()).To(Equal(ipldTxs.Len()))
|
||||||
|
Expect(types.TxDifference(gethTxs, ipldTxs).Len()).To(Equal(0))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("get block by hash", func() {
|
||||||
|
gethBlock, err := gethClient.BlockByHash(ctx, common.HexToHash(contract.BlockHash))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldBlock, err := ipldClient.BlockByHash(ctx, common.HexToHash(contract.BlockHash))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// check headers are equals
|
||||||
|
compareBlocks(gethBlock, ipldBlock)
|
||||||
|
|
||||||
|
gethTxs := gethBlock.Transactions()
|
||||||
|
ipldTxs := ipldBlock.Transactions()
|
||||||
|
|
||||||
|
Expect(gethTxs.Len()).To(Equal(ipldTxs.Len()))
|
||||||
|
Expect(types.TxDifference(gethTxs, ipldTxs).Len()).To(Equal(0))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Transaction", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
contract, contractErr = integration.DeployContract()
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Get tx by hash", func() {
|
||||||
|
Expect(contractErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethTx, _, err := gethClient.TransactionByHash(ctx, common.HexToHash(contract.TransactionHash))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldTx, _, err := ipldClient.TransactionByHash(ctx, common.HexToHash(contract.TransactionHash))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
compareTxs(gethTx, ipldTx)
|
||||||
|
|
||||||
|
Expect(gethTx.Hash()).To(Equal(ipldTx.Hash()))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Get tx by block hash and index", func() {
|
||||||
|
gethTx, err := gethClient.TransactionInBlock(ctx, common.HexToHash(contract.BlockHash), 0)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldTx, err := ipldClient.TransactionInBlock(ctx, common.HexToHash(contract.BlockHash), 0)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
compareTxs(gethTx, ipldTx)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Receipt", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
contract, contractErr = integration.DeployContract()
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Get tx receipt", func() {
|
||||||
|
Expect(contractErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethReceipt, err := gethClient.TransactionReceipt(ctx, common.HexToHash(contract.TransactionHash))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldReceipt, err := ipldClient.TransactionReceipt(ctx, common.HexToHash(contract.TransactionHash))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethReceipt).To(Equal(ipldReceipt))
|
||||||
|
|
||||||
|
rlpGeth, err := rlp.EncodeToBytes(gethReceipt)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
rlpIpld, err := rlp.EncodeToBytes(ipldReceipt)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(rlpGeth).To(Equal(rlpIpld))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("FilterLogs", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
contract, contractErr = integration.DeployContract()
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("with blockhash", func() {
|
||||||
|
Expect(contractErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
blockHash := common.HexToHash(contract.BlockHash)
|
||||||
|
filterQuery := ethereum.FilterQuery{
|
||||||
|
//Addresses: addresses,
|
||||||
|
BlockHash: &blockHash,
|
||||||
|
Topics: [][]common.Hash{},
|
||||||
|
}
|
||||||
|
|
||||||
|
gethLogs, err := gethClient.FilterLogs(ctx, filterQuery)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldLogs, err := ipldClient.FilterLogs(ctx, filterQuery)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// not empty list
|
||||||
|
Expect(gethLogs).ToNot(BeEmpty())
|
||||||
|
|
||||||
|
Expect(len(gethLogs)).To(Equal(len(ipldLogs)))
|
||||||
|
Expect(gethLogs).To(Equal(ipldLogs))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("CodeAt", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
contract, contractErr = integration.DeployContract()
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets code at non-existing address without block number", func() {
|
||||||
|
Expect(contractErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethCode, err := gethClient.CodeAt(ctx, common.HexToAddress(nonExistingAddress), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldCode, err := ipldClient.CodeAt(ctx, common.HexToAddress(nonExistingAddress), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethCode).To(BeEmpty())
|
||||||
|
Expect(gethCode).To(Equal(ipldCode))
|
||||||
|
})
|
||||||
|
It("gets code of deployed contract without block number", func() {
|
||||||
|
gethCode, err := gethClient.CodeAt(ctx, common.HexToAddress(contract.Address), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldCode, err := ipldClient.CodeAt(ctx, common.HexToAddress(contract.Address), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(gethCode).To(Equal(ipldCode))
|
||||||
|
})
|
||||||
|
It("gets code of deployed contract with block number", func() {
|
||||||
|
gethCode, err := gethClient.CodeAt(ctx, common.HexToAddress(contract.Address), big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldCode, err := ipldClient.CodeAt(ctx, common.HexToAddress(contract.Address), big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(gethCode).To(Equal(ipldCode))
|
||||||
|
})
|
||||||
|
It("gets code of contract that doesn't exist at this height", func() {
|
||||||
|
gethCode, err := gethClient.CodeAt(ctx, common.HexToAddress(contract.Address), big.NewInt(int64(contract.BlockNumber-1)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldCode, err := ipldClient.CodeAt(ctx, common.HexToAddress(contract.Address), big.NewInt(int64(contract.BlockNumber-1)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethCode).To(BeEmpty())
|
||||||
|
Expect(gethCode).To(Equal(ipldCode))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Get balance", func() {
|
||||||
|
address := "0x1111111111111111111111111111111111111112"
|
||||||
|
BeforeEach(func() {
|
||||||
|
tx, txErr = integration.SendEth(address, "0.01")
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets balance for an account with eth without block number", func() {
|
||||||
|
Expect(txErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethBalance, err := gethClient.BalanceAt(ctx, common.HexToAddress(address), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldBalance, err := ipldClient.BalanceAt(ctx, common.HexToAddress(address), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethBalance).To(Equal(ipldBalance))
|
||||||
|
})
|
||||||
|
It("gets balance for an account with eth with block number", func() {
|
||||||
|
Expect(txErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethBalance, err := gethClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldBalance, err := ipldClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethBalance).To(Equal(ipldBalance))
|
||||||
|
})
|
||||||
|
It("gets historical balance for an account with eth with block number", func() {
|
||||||
|
Expect(txErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethBalance, err := gethClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber-1)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldBalance, err := ipldClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber-1)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethBalance).To(Equal(ipldBalance))
|
||||||
|
})
|
||||||
|
It("gets balance for a non-existing account without block number", func() {
|
||||||
|
Expect(txErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethBalance, err := gethClient.BalanceAt(ctx, common.HexToAddress(nonExistingAddress), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldBalance, err := ipldClient.BalanceAt(ctx, common.HexToAddress(nonExistingAddress), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethBalance).To(Equal(ipldBalance))
|
||||||
|
})
|
||||||
|
It("gets balance for an non-existing block number", func() {
|
||||||
|
Expect(txErr).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethBalance, err := gethClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber+3)))
|
||||||
|
Expect(err).To(MatchError("header not found"))
|
||||||
|
|
||||||
|
ipldBalance, err := ipldClient.BalanceAt(ctx, common.HexToAddress(nonExistingAddress), big.NewInt(int64(tx.BlockNumber+3)))
|
||||||
|
Expect(err).To(MatchError("header not found"))
|
||||||
|
|
||||||
|
Expect(gethBalance).To(Equal(ipldBalance))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Get Storage", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
contract, contractErr = integration.DeployContract()
|
||||||
|
erc20TotalSupply, bigIntResult = new(big.Int).SetString("1000000000000000000000", 10)
|
||||||
|
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets ERC20 total supply (without block number)", func() {
|
||||||
|
Expect(contractErr).ToNot(HaveOccurred())
|
||||||
|
Expect(bigIntResult).To(Equal(true))
|
||||||
|
|
||||||
|
totalSupplyIndex := "0x2"
|
||||||
|
|
||||||
|
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethTotalSupply := new(big.Int).SetBytes(gethStorage)
|
||||||
|
Expect(gethTotalSupply).To(Equal(erc20TotalSupply))
|
||||||
|
|
||||||
|
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldTotalSupply := new(big.Int).SetBytes(ipldStorage)
|
||||||
|
Expect(ipldTotalSupply).To(Equal(erc20TotalSupply))
|
||||||
|
|
||||||
|
Expect(gethStorage).To(Equal(ipldStorage))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("gets ERC20 total supply (with block number)", func() {
|
||||||
|
totalSupplyIndex := "0x2"
|
||||||
|
|
||||||
|
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethTotalSupply := new(big.Int).SetBytes(gethStorage)
|
||||||
|
Expect(gethTotalSupply).To(Equal(erc20TotalSupply))
|
||||||
|
|
||||||
|
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(gethStorage).To(Equal(ipldStorage))
|
||||||
|
})
|
||||||
|
It("gets storage for non-existing account", func() {
|
||||||
|
totalSupplyIndex := "0x2"
|
||||||
|
|
||||||
|
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(nonExistingAddress), common.HexToHash(totalSupplyIndex), big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(nonExistingAddress), common.HexToHash(totalSupplyIndex), big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(gethStorage).To(Equal(ipldStorage))
|
||||||
|
})
|
||||||
|
It("gets storage for non-existing contract slot", func() {
|
||||||
|
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), randomHash, big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), randomHash, big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(gethStorage).To(Equal(ipldStorage))
|
||||||
|
})
|
||||||
|
It("gets storage for non-existing contract", func() {
|
||||||
|
totalSupplyIndex := "0x2"
|
||||||
|
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(0))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(0))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(gethStorage).To(Equal(ipldStorage))
|
||||||
|
})
|
||||||
|
It("gets storage for non-existing block number", func() {
|
||||||
|
blockNum := contract.BlockNumber + 100
|
||||||
|
totalSupplyIndex := "0x2"
|
||||||
|
|
||||||
|
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(int64(blockNum)))
|
||||||
|
Expect(err).To(MatchError("header not found"))
|
||||||
|
|
||||||
|
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(int64(blockNum)))
|
||||||
|
Expect(err).To(MatchError("header not found"))
|
||||||
|
Expect(gethStorage).To(Equal(ipldStorage))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("eth call", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
contract, contractErr = integration.DeployContract()
|
||||||
|
erc20TotalSupply, bigIntResult = new(big.Int).SetString("1000000000000000000000", 10)
|
||||||
|
|
||||||
|
time.Sleep(sleepInterval)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("calls totalSupply() without block number", func() {
|
||||||
|
Expect(contractErr).ToNot(HaveOccurred())
|
||||||
|
Expect(bigIntResult).To(Equal(true))
|
||||||
|
|
||||||
|
contractAddress := common.HexToAddress(contract.Address)
|
||||||
|
|
||||||
|
msg := ethereum.CallMsg{
|
||||||
|
To: &contractAddress,
|
||||||
|
Data: common.Hex2Bytes("18160ddd"), // totalSupply()
|
||||||
|
}
|
||||||
|
gethResult, err := gethClient.CallContract(ctx, msg, nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethTotalSupply := new(big.Int).SetBytes(gethResult)
|
||||||
|
Expect(gethTotalSupply).To(Equal(erc20TotalSupply))
|
||||||
|
|
||||||
|
ipldResult, err := ipldClient.CallContract(ctx, msg, nil)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethResult).To(Equal(ipldResult))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("calls totalSupply() with block number", func() {
|
||||||
|
contractAddress := common.HexToAddress(contract.Address)
|
||||||
|
|
||||||
|
msg := ethereum.CallMsg{
|
||||||
|
To: &contractAddress,
|
||||||
|
Data: common.Hex2Bytes("18160ddd"), // totalSupply()
|
||||||
|
}
|
||||||
|
gethResult, err := gethClient.CallContract(ctx, msg, big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
gethTotalSupply := new(big.Int).SetBytes(gethResult)
|
||||||
|
Expect(gethTotalSupply).To(Equal(erc20TotalSupply))
|
||||||
|
|
||||||
|
ipldResult, err := ipldClient.CallContract(ctx, msg, big.NewInt(int64(contract.BlockNumber)))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethResult).To(Equal(ipldResult))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Chain ID", func() {
|
||||||
|
It("Check chain id", func() {
|
||||||
|
gethChainId, err := gethClient.ChainID(ctx)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldChainId, err := ipldClient.ChainID(ctx)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethChainId).To(Equal(ipldChainId))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
func compareBlocks(block1 *types.Block, block2 *types.Block) {
|
||||||
|
Expect(block1.Header()).To(Equal(block2.Header()))
|
||||||
|
Expect(block1.Uncles()).To(Equal(block2.Uncles()))
|
||||||
|
|
||||||
|
txs1 := block1.Transactions()
|
||||||
|
txs2 := block2.Transactions()
|
||||||
|
|
||||||
|
Expect(len(txs1)).To(Equal(len(txs2)))
|
||||||
|
for i, tx := range txs1 {
|
||||||
|
compareTxs(tx, txs2[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareTxs(tx1 *types.Transaction, tx2 *types.Transaction) {
|
||||||
|
Expect(tx1.Data()).To(Equal(tx2.Data()))
|
||||||
|
Expect(tx1.Hash()).To(Equal(tx2.Hash()))
|
||||||
|
Expect(tx1.Size()).To(Equal(tx2.Size()))
|
||||||
|
|
||||||
|
signer := types.NewEIP155Signer(big.NewInt(4))
|
||||||
|
|
||||||
|
gethSender, err := types.Sender(signer, tx1)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
ipldSender, err := types.Sender(signer, tx2)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
Expect(gethSender).To(Equal(ipldSender))
|
||||||
|
}
|
||||||
+1
-1
@@ -21,7 +21,7 @@ import "fmt"
|
|||||||
const (
|
const (
|
||||||
Major = 0 // Major version component of the current release
|
Major = 0 // Major version component of the current release
|
||||||
Minor = 3 // Minor version component of the current release
|
Minor = 3 // Minor version component of the current release
|
||||||
Patch = 1 // Patch version component of the current release
|
Patch = 6 // Patch version component of the current release
|
||||||
Meta = "alpha" // Version metadata to append to the version string
|
Meta = "alpha" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user