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

rpc: implement txpool_contentFrom #9057

Merged
merged 3 commits into from
Dec 28, 2023
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
61 changes: 30 additions & 31 deletions cmd/rpcdaemon/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
- [Introduction](#introduction)
- [Getting Started](#getting-started)
* [Running locally](#running-locally)
* [Running remotely](#running-remotely)
* [Healthcheck](#healthcheck)
* [Testing](#testing)
- [Running locally](#running-locally)
- [Running remotely](#running-remotely)
- [Healthcheck](#healthcheck)
- [Testing](#testing)
- [FAQ](#faq)
* [Relations between prune options and rpc methods](#relations-between-prune-options-and-rpc-method)
* [RPC Implementation Status](#rpc-implementation-status)
* [Securing the communication between RPC daemon and Erigon instance via TLS and authentication](#securing-the-communication-between-rpc-daemon-and-erigon-instance-via-tls-and-authentication)
* [Ethstats](#ethstats)
* [Allowing only specific methods (Allowlist)](#allowing-only-specific-methods--allowlist-)
* [Trace transactions progress](#trace-transactions-progress)
* [Clients getting timeout, but server load is low](#clients-getting-timeout--but-server-load-is-low)
* [Server load too high](#server-load-too-high)
* [Faster Batch requests](#faster-batch-requests)
- [Relations between prune options and rpc methods](#relations-between-prune-options-and-rpc-method)
- [RPC Implementation Status](#rpc-implementation-status)
- [Securing the communication between RPC daemon and Erigon instance via TLS and authentication](#securing-the-communication-between-rpc-daemon-and-erigon-instance-via-tls-and-authentication)
- [Ethstats](#ethstats)
- [Allowing only specific methods (Allowlist)](#allowing-only-specific-methods--allowlist-)
- [Trace transactions progress](#trace-transactions-progress)
- [Clients getting timeout, but server load is low](#clients-getting-timeout--but-server-load-is-low)
- [Server load too high](#server-load-too-high)
- [Faster Batch requests](#faster-batch-requests)
- [For Developers](#for-developers)
* [Code generation](#code-generation)
- [Code generation](#code-generation)

## Introduction

Expand Down Expand Up @@ -72,7 +72,7 @@ it may scale well for some workloads that are heavy on the current state queries

### Healthcheck

There are 2 options for running healtchecks, POST request, or GET request with custom headers. Both options are available
There are 2 options for running healtchecks, POST request, or GET request with custom headers. Both options are available
at the `/health` endpoint.

#### POST request
Expand All @@ -99,7 +99,7 @@ Not adding a check disables that.
`eth` namespace to be listed in `http.api`.

Example request
```http POST http://localhost:8545/health --raw '{"min_peer_count": 3, "known_block": "0x1F"}'```
`http POST http://localhost:8545/health --raw '{"min_peer_count": 3, "known_block": "0x1F"}'`
Example response

```
Expand All @@ -114,19 +114,21 @@ Example response

If the healthcheck is successful it will return a 200 status code.

If the healthcheck fails for any reason a status 500 will be returned. This is true if one of the criteria requested
If the healthcheck fails for any reason a status 500 will be returned. This is true if one of the criteria requested
fails its check.

You can set any number of values on the `X-ERIGON-HEALTHCHECK` header. Ones that are not included are skipped in the
You can set any number of values on the `X-ERIGON-HEALTHCHECK` header. Ones that are not included are skipped in the
checks.

Available Options:

- `synced` - will check if the node has completed syncing
- `min_peer_count<count>` - will check that the node has at least `<count>` many peers
- `check_block<block>` - will check that the node is at least ahead of the `<block>` specified
- `max_seconds_behind<seconds>` - will check that the node is no more than `<seconds>` behind from its latest block

Example Request

```
curl --location --request GET 'http://localhost:8545/health' \
--header 'X-ERIGON-HEALTHCHECK: min_peer_count1' \
Expand All @@ -135,6 +137,7 @@ curl --location --request GET 'http://localhost:8545/health' \
```

Example Response

```
{
"check_block":"DISABLED",
Expand Down Expand Up @@ -194,7 +197,6 @@ If the `--http.url` flag is set, then `--http.addr` and `--http.port` with both

note that this is NOT geth-style IPC. for that, read the next section, IPC endpoint(geth-compatible)


### HTTPS, HTTP2, and H2C

Erigon supports HTTPS, HTTP2, and H2C out of the box. H2C is served by the default HTTP handler.
Expand All @@ -207,7 +209,6 @@ The HTTPS server will inherit all other configuration parameters from http, for

If the `--https.url` flag is set, then `--https.addr` and `--https.port` with both be ignored.


### IPC endpoint (geth compatible)

erigon supports the geth-style unix socket IPC. you can enable this with `--socket.enabled` flag,
Expand All @@ -225,7 +226,7 @@ Label "remote" means: `--private.api.addr` flag is required.
The following table shows the current implementation status of Erigon's RPC daemon.

| Command | Avail | Notes |
| ------------------------------------------ |---------|--------------------------------------|
| ------------------------------------------ | ------- | ------------------------------------ |
| admin_nodeInfo | Yes | |
| admin_peers | Yes | |
| admin_addPeer | Yes | |
Expand Down Expand Up @@ -280,7 +281,7 @@ The following table shows the current implementation status of Erigon's RPC daem
| eth_getFilterChanges | Yes | |
| eth_uninstallFilter | Yes | |
| eth_getLogs | Yes | |
| interned spe | | |
| interned spe | | |
| eth_accounts | No | deprecated |
| eth_sendRawTransaction | Yes | `remote`. |
| eth_sendTransaction | - | not yet implemented |
Expand Down Expand Up @@ -337,6 +338,7 @@ The following table shows the current implementation status of Erigon's RPC daem
| trace_transaction | Yes | |
| | | |
| txpool_content | Yes | `remote` |
| txpool_contentFrom | Yes | `remote` |
| txpool_status | Yes | `remote` |
| | | |
| eth_getCompilers | No | deprecated |
Expand Down Expand Up @@ -371,10 +373,10 @@ The following table shows the current implementation status of Erigon's RPC daem

### GraphQL

| Command | Avail | Notes |
|--------------------------------------------|---------|--------------------------------------|
| GetBlockDetails | Yes | |
| GetChainID | Yes | |
| Command | Avail | Notes |
| --------------- | ----- | ----- |
| GetBlockDetails | Yes | |
| GetChainID | Yes | |

This table is constantly updated. Please visit again.

Expand Down Expand Up @@ -530,10 +532,7 @@ with `rpc.accessList` flag.

```json
{
"allow": [
"net_version",
"web3_eth_getBlockByHash"
]
"allow": ["net_version", "web3_eth_getBlockByHash"]
}
```

Expand Down Expand Up @@ -568,7 +567,7 @@ Currently batch requests are spawn multiple goroutines and process all sub-reque
huge batch to other users - added flag `--rpc.batch.concurrency` (default: 2). Increase it to process large batches
faster.

Known Issue: if at least 1 request is "streamable" (has parameter of type *jsoniter.Stream) - then whole batch will
Known Issue: if at least 1 request is "streamable" (has parameter of type \*jsoniter.Stream) - then whole batch will
processed sequentially (on 1 goroutine).

## For Developers
Expand Down
74 changes: 73 additions & 1 deletion turbo/jsonrpc/txpool_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package jsonrpc
import (
"context"
"fmt"

"github.com/ledgerwatch/erigon-lib/common/hexutil"

libcommon "github.com/ledgerwatch/erigon-lib/common"
Expand All @@ -14,9 +15,10 @@ import (
"github.com/ledgerwatch/erigon/core/types"
)

// NetAPI the interface for the net_ RPC commands
// TxPoolAPI the interface for the txpool_ RPC commands
type TxPoolAPI interface {
Content(ctx context.Context) (map[string]map[string]map[string]*RPCTransaction, error)
ContentFrom(ctx context.Context, addr libcommon.Address) (map[string]map[string]*RPCTransaction, error)
}

// TxPoolAPIImpl data structure to store things needed for net_ commands
Expand Down Expand Up @@ -116,6 +118,76 @@ func (api *TxPoolAPIImpl) Content(ctx context.Context) (map[string]map[string]ma
return content, nil
}

func (api *TxPoolAPIImpl) ContentFrom(ctx context.Context, addr libcommon.Address) (map[string]map[string]*RPCTransaction, error) {
reply, err := api.pool.All(ctx, &proto_txpool.AllRequest{})
if err != nil {
return nil, err
}

content := map[string]map[string]*RPCTransaction{
"pending": make(map[string]*RPCTransaction),
"baseFee": make(map[string]*RPCTransaction),
"queued": make(map[string]*RPCTransaction),
}

pending := make([]types.Transaction, 0, 4)
baseFee := make([]types.Transaction, 0, 4)
queued := make([]types.Transaction, 0, 4)
for i := range reply.Txs {
txn, err := types.DecodeWrappedTransaction(reply.Txs[i].RlpTx)
if err != nil {
return nil, fmt.Errorf("decoding transaction from: %x: %w", reply.Txs[i].RlpTx, err)
}
sender := gointerfaces.ConvertH160toAddress(reply.Txs[i].Sender)
if sender != addr {
continue
}

switch reply.Txs[i].TxnType {
case proto_txpool.AllReply_PENDING:
pending = append(pending, txn)
case proto_txpool.AllReply_BASE_FEE:
baseFee = append(baseFee, txn)
case proto_txpool.AllReply_QUEUED:
queued = append(queued, txn)
}
}

tx, err := api.db.BeginRo(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback()
cc, err := api.chainConfig(tx)
if err != nil {
return nil, err
}

curHeader := rawdb.ReadCurrentHeader(tx)
if curHeader == nil {
return nil, nil
}
// Flatten the pending transactions
dump := make(map[string]*RPCTransaction)
for _, txn := range pending {
dump[fmt.Sprintf("%d", txn.GetNonce())] = newRPCPendingTransaction(txn, curHeader, cc)
}
content["pending"] = dump
// Flatten the baseFee transactions
dump = make(map[string]*RPCTransaction)
for _, txn := range baseFee {
dump[fmt.Sprintf("%d", txn.GetNonce())] = newRPCPendingTransaction(txn, curHeader, cc)
}
content["baseFee"] = dump
// Flatten the queued transactions
dump = make(map[string]*RPCTransaction)
for _, txn := range queued {
dump[fmt.Sprintf("%d", txn.GetNonce())] = newRPCPendingTransaction(txn, curHeader, cc)
}
content["queued"] = dump
return content, nil
}

// Status returns the number of pending and queued transaction in the pool.
func (api *TxPoolAPIImpl) Status(ctx context.Context) (map[string]hexutil.Uint, error) {
reply, err := api.pool.Status(ctx, &proto_txpool.StatusRequest{})
Expand Down
Loading