integration test #53
27
.github/workflows/on-pr.yaml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
- name: Run docker build
|
||||
run: make docker-build
|
||||
test:
|
||||
name: Run integration tests
|
||||
name: Run unit tests
|
||||
env:
|
||||
GOPATH: /tmp/go
|
||||
strategy:
|
||||
@ -33,3 +33,28 @@ jobs:
|
||||
run: |
|
||||
sleep 10
|
||||
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
|
||||
|
13
Dockerfile
@ -6,8 +6,17 @@ RUN apk add busybox-extras
|
||||
|
||||
# Build 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
|
||||
WORKDIR /
|
||||
|
22
Makefile
@ -61,39 +61,25 @@ test: | $(GINKGO) $(GOOSE)
|
||||
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 --skipPackage=integration_tests,integration
|
||||
$(GINKGO) -r --skipPackage=test
|
||||
|
||||
.PHONY: integrationtest
|
||||
integrationtest: | $(GINKGO) $(GOOSE)
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
export PGPASSWORD=$(DATABASE_PASSWORD)
|
||||
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/
|
||||
$(GINKGO) -r test/ -v
|
||||
|
||||
.PHONY: test_local
|
||||
test_local: | $(GINKGO) $(GOOSE)
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
dropdb -h $(HOST_NAME) -p $(PORT) -U $(USER) --if-exists $(TEST_DB)
|
||||
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
|
||||
./scripts/run_unit_test.sh
|
||||
|
||||
.PHONY: integrationtest_local
|
||||
integrationtest_local: | $(GINKGO) $(GOOSE)
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
dropdb -h $(HOST_NAME) -p $(PORT) -U $(USER) --if-exists $(TEST_DB)
|
||||
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/
|
||||
./scripts/run_intregration_test.sh
|
||||
|
||||
build:
|
||||
go fmt ./...
|
||||
|
@ -135,9 +135,9 @@ TODO: Add the rest of the standard endpoints and unique endpoints (e.g. getSlice
|
||||
| `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_HTTP_PATH` | | If `eth-server-http` set to `true`, endpoint url for Eth HTTP JSON-RPC server (host:port) |
|
||||
| `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_WS_PATH` | | If `eth-server-ws` set to `true`, endpoint url for Eth WS JSON-RPC server (host:port) |
|
||||
| `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 |
|
||||
|
16
chain.json
Normal file
@ -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
|
||||
}
|
||||
}
|
14
docker-compose.test.yml
Normal file
@ -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"
|
@ -20,7 +20,7 @@ services:
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
- db
|
||||
image: vulcanize/statediff-migrations:v0.3.0
|
||||
image: vulcanize/statediff-migrations:v0.4.0
|
||||
environment:
|
||||
|
||||
DATABASE_USER: vdbm
|
||||
DATABASE_NAME: vulcanize_public
|
||||
@ -41,6 +41,7 @@ services:
|
||||
- "127.0.0.1:8077:5432"
|
||||
|
||||
eth-server:
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
build:
|
||||
@ -49,16 +50,22 @@ services:
|
||||
- alpine:latest
|
||||
- golang:1.13-alpine
|
||||
environment:
|
||||
IPLD_SERVER_GRAPHQL: "true"
|
||||
IPLD_POSTGRAPHILEPATH: http://graphql:5000
|
||||
ETH_SERVER_HTTPPATH: 0.0.0.0:8081
|
||||
VDB_COMMAND: "serve"
|
||||
ETH_CHAIN_CONFIG: "/tmp/chain.json"
|
||||
DATABASE_NAME: "vulcanize_public"
|
||||
DATABASE_HOSTNAME: "db"
|
||||
DATABASE_PORT: 5432
|
||||
DATABASE_USER: "vdbm"
|
||||
DATABASE_PASSWORD: "password"
|
||||
SERVER_WS_PATH: "0.0.0.0:8081"
|
||||
SERVER_HTTP_PATH: "0.0.0.0:8082"
|
||||
ETH_CHAIN_ID: 4
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./chain.json
|
||||
target: /tmp/chain.json
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
- "127.0.0.1:8081:8081"
|
||||
|
||||
graphql:
|
||||
|
@ -18,9 +18,11 @@ package eth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
"time"
|
||||
@ -38,7 +40,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/statediff"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
||||
)
|
||||
|
||||
@ -167,6 +168,21 @@ func (pea *PublicEthAPI) GetBlockByHash(ctx context.Context, hash common.Hash, f
|
||||
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
|
||||
@ -440,6 +456,14 @@ func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash co
|
||||
if err != nil {
|
||||
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) {
|
||||
return nil, nil
|
||||
}
|
||||
@ -525,9 +549,11 @@ func (pea *PublicEthAPI) localGetLogs(crit filters.FilterCriteria) ([]*types.Log
|
||||
for i, addr := range crit.Addresses {
|
||||
addrStrs[i] = addr.String()
|
||||
}
|
||||
topicStrSets := make([][]string, 4)
|
||||
|
||||
topicStrSets := make([][]string, len(crit.Topics))
|
||||
for i, topicSet := range crit.Topics {
|
||||
if i > 3 {
|
||||
topicStrSets = topicStrSets[:4]
|
||||
// don't allow more than 4 topics
|
||||
break
|
||||
}
|
||||
@ -569,8 +595,13 @@ func (pea *PublicEthAPI) localGetLogs(crit filters.FilterCriteria) ([]*types.Log
|
||||
if err := tx.Commit(); err != nil {
|
||||
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
|
||||
// nil values are filled in; to request a single block have both ToBlock and FromBlock equal that number
|
||||
startingBlock := crit.FromBlock
|
||||
@ -578,6 +609,7 @@ func (pea *PublicEthAPI) localGetLogs(crit filters.FilterCriteria) ([]*types.Log
|
||||
if startingBlock == nil {
|
||||
startingBlock = common.Big0
|
||||
}
|
||||
|
||||
if endingBlock == nil {
|
||||
endingBlockInt, err := pea.B.Retriever.RetrieveLastBlockNumber()
|
||||
if err != nil {
|
||||
@ -585,24 +617,38 @@ func (pea *PublicEthAPI) localGetLogs(crit filters.FilterCriteria) ([]*types.Log
|
||||
}
|
||||
endingBlock = big.NewInt(endingBlockInt)
|
||||
}
|
||||
|
||||
start := startingBlock.Int64()
|
||||
end := endingBlock.Int64()
|
||||
allRctCIDs := make([]eth.ReceiptModel, 0)
|
||||
var logs []*types.Log
|
||||
for i := start; i <= end; i++ {
|
||||
rctCIDs, err := pea.B.Retriever.RetrieveRctCIDs(tx, filter, i, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allRctCIDs = append(allRctCIDs, rctCIDs...)
|
||||
}
|
||||
rctIPLDs, err := pea.B.Fetcher.FetchRcts(tx, allRctCIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
block, err := pea.B.BlockByNumber(context.Background(), rpc.BlockNumber(i))
|
||||
if err != nil {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
@ -627,6 +673,10 @@ func (pea *PublicEthAPI) GetBalance(ctx context.Context, address common.Address,
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
if err == sql.ErrNoRows {
|
||||
return (*hexutil.Big)(big.NewInt(0)), nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -644,7 +694,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) {
|
||||
storageVal, err := pea.B.GetStorageByNumberOrHash(ctx, address, common.HexToHash(key), blockNrOrHash)
|
||||
if storageVal != nil && err == nil {
|
||||
return storageVal, nil
|
||||
var value common.Hash
|
||||
Did you confirm this behaviour against the standard JSON RPC API endpoint, i.e. expected result when the storage slot doesn't exist. Did you confirm this behaviour against the standard JSON RPC API endpoint, i.e. expected result when the storage slot doesn't exist.
i-norden
commented
Yeah I think this is undoing one of the fixes Ramil made here, the unit test is broken in what it is expecting rather than what it is receiving in this case (and probably all the cases where the unit tests were broken by the changes made in this PR, as the unit tests were passing before them). The majority of the problems this PR is fixing are due to me not anticipating (and failing to test) what the correct expected results were for error and nil cases. Ramil's integration tests compare the results to the results from a standard ETH JSON-RPC client so those are the source of truth. Yeah I think this is undoing one of the fixes Ramil made here, the unit test is broken in what it is expecting rather than what it is receiving in this case (and probably all the cases where the unit tests were broken by the changes made in this PR, as the unit tests were passing before them). The majority of the problems this PR is fixing are due to me not anticipating (and failing to test) what the correct expected results were for error and nil cases. Ramil's integration tests compare the results to the results from a standard ETH JSON-RPC client so those are the source of truth.
Yes, I confirmed the behavior manually. Yes, I confirmed the behavior manually.
We have two tests suite:
**Unit test:** Which makes calls to the DB and checks expectations.
**Integration test**: Which compares ETH and IPLD APIs response.
I will check if there is an Integration test for the same or else I will add it.
|
||||
_, 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 {
|
||||
var res hexutil.Bytes
|
||||
@ -653,6 +713,9 @@ func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Addres
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
if err == sql.ErrNoRows {
|
||||
return make([]byte, 32), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -669,6 +732,10 @@ func (pea *PublicEthAPI) GetCode(ctx context.Context, address common.Address, bl
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
if err == sql.ErrNoRows {
|
||||
return code, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,16 @@ package eth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"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/eth/filters"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
. "github.com/onsi/ginkgo"
|
||||
@ -168,7 +171,7 @@ var (
|
||||
"to": expectedTransaction3.To,
|
||||
"gasUsed": hexutil.Uint64(test_helpers.MockReceipts[2].GasUsed),
|
||||
"cumulativeGasUsed": hexutil.Uint64(test_helpers.MockReceipts[2].CumulativeGasUsed),
|
||||
"contractAddress": nil,
|
||||
"contractAddress": test_helpers.ContractAddress,
|
||||
"logs": test_helpers.MockReceipts[2].Logs,
|
||||
"logsBloom": test_helpers.MockReceipts[2].Bloom,
|
||||
"root": hexutil.Bytes(test_helpers.MockReceipts[2].PostState),
|
||||
@ -177,8 +180,9 @@ var (
|
||||
|
||||
var _ = Describe("API", func() {
|
||||
var (
|
||||
db *postgres.DB
|
||||
api *eth.PublicEthAPI
|
||||
db *postgres.DB
|
||||
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
|
||||
// Note: if you focus one of the tests be sure to focus this and the defered It()
|
||||
@ -187,7 +191,11 @@ var _ = Describe("API", func() {
|
||||
db, err = shared.SetupDB()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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())
|
||||
api = eth.NewPublicEthAPI(backend, nil, false)
|
||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
||||
@ -271,10 +279,10 @@ var _ = Describe("API", func() {
|
||||
Expect(val).To(Equal(block[key]))
|
||||
}
|
||||
})
|
||||
It("Throws an error if a block cannot be found", func() {
|
||||
_, err := api.GetBlockByNumber(ctx, wrongNumber, false)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
It("Returns `nil` if a block cannot be found", func() {
|
||||
block, err := api.GetBlockByNumber(ctx, wrongNumber, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(block).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
@ -303,10 +311,10 @@ var _ = Describe("API", func() {
|
||||
Expect(val).To(Equal(block[key]))
|
||||
}
|
||||
})
|
||||
It("Throws an error if a block cannot be found", func() {
|
||||
_, err := api.GetBlockByHash(ctx, randomHash, false)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
It("Returns `nil` if a block cannot be found", func() {
|
||||
block, err := api.GetBlockByHash(ctx, randomHash, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(block).To(BeZero())
|
||||
})
|
||||
})
|
||||
|
||||
@ -325,10 +333,10 @@ var _ = Describe("API", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(uncle2).To(Equal(expectedUncle2))
|
||||
})
|
||||
It("Throws an error if an block for blocknumber cannot be found", func() {
|
||||
_, err := api.GetUncleByBlockNumberAndIndex(ctx, wrongNumber, 0)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
It("Returns `nil` if an block for block number cannot be found", func() {
|
||||
block, err := api.GetUncleByBlockNumberAndIndex(ctx, wrongNumber, 0)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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() {
|
||||
uncle, err := api.GetUncleByBlockNumberAndIndex(ctx, number, 2)
|
||||
@ -346,10 +354,10 @@ var _ = Describe("API", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(uncle2).To(Equal(expectedUncle2))
|
||||
})
|
||||
It("Throws an error if an block for blockhash cannot be found", func() {
|
||||
_, err := api.GetUncleByBlockHashAndIndex(ctx, randomHash, 0)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
It("Returns `nil` if a block for blockhash cannot be found", func() {
|
||||
block, err := api.GetUncleByBlockHashAndIndex(ctx, randomHash, 0)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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() {
|
||||
uncle, err := api.GetUncleByBlockHashAndIndex(ctx, blockHash, 2)
|
||||
@ -361,6 +369,7 @@ var _ = Describe("API", func() {
|
||||
Describe("eth_getUncleCountByBlockNumber", func() {
|
||||
It("Retrieves the number of uncles for the canonical block with the provided number", func() {
|
||||
count := api.GetUncleCountByBlockNumber(ctx, number)
|
||||
Expect(*count).NotTo(Equal(nil))
|
||||
Expect(uint64(*count)).To(Equal(uint64(2)))
|
||||
})
|
||||
})
|
||||
@ -368,6 +377,7 @@ var _ = Describe("API", func() {
|
||||
Describe("eth_getUncleCountByBlockHash", func() {
|
||||
It("Retrieves the number of uncles for the block with the provided hash", func() {
|
||||
count := api.GetUncleCountByBlockHash(ctx, blockHash)
|
||||
Expect(*count).NotTo(Equal(nil))
|
||||
Expect(uint64(*count)).To(Equal(uint64(2)))
|
||||
})
|
||||
})
|
||||
@ -948,8 +958,17 @@ var _ = Describe("API", func() {
|
||||
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", func() {
|
||||
_, err := api.GetBalance(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true))
|
||||
It("Retrieves the eth balance for the non-existing account address at the block with the provided hash", func() {
|
||||
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())
|
||||
})
|
||||
})
|
||||
@ -965,9 +984,10 @@ var _ = Describe("API", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(code).To(Equal((hexutil.Bytes)(test_helpers.ContractCode)))
|
||||
})
|
||||
It("Throws an error for an account it cannot find the code for", func() {
|
||||
_, err := api.GetCode(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true))
|
||||
Expect(err).To(HaveOccurred())
|
||||
It("Returns `nil` for an account it cannot find the code for", func() {
|
||||
code, err := api.GetCode(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(code).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -18,6 +18,7 @@ package eth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
@ -50,6 +51,8 @@ import (
|
||||
var (
|
||||
errPendingBlockNumber = errors.New("pending 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 (
|
||||
@ -201,9 +204,9 @@ func (b *Backend) GetTd(blockHash common.Hash) (*big.Int, error) {
|
||||
}
|
||||
|
||||
// CurrentBlock returns the current block
|
||||
func (b *Backend) CurrentBlock() *types.Block {
|
||||
block, _ := b.BlockByNumber(context.Background(), rpc.LatestBlockNumber)
|
||||
return block
|
||||
func (b *Backend) CurrentBlock() (*types.Block, error) {
|
||||
block, err := b.BlockByNumber(context.Background(), rpc.LatestBlockNumber)
|
||||
return block, err
|
||||
}
|
||||
|
||||
// BlockByNumberOrHash returns block by number or hash
|
||||
@ -263,12 +266,18 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
||||
// Get the canonical hash
|
||||
canonicalHash, err := b.GetCanonicalHash(uint64(number))
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
// 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)
|
||||
headerCID, uncleCIDs, txCIDs, rctCIDs, err := b.Retriever.RetrieveBlockByHash(canonicalHash)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -291,6 +300,9 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
||||
// Fetch and decode the header IPLD
|
||||
headerIPLD, err := b.Fetcher.FetchHeader(tx, headerCID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var header types.Header
|
||||
@ -346,6 +358,9 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
// Retrieve all the CIDs for the block
|
||||
headerCID, uncleCIDs, txCIDs, rctCIDs, err := b.Retriever.RetrieveBlockByHash(hash)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -368,6 +383,9 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
// Fetch and decode the header IPLD
|
||||
headerIPLD, err := b.Fetcher.FetchHeader(tx, headerCID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var header types.Header
|
||||
@ -377,6 +395,9 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
// Fetch and decode the uncle IPLDs
|
||||
uncleIPLDs, err := b.Fetcher.FetchUncles(tx, uncleCIDs)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var uncles []*types.Header
|
||||
@ -390,6 +411,9 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
// Fetch and decode the transaction IPLDs
|
||||
txIPLDs, err := b.Fetcher.FetchTrxs(tx, txCIDs)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var transactions []*types.Transaction
|
||||
@ -403,6 +427,9 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
// Fetch and decode the receipt IPLDs
|
||||
rctIPLDs, err := b.Fetcher.FetchRcts(tx, rctCIDs)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var receipts []*types.Receipt
|
||||
@ -545,7 +572,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
|
||||
func (b *Backend) GetAccountByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*state.Account, error) {
|
||||
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 {
|
||||
return b.GetAccountByHash(ctx, address, hash)
|
||||
@ -554,23 +581,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
|
||||
func (b *Backend) GetAccountByNumber(ctx context.Context, address common.Address, number uint64) (*state.Account, error) {
|
||||
hash, err := b.GetCanonicalHash(number)
|
||||
if err != nil {
|
||||
func (b *Backend) GetAccountByNumber(ctx context.Context, address common.Address, blockNumber rpc.BlockNumber) (*state.Account, error) {
|
||||
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 == sql.ErrNoRows {
|
||||
return nil, errHeaderNotFound
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hash == (common.Hash{}) {
|
||||
return nil, fmt.Errorf("no canoncial block hash found for provided height (%d)", number)
|
||||
}
|
||||
|
||||
return b.GetAccountByHash(ctx, address, 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) {
|
||||
_, 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acct := new(state.Account)
|
||||
return acct, rlp.DecodeBytes(accountRlp, acct)
|
||||
}
|
||||
@ -578,7 +630,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
|
||||
func (b *Backend) GetCodeByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) ([]byte, error) {
|
||||
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 {
|
||||
return b.GetCodeByHash(ctx, address, hash)
|
||||
@ -587,8 +639,25 @@ 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
|
||||
func (b *Backend) GetCodeByNumber(ctx context.Context, address common.Address, number uint64) ([]byte, error) {
|
||||
hash, err := b.GetCanonicalHash(number)
|
||||
func (b *Backend) GetCodeByNumber(ctx context.Context, address common.Address, blockNumber rpc.BlockNumber) ([]byte, error) {
|
||||
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
|
||||
}
|
||||
@ -630,31 +699,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
|
||||
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 {
|
||||
return b.GetStorageByNumber(ctx, address, storageLeafKey, uint64(blockNr.Int64()))
|
||||
return b.GetStorageByNumber(ctx, address, key, blockNr)
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
// 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) {
|
||||
hash, err := b.GetCanonicalHash(number)
|
||||
if err != nil {
|
||||
func (b *Backend) GetStorageByNumber(ctx context.Context, address common.Address, key common.Hash, blockNumber rpc.BlockNumber) (hexutil.Bytes, error) {
|
||||
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 == sql.ErrNoRows {
|
||||
return nil, errHeaderNotFound
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hash == (common.Hash{}) {
|
||||
return nil, fmt.Errorf("no canoncial block hash found for provided height (%d)", number)
|
||||
}
|
||||
return b.GetStorageByHash(ctx, address, storageLeafKey, hash)
|
||||
|
||||
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
|
||||
func (b *Backend) GetStorageByHash(ctx context.Context, address common.Address, storageLeafKey, hash common.Hash) (hexutil.Bytes, error) {
|
||||
_, storageRlp, err := b.IPLDRetriever.RetrieveStorageAtByAddressAndStorageKeyAndBlockHash(address, storageLeafKey, hash)
|
||||
func (b *Backend) GetStorageByHash(ctx context.Context, address common.Address, key, hash common.Hash) (hexutil.Bytes, error) {
|
||||
_, 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
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,12 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
)
|
||||
@ -244,23 +244,91 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransacti
|
||||
}
|
||||
|
||||
i-norden
commented
This continue doesn't need the label This continue doesn't need the label
Done Done
|
||||
// extractLogsOfInterest returns logs from the receipt IPLD
|
||||
func extractLogsOfInterest(rctIPLDs []ipfs.BlockModel, wantedTopics [][]string) ([]*types.Log, error) {
|
||||
var logs []*types.Log
|
||||
for _, rctIPLD := range rctIPLDs {
|
||||
rctRLP := rctIPLD
|
||||
var rct types.Receipt
|
||||
if err := rlp.DecodeBytes(rctRLP.Data, &rct); err != nil {
|
||||
func extractLogsOfInterest(config *params.ChainConfig, blockHash common.Hash, blockNumber uint64,
|
||||
txs types.Transactions, rctIPLDs []ipfs.BlockModel, filter ReceiptFilter) ([]*types.Log, error) {
|
||||
receipts := make(types.Receipts, len(rctIPLDs))
|
||||
|
||||
for i, rctBytes := range rctIPLDs {
|
||||
rct := new(types.Receipt)
|
||||
if err := rlp.DecodeBytes(rctBytes.Data, rct); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, log := range rct.Logs {
|
||||
if wanted := wantedLog(wantedTopics, log.Topics); wanted == true {
|
||||
logs = append(logs, log)
|
||||
}
|
||||
receipts[i] = rct
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
func wantedLog(wantedTopics [][]string, actualTopics []common.Hash) bool {
|
||||
// actualTopics will always have length <= 4
|
||||
|
@ -310,6 +310,14 @@ func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, b
|
||||
args = append(args, blockHash.String())
|
||||
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 {
|
||||
// Filter on log contract addresses if there are any
|
||||
pgStr += fmt.Sprintf(` AND ((receipt_cids.log_contracts && $%d::VARCHAR(66)[]`, id)
|
||||
@ -371,6 +379,7 @@ func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, b
|
||||
args = append(args, pq.Array(trxIds))
|
||||
}
|
||||
}
|
||||
|
||||
pgStr += ` ORDER BY transaction_cids.index`
|
||||
receiptCids := make([]eth.ReceiptModel, 0)
|
||||
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
||||
|
@ -237,6 +237,7 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
Expect(len(cids)).To(Equal(1))
|
||||
Expect(cids[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
|
||||
expectedHeaderCID := test_helpers.MockCIDWrapper.Header
|
||||
expectedHeaderCID.ID = cids[0].Header.ID
|
||||
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[2].CID)).To(BeTrue())
|
||||
Expect(len(cids[0].StateNodes)).To(Equal(2))
|
||||
|
||||
for _, stateNode := range cids[0].StateNodes {
|
||||
if stateNode.CID == test_helpers.State1CID.String() {
|
||||
Expect(stateNode.StateKey).To(Equal(common.BytesToHash(test_helpers.ContractLeafKey).Hex()))
|
||||
|
@ -38,7 +38,6 @@ import (
|
||||
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"
|
||||
)
|
||||
@ -60,6 +59,7 @@ func init() {
|
||||
}
|
||||
|
||||
var _ = Describe("eth state reading tests", func() {
|
||||
const chainLength = 5
|
||||
var (
|
||||
blocks []*types.Block
|
||||
receipts []types.Receipts
|
||||
@ -80,13 +80,13 @@ var _ = Describe("eth state reading tests", func() {
|
||||
backend, err = eth.NewEthBackend(db, ð.Config{
|
||||
ChainConfig: chainConfig,
|
||||
VmConfig: vm.Config{},
|
||||
RPCGasCap: big.NewInt(10000000000),
|
||||
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
api = eth.NewPublicEthAPI(backend, nil, false)
|
||||
|
||||
// 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{
|
||||
IntermediateStateNodes: 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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||
_, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(1))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(1))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(1))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(2))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock2))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(2))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedContractBalance))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(2))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(3))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock3))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(3))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedContractBalance))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(3))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(4))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(4))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedContractBalance))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(4))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock5))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(5))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(5))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedContractBalance))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(5))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||
_, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
||||
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))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock2))
|
||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedContractBalance))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock3))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedContractBalance))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedContractBalance))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct1BalanceBlock5))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal(expectedContractBalance))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
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() {
|
||||
_, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
_, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
It("Returns `0` for an account it cannot find the balance for an account at the provided block number", func() {
|
||||
bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||
|
||||
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() {
|
||||
_, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
_, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
It("Returns `0` for an error for an account it cannot find the balance for an account at the provided block hash", func() {
|
||||
bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||
|
||||
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
|
||||
|
||||
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(code).To(Equal((hexutil.Bytes)(test_helpers.ContractCode)))
|
||||
})
|
||||
It("Throws an error for an account it cannot find the code for", func() {
|
||||
_, err := api.GetCode(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||
Expect(err).To(HaveOccurred())
|
||||
It("Returns `nil` for an account it cannot find the code for", func() {
|
||||
code, err := api.GetCode(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(code).To(BeEmpty())
|
||||
})
|
||||
It("Throws an error for a contract that doesn't exist at this hieght", func() {
|
||||
_, err := api.GetCode(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).To(HaveOccurred())
|
||||
It("Returns `nil` for a contract that doesn't exist at this height", func() {
|
||||
code, err := api.GetCode(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(code).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("eth_getStorageAt", func() {
|
||||
It("Throws an error 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))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
It("Returns empty slice if it tries to access a contract which does not exist", func() {
|
||||
storage, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(storage).To(Equal(hexutil.Bytes(make([]byte, 32))))
|
||||
|
||||
_, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(1))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
storage, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(1))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
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() {
|
||||
_, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, randomHash.Hex(), rpc.BlockNumberOrHashWithNumber(2))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
It("Returns empty slice if it tries to access a contract slot which does not exist", func() {
|
||||
storage, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, randomHash.Hex(), rpc.BlockNumberOrHashWithNumber(2))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
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() {
|
||||
// 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())
|
||||
expectedRes := hexutil.Bytes(common.Hex2Bytes("01"))
|
||||
expectedRes := hexutil.Bytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"))
|
||||
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())
|
||||
expectedRes = hexutil.Bytes(common.Hex2Bytes("03"))
|
||||
expectedRes = hexutil.Bytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000003"))
|
||||
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())
|
||||
expectedRes = hexutil.Bytes(common.Hex2Bytes("09"))
|
||||
expectedRes = hexutil.Bytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000009"))
|
||||
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(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() {
|
||||
|
@ -428,11 +428,12 @@ func (r *IPLDRetriever) RetrieveAccountByAddressAndBlockNumber(address common.Ad
|
||||
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
|
||||
func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageKeyAndBlockHash(address common.Address, storageLeafKey, hash common.Hash) (string, []byte, error) {
|
||||
// RetrieveStorageAtByAddressAndStorageSlotAndBlockHash returns the cid and rlp bytes for the storage value corresponding to the provided address, storage slot, and block hash
|
||||
i-norden
commented
The name of this function implies the actual storage leaf key is provided to it, it shouldn't need to hash it again. If an actual storage key was provided this hashing would break the function. We should perform the hashing of the slot key into the leaf key at the level above or change the name to The name of this function implies the actual storage leaf key is provided to it, it shouldn't need to hash it again. If an actual storage key was provided this hashing would break the function. We should perform the hashing of the slot key into the leaf key at the level above or change the name to `RetrieveStorageAtByAddressAndStorageSlotAndBlockHash` so that the name aligns with the behavior.
Updated it to Updated it to `RetrieveStorageAtByAddressAndStorageSlotAndBlockHash` since the api gives us storage slot.
|
||||
func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageSlotAndBlockHash(address common.Address, key, hash common.Hash) (string, []byte, error) {
|
||||
storageResult := new(nodeInfo)
|
||||
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())
|
||||
if err := r.db.Get(storageResult, RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr, stateLeafKey.Hex(), storageHash.Hex(), hash.Hex()); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if storageResult.Removed {
|
||||
|
@ -34,7 +34,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"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"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@ -80,7 +80,7 @@ var (
|
||||
},
|
||||
}
|
||||
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())
|
||||
MockChildHeader = types.Header{
|
||||
Time: 0,
|
||||
@ -104,15 +104,22 @@ var (
|
||||
mockTopic21 = common.HexToHash("0x05")
|
||||
mockTopic22 = common.HexToHash("0x07")
|
||||
MockLog1 = &types.Log{
|
||||
Address: Address,
|
||||
Topics: []common.Hash{mockTopic11, mockTopic12},
|
||||
Data: []byte{},
|
||||
Address: Address,
|
||||
Topics: []common.Hash{mockTopic11, mockTopic12},
|
||||
Data: []byte{},
|
||||
BlockNumber: BlockNumber.Uint64(),
|
||||
TxIndex: 0,
|
||||
Index: 0,
|
||||
}
|
||||
MockLog2 = &types.Log{
|
||||
Address: AnotherAddress,
|
||||
Topics: []common.Hash{mockTopic21, mockTopic22},
|
||||
Data: []byte{},
|
||||
Address: AnotherAddress,
|
||||
Topics: []common.Hash{mockTopic21, mockTopic22},
|
||||
Data: []byte{},
|
||||
BlockNumber: BlockNumber.Uint64(),
|
||||
TxIndex: 1,
|
||||
Index: 1,
|
||||
}
|
||||
|
||||
HeaderCID, _ = ipld.RawdataToCid(ipld.MEthHeader, MockHeaderRlp, multihash.KECCAK_256)
|
||||
HeaderMhKey = shared.MultihashKeyFromCID(HeaderCID)
|
||||
Trx1CID, _ = ipld.RawdataToCid(ipld.MEthTx, MockTransactions.GetRlp(0), multihash.KECCAK_256)
|
||||
@ -375,6 +382,8 @@ var (
|
||||
StateNodes: MockStateNodes,
|
||||
}
|
||||
|
||||
Reward = eth.CalcEthBlockReward(MockBlock.Header(), MockBlock.Uncles(), MockBlock.Transactions(), MockReceipts)
|
||||
|
||||
MockCIDWrapper = ð2.CIDWrapper{
|
||||
BlockNumber: new(big.Int).Set(BlockNumber),
|
||||
Header: eth.HeaderModel{
|
||||
@ -384,7 +393,7 @@ var (
|
||||
CID: HeaderCID.String(),
|
||||
MhKey: HeaderMhKey,
|
||||
TotalDifficulty: MockBlock.Difficulty().String(),
|
||||
Reward: "5312500000000000000",
|
||||
Reward: Reward.String(),
|
||||
StateRoot: MockBlock.Root().String(),
|
||||
RctRoot: MockBlock.ReceiptHash().String(),
|
||||
TxRoot: MockBlock.TxHash().String(),
|
||||
@ -489,6 +498,17 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func createNewBlock(header *types.Header, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, hasher types.Hasher) *types.Block {
|
||||
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
|
||||
}
|
||||
|
||||
// createTransactionsAndReceipts is a helper function to generate signed mock transactions and mock receipts with mock logs
|
||||
func createTransactionsAndReceipts() (types.Transactions, types.Receipts, common.Address) {
|
||||
// make transactions
|
||||
@ -519,13 +539,26 @@ func createTransactionsAndReceipts() (types.Transactions, types.Receipts, common
|
||||
}
|
||||
// make receipts
|
||||
mockReceipt1 := types.NewReceipt(common.HexToHash("0x0").Bytes(), false, 50)
|
||||
|
||||
hash1 := signedTrx1.Hash()
|
||||
MockLog1.TxHash = hash1
|
||||
|
||||
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)
|
||||
hash2 := signedTrx2.Hash()
|
||||
MockLog2.TxHash = hash2
|
||||
|
||||
mockReceipt2.Logs = []*types.Log{MockLog2}
|
||||
mockReceipt2.TxHash = signedTrx2.Hash()
|
||||
mockReceipt3 := types.NewReceipt(common.HexToHash("0x2").Bytes(), false, 75)
|
||||
mockReceipt2.TxHash = hash2
|
||||
mockReceipt2.GasUsed = mockReceipt2.CumulativeGasUsed - mockReceipt1.CumulativeGasUsed
|
||||
|
||||
mockReceipt3 := types.NewReceipt(common.HexToHash("0x2").Bytes(), false, 175)
|
||||
mockReceipt3.Logs = []*types.Log{}
|
||||
mockReceipt3.TxHash = signedTrx3.Hash()
|
||||
mockReceipt3.GasUsed = mockReceipt3.CumulativeGasUsed - mockReceipt2.CumulativeGasUsed
|
||||
|
||||
return types.Transactions{signedTrx1, signedTrx2, signedTrx3}, types.Receipts{mockReceipt1, mockReceipt2, mockReceipt3}, SenderAddr
|
||||
}
|
||||
|
@ -867,7 +867,11 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
|
||||
if args.To != nil {
|
||||
to = rpc.BlockNumber(*args.To)
|
||||
} 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 {
|
||||
return []*Block{}, nil
|
||||
|
21
scripts/run_intregration_test.sh
Executable file
@ -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
|
2
scripts/run_unit_test.sh
Executable file
@ -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
|
15
test/README.md
Normal file
@ -0,0 +1,15 @@
|
||||
Typo ("intrgration") Typo ("intrgration")
Typo ("intrgration") Typo ("intrgration")
Done Done
Done Done
|
||||
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
Spin up services:
|
||||
Add documentation on how to run the unit and integration tests. Add documentation on how to run the unit and integration tests.
Done Done
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
```
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
```
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
Running unit tests:
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
```bash
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
make test_local
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
```
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
Running integration test:
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
```bash
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
make integrationtest_local
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
||||
```
|
||||
Typo ("intrgration") Typo ("intrgration")
Done Done
|
3
test/contract/.dockerignore
Normal file
@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
artifacts
|
||||
cache
|
5
test/contract/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
|
||||
#Hardhat files
|
||||
cache
|
||||
artifacts
|
14
test/contract/Dockerfile
Normal file
@ -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"]
|
7
test/contract/contracts/GLDToken.sol
Normal file
@ -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);
|
||||
}
|
||||
}
|
32
test/contract/hardhat.config.js
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
27700
test/contract/package-lock.json
generated
Normal file
27
test/contract/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
18
test/contract/scripts/deploy.js
Normal file
@ -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);
|
||||
});
|
36
test/contract/scripts/sample-script.js
Normal file
@ -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);
|
||||
});
|
60
test/contract/src/index.js
Normal file
@ -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();
|
14
test/contract/test/sample-test.js
Normal file
@ -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!");
|
||||
});
|
||||
});
|
62
test/helper.go
Normal file
@ -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
|
||||
}
|
19
test/integration_suite_test.go
Normal file
@ -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)
|
||||
})
|
486
test/integration_test.go
Normal file
@ -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))
|
||||
}
|
Check if this is the latest one?
The test fails after upgrading the docker images.
Latest is v0.5.0