GQL API for getStorageAt and getLogs #69
15
go.mod
15
go.mod
@ -3,8 +3,6 @@ module github.com/vulcanize/ipld-eth-server
|
|||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ClickHouse/clickhouse-go v1.4.5 // indirect
|
|
||||||
github.com/denisenkom/go-mssqldb v0.10.0 // indirect
|
|
||||||
github.com/ethereum/go-ethereum v1.9.25
|
github.com/ethereum/go-ethereum v1.9.25
|
||||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20201003130358-c5bdf3b1108e
|
github.com/graph-gophers/graphql-go v0.0.0-20201003130358-c5bdf3b1108e
|
||||||
@ -15,31 +13,24 @@ require (
|
|||||||
github.com/ipfs/go-ipld-format v0.2.0
|
github.com/ipfs/go-ipld-format v0.2.0
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/lib/pq v1.10.2
|
github.com/lib/pq v1.10.2
|
||||||
github.com/machinebox/graphql v0.2.2 // indirect
|
github.com/machinebox/graphql v0.2.2
|
||||||
|
github.com/matryer/is v1.4.0 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.7 // indirect
|
github.com/mattn/go-sqlite3 v1.14.7 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.1.2 // indirect
|
|
||||||
github.com/multiformats/go-multihash v0.0.14
|
github.com/multiformats/go-multihash v0.0.14
|
||||||
github.com/onsi/ginkgo v1.16.4
|
github.com/onsi/ginkgo v1.16.4
|
||||||
github.com/onsi/gomega v1.10.1
|
github.com/onsi/gomega v1.10.1
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pressly/goose v2.7.0+incompatible // indirect
|
|
||||||
github.com/prometheus/client_golang v1.5.1
|
github.com/prometheus/client_golang v1.5.1
|
||||||
github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a
|
|
||||||
github.com/sirupsen/logrus v1.7.0
|
github.com/sirupsen/logrus v1.7.0
|
||||||
github.com/spf13/cobra v1.1.1
|
github.com/spf13/cobra v1.1.1
|
||||||
github.com/spf13/viper v1.7.0
|
github.com/spf13/viper v1.7.0
|
||||||
github.com/vulcanize/gap-filler v0.3.1
|
github.com/vulcanize/gap-filler v0.3.1
|
||||||
github.com/vulcanize/ipfs-ethdb v0.0.2-alpha
|
github.com/vulcanize/ipfs-ethdb v0.0.2
|
||||||
github.com/vulcanize/ipld-eth-indexer v0.7.1-alpha
|
github.com/vulcanize/ipld-eth-indexer v0.7.1-alpha
|
||||||
github.com/ziutek/mymysql v1.5.4 // indirect
|
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
|
||||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b // indirect
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
|
||||||
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect
|
golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect
|
||||||
golang.org/x/tools v0.1.3 // indirect
|
golang.org/x/tools v0.1.3 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/ethereum/go-ethereum v1.9.25 => github.com/vulcanize/go-ethereum v1.9.25-statediff-0.0.15
|
replace github.com/ethereum/go-ethereum v1.9.25 => github.com/vulcanize/go-ethereum v1.9.25-statediff-0.0.15
|
||||||
|
|
||||||
replace github.com/vulcanize/ipfs-ethdb v0.0.2-alpha => github.com/vulcanize/pg-ipfs-ethdb v0.0.2-alpha
|
|
||||||
|
@ -12,8 +12,8 @@ import (
|
|||||||
|
|
||||||
type StorageResponse struct {
|
type StorageResponse struct {
|
||||||
Cid string `json:"cid"`
|
Cid string `json:"cid"`
|
||||||
|
Value hexutil.Bytes `json:"value"`
|
||||||
IpldBlock hexutil.Bytes `json:"ipldBlock"`
|
IpldBlock hexutil.Bytes `json:"ipldBlock"`
|
||||||
Value common.Hash `json:"value"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetStorageAt struct {
|
type GetStorageAt struct {
|
||||||
@ -94,7 +94,6 @@ func (c *Client) GetStorageAt(ctx context.Context, hash common.Hash, address com
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var storageAt GetStorageAt
|
var storageAt GetStorageAt
|
||||||
err = json.Unmarshal(jsonStr, &storageAt)
|
err = json.Unmarshal(jsonStr, &storageAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
@ -965,8 +964,8 @@ type StorageResult struct {
|
|||||||
ipldBlock []byte
|
ipldBlock []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StorageResult) Value(ctx context.Context) common.Hash {
|
func (s *StorageResult) Value(ctx context.Context) hexutil.Bytes {
|
||||||
return common.BytesToHash(s.value)
|
return s.value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StorageResult) Cid(ctx context.Context) string {
|
func (s *StorageResult) Cid(ctx context.Context) string {
|
||||||
@ -982,32 +981,14 @@ func (r *Resolver) GetStorageAt(ctx context.Context, args struct {
|
|||||||
Contract common.Address
|
Contract common.Address
|
||||||
Slot common.Hash
|
Slot common.Hash
|
||||||
}) (*StorageResult, error) {
|
}) (*StorageResult, error) {
|
||||||
storageLeafKey := crypto.Keccak256Hash(args.Slot.Bytes())
|
cid, ipldBlock, rlpValue, err := r.backend.IPLDRetriever.RetrieveStorageAtByAddressAndStorageKeyAndBlockHash(args.Contract, args.Slot, args.BlockHash)
|
||||||
cid, ipldBlock, rlpValue, err := r.backend.IPLDRetriever.RetrieveStorageAtByAddressAndStorageKeyAndBlockHash(args.Contract, storageLeafKey, args.BlockHash)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
ret := StorageResult{value: ([]byte{}), cid: "", ipldBlock: ([]byte{})}
|
return &StorageResult{value: []byte{}, cid: "", ipldBlock: []byte{}}, nil
|
||||||
|
} else if err != nil {
|
||||||
return &ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var value interface{}
|
return &StorageResult{value: rlpValue, cid: cid, ipldBlock: ipldBlock}, nil
|
||||||
err = rlp.DecodeBytes(rlpValue, &value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ret := StorageResult{value: value.([]byte), cid: cid, ipldBlock: ipldBlock}
|
|
||||||
|
|
||||||
return &ret, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) GetLogs(ctx context.Context, args struct {
|
func (r *Resolver) GetLogs(ctx context.Context, args struct {
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
@ -54,7 +53,7 @@ var _ = Describe("GraphQL", func() {
|
|||||||
receipts []types.Receipts
|
receipts []types.Receipts
|
||||||
chain *core.BlockChain
|
chain *core.BlockChain
|
||||||
db *postgres.DB
|
db *postgres.DB
|
||||||
|
blockHashes []common.Hash
|
||||||
backend *eth.Backend
|
backend *eth.Backend
|
||||||
graphQLServer *graphql.Service
|
graphQLServer *graphql.Service
|
||||||
chainConfig = params.TestChainConfig
|
chainConfig = params.TestChainConfig
|
||||||
@ -88,6 +87,7 @@ var _ = Describe("GraphQL", func() {
|
|||||||
// iterate over the blocks, generating statediff payloads, and transforming the data into Postgres
|
// iterate over the blocks, generating statediff payloads, and transforming the data into Postgres
|
||||||
builder := statediff.NewBuilder(chain.StateCache())
|
builder := statediff.NewBuilder(chain.StateCache())
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
blockHashes = append(blockHashes, block.Hash())
|
||||||
var args statediff.Args
|
var args statediff.Args
|
||||||
var rcts types.Receipts
|
var rcts types.Receipts
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
@ -133,6 +133,7 @@ var _ = Describe("GraphQL", func() {
|
|||||||
|
|
||||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
// The non-canonical header has a child
|
// The non-canonical header has a child
|
||||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayloadForChild)
|
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayloadForChild)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@ -175,13 +176,39 @@ var _ = Describe("GraphQL", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Describe("eth_getStorageAt", func() {
|
Describe("eth_getStorageAt", func() {
|
||||||
It("Retrieves storage at the provided blockHash contract address and slot", func() {
|
It("Retrieves the storage value at the provided contract address and storage leaf key at the block with the provided hash", func() {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
storageRes, err := client.GetStorageAt(ctx, blockHashes[2], contractAddress, slot)
|
||||||
defer cancel()
|
|
||||||
_, err := client.GetStorageAt(ctx, blockHash, contractAddress, slot)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(hexutil.Bytes(common.Hex2Bytes("01"))))
|
||||||
|
|
||||||
// TODO: Currently this is failing, Update the test when the underlying code is fixed.
|
storageRes, err = client.GetStorageAt(ctx, blockHashes[3], contractAddress, slot)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(hexutil.Bytes(common.Hex2Bytes("03"))))
|
||||||
|
|
||||||
|
storageRes, err = client.GetStorageAt(ctx, blockHashes[4], contractAddress, slot)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(hexutil.Bytes(common.Hex2Bytes("09"))))
|
||||||
|
|
||||||
|
storageRes, err = client.GetStorageAt(ctx, blockHashes[5], contractAddress, slot)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(hexutil.Bytes{}))
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Retrieves empty data if it tries to access a contract at the blockHash which does not exist", func() {
|
||||||
|
storageRes, err := client.GetStorageAt(ctx, blockHashes[0], contractAddress, slot)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(hexutil.Bytes{}))
|
||||||
|
|
||||||
|
storageRes, err = client.GetStorageAt(ctx, blockHashes[1], contractAddress, slot)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(hexutil.Bytes{}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Retrieves empty data if it tries to access a contract slot which does not exist", func() {
|
||||||
|
storageRes, err := client.GetStorageAt(ctx, blockHashes[3], contractAddress, randomHash.Hex())
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(storageRes.Value).To(Equal(hexutil.Bytes{}))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -191,14 +218,17 @@ func publishCode(db *postgres.DB, codeHash common.Hash, code []byte) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mhKey, err := shared.MultihashKeyFromKeccak256(codeHash)
|
mhKey, err := shared.MultihashKeyFromKeccak256(codeHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = tx.Rollback()
|
_ = tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := shared.PublishDirect(tx, mhKey, code); err != nil {
|
if err := shared.PublishDirect(tx, mhKey, code); err != nil {
|
||||||
_ = tx.Rollback()
|
_ = tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ const schema string = `
|
|||||||
|
|
||||||
# Storage trie value with IPLD data.
|
# Storage trie value with IPLD data.
|
||||||
type StorageResult {
|
type StorageResult {
|
||||||
value: Bytes32!
|
value: Bytes!
|
||||||
|
|
||||||
# CID for the storage trie IPLD block.
|
# CID for the storage trie IPLD block.
|
||||||
cid: String!
|
cid: String!
|
||||||
|
Loading…
Reference in New Issue
Block a user