rpc: implement txpool_contentFrom (#9057)

implement the `txpool_contentFrom` rpc, used to retrieve the specified
address's tx contents.

---------

Signed-off-by: jsvisa <delweng@gmail.com>
This commit is contained in:
Delweng 2023-12-28 15:15:16 +08:00 committed by GitHub
parent 79ed8cad35
commit 398bcb50a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 32 deletions

View File

@ -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
@ -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
@ -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
```
@ -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' \
@ -135,6 +137,7 @@ curl --location --request GET 'http://localhost:8545/health' \
```
Example Response
```
{
"check_block":"DISABLED",
@ -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.
@ -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,
@ -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 | |
@ -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 |
@ -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 |
@ -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.
@ -530,10 +532,7 @@ with `rpc.accessList` flag.
```json
{
"allow": [
"net_version",
"web3_eth_getBlockByHash"
]
"allow": ["net_version", "web3_eth_getBlockByHash"]
}
```
@ -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

View File

@ -3,6 +3,7 @@ package jsonrpc
import (
"context"
"fmt"
"github.com/ledgerwatch/erigon-lib/common/hexutil"
libcommon "github.com/ledgerwatch/erigon-lib/common"
@ -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
@ -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{})