Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local state index engine #537

Merged
merged 1 commit into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ EVM Gateway has public RPC endpoints available for the following environments:

| Name | Value |
|-----------------|----------------------------------------|
| Network Name | Testnet |
| Network Name | EVM on Flow Testnet |
| Description | The public RPC URL for Flow Testnet |
| RPC Endpoint | https://testnet.evm.nodes.onflow.org |
| Chain ID | 545 |
Expand All @@ -226,7 +226,7 @@ EVM Gateway has public RPC endpoints available for the following environments:

| Name | Value |
|-----------------|----------------------------------------|
| Network Name | Mainnet |
| Network Name | EVM on Flow |
| Description | The public RPC URL for Flow Mainnet |
| RPC Endpoint | https://mainnet.evm.nodes.onflow.org |
| Chain ID | 747 |
Expand Down
68 changes: 45 additions & 23 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,12 @@ func (b *BlockChainAPI) GetTransactionByBlockHashAndIndex(
return handleError[*Transaction](err, l, b.collector)
}

highestIndex := len(block.TransactionHashes) - 1
if index > hexutil.Uint(highestIndex) {
if int(index) >= len(block.TransactionHashes) {
return nil, nil
}

txHash := block.TransactionHashes[index]
tx, err := b.GetTransactionByHash(ctx, txHash)
tx, err := b.prepareTransactionResponse(txHash)
if err != nil {
return handleError[*Transaction](err, l, b.collector)
}
Expand Down Expand Up @@ -324,7 +323,7 @@ func (b *BlockChainAPI) GetTransactionByBlockNumberAndIndex(
}

txHash := block.TransactionHashes[index]
tx, err := b.GetTransactionByHash(ctx, txHash)
tx, err := b.prepareTransactionResponse(txHash)
if err != nil {
return handleError[*Transaction](err, l, b.collector)
}
Expand Down Expand Up @@ -385,7 +384,7 @@ func (b *BlockChainAPI) GetBlockByHash(
return handleError[*Block](err, l, b.collector)
}

apiBlock, err := b.prepareBlockResponse(ctx, block, fullTx)
apiBlock, err := b.prepareBlockResponse(block, fullTx)
if err != nil {
return handleError[*Block](err, l, b.collector)
}
Expand Down Expand Up @@ -429,7 +428,7 @@ func (b *BlockChainAPI) GetBlockByNumber(
return handleError[*Block](err, l, b.collector)
}

apiBlock, err := b.prepareBlockResponse(ctx, block, fullTx)
apiBlock, err := b.prepareBlockResponse(block, fullTx)
if err != nil {
return handleError[*Block](err, l, b.collector)
}
Expand All @@ -440,11 +439,11 @@ func (b *BlockChainAPI) GetBlockByNumber(
// GetBlockReceipts returns the block receipts for the given block hash or number or tag.
func (b *BlockChainAPI) GetBlockReceipts(
ctx context.Context,
numHash rpc.BlockNumberOrHash,
) ([]*models.Receipt, error) {
blockNumberOrHash rpc.BlockNumberOrHash,
) ([]map[string]interface{}, error) {
l := b.logger.With().
Str("endpoint", "getBlockReceipts").
Str("hash", numHash.String()).
Str("hash", blockNumberOrHash.String()).
Logger()

if err := rateLimit(ctx, b.limiter, l); err != nil {
Expand All @@ -455,28 +454,37 @@ func (b *BlockChainAPI) GetBlockReceipts(
block *models.Block
err error
)
if numHash.BlockHash != nil {
block, err = b.blocks.GetByID(*numHash.BlockHash)
} else if numHash.BlockNumber != nil {
block, err = b.blocks.GetByHeight(uint64(numHash.BlockNumber.Int64()))
if blockNumberOrHash.BlockHash != nil {
block, err = b.blocks.GetByID(*blockNumberOrHash.BlockHash)
} else if blockNumberOrHash.BlockNumber != nil {
block, err = b.blocks.GetByHeight(uint64(blockNumberOrHash.BlockNumber.Int64()))
} else {
return handleError[[]*models.Receipt](
return handleError[[]map[string]interface{}](
fmt.Errorf("%w: block number or hash not provided", errs.ErrInvalid),
l,
b.collector,
)
}
if err != nil {
return handleError[[]*models.Receipt](err, l, b.collector)
return handleError[[]map[string]interface{}](err, l, b.collector)
}

receipts := make([]*models.Receipt, len(block.TransactionHashes))
receipts := make([]map[string]interface{}, len(block.TransactionHashes))
for i, hash := range block.TransactionHashes {
rcp, err := b.receipts.GetByTransactionID(hash)
tx, err := b.transactions.Get(hash)
if err != nil {
return handleError[[]map[string]interface{}](err, l, b.collector)
}

receipt, err := b.receipts.GetByTransactionID(hash)
if err != nil {
return handleError[[]*models.Receipt](err, l, b.collector)
return handleError[[]map[string]interface{}](err, l, b.collector)
}

receipts[i], err = MarshalReceipt(receipt, tx)
if err != nil {
return handleError[[]map[string]interface{}](err, l, b.collector)
}
receipts[i] = rcp
}

return receipts, nil
Expand Down Expand Up @@ -920,12 +928,11 @@ func (b *BlockChainAPI) GetStorageAt(
}

func (b *BlockChainAPI) fetchBlockTransactions(
ctx context.Context,
block *models.Block,
) ([]*Transaction, error) {
transactions := make([]*Transaction, 0)
for _, txHash := range block.TransactionHashes {
transaction, err := b.GetTransactionByHash(ctx, txHash)
transaction, err := b.prepareTransactionResponse(txHash)
if err != nil {
return nil, err
}
Expand All @@ -943,8 +950,23 @@ func (b *BlockChainAPI) fetchBlockTransactions(
return transactions, nil
}

func (b *BlockChainAPI) prepareTransactionResponse(
txHash common.Hash,
) (*Transaction, error) {
tx, err := b.transactions.Get(txHash)
if err != nil {
return nil, err
}

receipt, err := b.receipts.GetByTransactionID(txHash)
if err != nil {
return nil, err
}

return NewTransactionResult(tx, *receipt, b.config.EVMNetworkID)
}

func (b *BlockChainAPI) prepareBlockResponse(
ctx context.Context,
block *models.Block,
fullTx bool,
) (*Block, error) {
Expand Down Expand Up @@ -977,7 +999,7 @@ func (b *BlockChainAPI) prepareBlockResponse(
}
blockSize := rlp.ListSize(uint64(len(blockBytes)))

transactions, err := b.fetchBlockTransactions(ctx, block)
transactions, err := b.fetchBlockTransactions(block)
if err != nil {
return nil, err
}
Expand Down
73 changes: 16 additions & 57 deletions api/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/sethvargo/go-limiter"

"github.com/onflow/flow-evm-gateway/config"
"github.com/onflow/flow-evm-gateway/metrics"
errs "github.com/onflow/flow-evm-gateway/models/errors"
"github.com/onflow/flow-evm-gateway/services/logs"
"github.com/onflow/flow-evm-gateway/storage"
Expand Down Expand Up @@ -286,7 +285,7 @@ func (api *PullAPI) NewFilter(ctx context.Context, criteria filters.FilterCriter
}

// GetFilterLogs returns the logs for the filter with the given id.
// If the filter could not be found, `nil` is returned.
// If the filter could not be found or has expired, an error is returned.
func (api *PullAPI) GetFilterLogs(
ctx context.Context,
id rpc.ID,
Expand All @@ -300,56 +299,36 @@ func (api *PullAPI) GetFilterLogs(

filter, ok := api.filters[id]
if !ok {
return handleError[[]*gethTypes.Log](
fmt.Errorf("%w: filter by id %s does not exist", errs.ErrEntityNotFound, id),
api.logger,
metrics.NopCollector,
)
return nil, fmt.Errorf("filter by id %s does not exist", id)
}

if filter.expired() {
api.uninstallFilter(id)
return handleError[[]*gethTypes.Log](
fmt.Errorf("%w: filter by id %s has expired", errs.ErrEntityNotFound, id),
api.logger,
metrics.NopCollector,
)
return nil, fmt.Errorf("filter by id %s has expired", id)
}

logsFilter, ok := filter.(*logsFilter)
if !ok {
return handleError[[]*gethTypes.Log](
fmt.Errorf("%w: filter by id %s is not a logs filter", errs.ErrInvalid, id),
api.logger,
metrics.NopCollector,
return nil, fmt.Errorf(
"%w: filter by id %s is not a logs filter",
errs.ErrInvalid,
id,
)
}

current, err := api.blocks.LatestEVMHeight()
if err != nil {
return handleError[[]*gethTypes.Log](
err,
api.logger,
metrics.NopCollector,
)
return nil, err
}

result, err := api.getLogs(current, logsFilter)
if err != nil {
return handleError[[]*gethTypes.Log](
err,
api.logger,
metrics.NopCollector,
)
return nil, err
}

logs, ok := result.([]*gethTypes.Log)
if !ok {
return handleError[[]*gethTypes.Log](
fmt.Errorf("logs filter returned incorrect type: %T", result),
api.logger,
metrics.NopCollector,
)
return nil, fmt.Errorf("logs filter returned incorrect type: %T", result)
}

return logs, nil
Expand All @@ -362,37 +341,25 @@ func (api *PullAPI) GetFilterLogs(
// (pending)Log filters return []Log.
func (api *PullAPI) GetFilterChanges(ctx context.Context, id rpc.ID) (any, error) {
if err := rateLimit(ctx, api.ratelimiter, api.logger); err != nil {
return "", err
return nil, err
}

api.mux.Lock()
defer api.mux.Unlock()

f, ok := api.filters[id]
if !ok {
return handleError[any](
fmt.Errorf("%w: filter by id %s does not exist", errs.ErrEntityNotFound, id),
api.logger,
metrics.NopCollector,
)
return nil, fmt.Errorf("filter by id %s does not exist", id)
}

current, err := api.blocks.LatestEVMHeight()
if err != nil {
return handleError[any](
err,
api.logger,
metrics.NopCollector,
)
return nil, err
}

if f.expired() {
api.uninstallFilter(id)
return handleError[any](
fmt.Errorf("%w: filter by id %s has expired", errs.ErrEntityNotFound, id),
api.logger,
metrics.NopCollector,
)
return nil, fmt.Errorf("filter by id %s has expired", id)
}

var result any
Expand All @@ -404,19 +371,11 @@ func (api *PullAPI) GetFilterChanges(ctx context.Context, id rpc.ID) (any, error
case *logsFilter:
result, err = api.getLogs(current, filterType)
default:
return handleError[any](
fmt.Errorf("%w: non-supported filter type: %T", errs.ErrInvalid, filterType),
api.logger,
metrics.NopCollector,
)
return nil, fmt.Errorf("non-supported filter type: %T", filterType)
}

if err != nil {
return handleError[any](
err,
api.logger,
metrics.NopCollector,
)
return nil, err
}

f.updateUsed(current)
Expand Down
6 changes: 6 additions & 0 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,12 @@ func (w *responseHandler) Write(data []byte) (int, error) {
if message.Error == nil {
r, _ := message.Result.MarshalJSON()
log.RawJSON("result", r).Msg("API response")
} else { // still debug output all errors even known ones
l.Debug().
Str("error", message.Error.Message).
Int("code", message.Error.Code).
Any("data", message.Error.Data).
Msg("API error response")
}

return w.ResponseWriter.Write(data)
Expand Down
12 changes: 10 additions & 2 deletions bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/onflow/flow-go-sdk/crypto"
"github.com/rs/zerolog"
"github.com/sethvargo/go-limiter/memorystore"
grpcOpts "google.golang.org/grpc"

"github.com/onflow/flow-evm-gateway/api"
"github.com/onflow/flow-evm-gateway/config"
Expand Down Expand Up @@ -392,9 +393,16 @@ func startEngine(
// setupCrossSporkClient sets up a cross-spork AN client.
func setupCrossSporkClient(config *config.Config, logger zerolog.Logger) (*requester.CrossSporkClient, error) {
// create access client with cross-spork capabilities
currentSporkClient, err := grpc.NewClient(config.AccessNodeHost)
currentSporkClient, err := grpc.NewClient(
config.AccessNodeHost,
grpc.WithGRPCDialOptions(grpcOpts.WithDefaultCallOptions(grpcOpts.MaxCallRecvMsgSize(1024*1024*1024))),
)
if err != nil {
return nil, fmt.Errorf("failed to create client connection for host: %s, with error: %w", config.AccessNodeHost, err)
return nil, fmt.Errorf(
"failed to create client connection for host: %s, with error: %w",
config.AccessNodeHost,
err,
)
}

// if we provided access node previous spork hosts add them to the client
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/onflow/atree v0.8.0-rc.6
github.com/onflow/cadence v1.0.0-preview.52
github.com/onflow/flow-go v0.37.10
github.com/onflow/flow-go-sdk v1.0.0-preview.54
github.com/onflow/flow-go-sdk v1.0.0-preview.56
github.com/onflow/flow/protobuf/go/flow v0.4.6
github.com/onflow/go-ethereum v1.14.7
github.com/prometheus/client_golang v1.18.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1865,8 +1865,8 @@ github.com/onflow/flow-ft/lib/go/templates v1.0.0/go.mod h1:uQ8XFqmMK2jxyBSVrmyu
github.com/onflow/flow-go v0.37.10 h1:Nz2Gp63+0ubb9FuQaEZgCsXNXM5WsXq/j0ukC74N5Vw=
github.com/onflow/flow-go v0.37.10/go.mod h1:bfOCsCk0v1J93vXd+zrYkCmRIVOaL9oAXvNFWgVOujE=
github.com/onflow/flow-go-sdk v1.0.0-M1/go.mod h1:TDW0MNuCs4SvqYRUzkbRnRmHQL1h4X8wURsCw9P9beo=
github.com/onflow/flow-go-sdk v1.0.0-preview.54 h1:5GjCkyIyvE9KolOUUPTkGdEiV/8qOe1MGnLHOLBmthA=
github.com/onflow/flow-go-sdk v1.0.0-preview.54/go.mod h1:u9oFiS25TpnU1EW62PQlq22jzkwBAj4VEiiCBM6nhHo=
github.com/onflow/flow-go-sdk v1.0.0-preview.56 h1:ZnFznUXI1V8iZ+cKxoJRIeQwJTHItriKpnoKf8hFFso=
github.com/onflow/flow-go-sdk v1.0.0-preview.56/go.mod h1:rBRNboXaTprn7M0MeO6/R1bxNpctbrx66I2FLp0V6fM=
github.com/onflow/flow-nft/lib/go/contracts v1.2.1 h1:woAAS5z651sDpi7ihAHll8NvRS9uFXIXkL6xR+bKFZY=
github.com/onflow/flow-nft/lib/go/contracts v1.2.1/go.mod h1:2gpbza+uzs1k7x31hkpBPlggIRkI53Suo0n2AyA2HcE=
github.com/onflow/flow-nft/lib/go/templates v1.2.0 h1:JSQyh9rg0RC+D1930BiRXN8lrtMs+ubVMK6aQPon6Yc=
Expand Down
Loading
Loading