2021-06-11 08:34:47 +00:00
|
|
|
|
package commands
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
|
2023-01-13 18:12:18 +00:00
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
2022-04-28 08:35:14 +00:00
|
|
|
|
"github.com/ledgerwatch/erigon-lib/gointerfaces"
|
2021-07-01 21:31:14 +00:00
|
|
|
|
proto_txpool "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool"
|
2021-07-29 11:53:13 +00:00
|
|
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
2023-01-13 18:12:18 +00:00
|
|
|
|
|
2021-08-06 02:45:44 +00:00
|
|
|
|
"github.com/ledgerwatch/erigon/common/hexutil"
|
2021-07-22 14:21:55 +00:00
|
|
|
|
"github.com/ledgerwatch/erigon/core/rawdb"
|
2021-06-11 08:34:47 +00:00
|
|
|
|
"github.com/ledgerwatch/erigon/core/types"
|
|
|
|
|
"github.com/ledgerwatch/erigon/rlp"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// NetAPI the interface for the net_ RPC commands
|
|
|
|
|
type TxPoolAPI interface {
|
|
|
|
|
Content(ctx context.Context) (map[string]map[string]map[string]*RPCTransaction, error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TxPoolAPIImpl data structure to store things needed for net_ commands
|
|
|
|
|
type TxPoolAPIImpl struct {
|
|
|
|
|
*BaseAPI
|
|
|
|
|
pool proto_txpool.TxpoolClient
|
2021-07-28 02:47:38 +00:00
|
|
|
|
db kv.RoDB
|
2021-06-11 08:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewTxPoolAPI returns NetAPIImplImpl instance
|
2021-07-28 02:47:38 +00:00
|
|
|
|
func NewTxPoolAPI(base *BaseAPI, db kv.RoDB, pool proto_txpool.TxpoolClient) *TxPoolAPIImpl {
|
2021-06-11 08:34:47 +00:00
|
|
|
|
return &TxPoolAPIImpl{
|
|
|
|
|
BaseAPI: base,
|
|
|
|
|
pool: pool,
|
|
|
|
|
db: db,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (api *TxPoolAPIImpl) Content(ctx context.Context) (map[string]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]map[string]*RPCTransaction{
|
|
|
|
|
"pending": make(map[string]map[string]*RPCTransaction),
|
2021-10-13 04:04:59 +00:00
|
|
|
|
"baseFee": make(map[string]map[string]*RPCTransaction),
|
2021-06-11 08:34:47 +00:00
|
|
|
|
"queued": make(map[string]map[string]*RPCTransaction),
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-13 18:12:18 +00:00
|
|
|
|
pending := make(map[libcommon.Address][]types.Transaction, 8)
|
|
|
|
|
baseFee := make(map[libcommon.Address][]types.Transaction, 8)
|
|
|
|
|
queued := make(map[libcommon.Address][]types.Transaction, 8)
|
2021-06-11 08:34:47 +00:00
|
|
|
|
for i := range reply.Txs {
|
|
|
|
|
stream := rlp.NewStream(bytes.NewReader(reply.Txs[i].RlpTx), 0)
|
|
|
|
|
txn, err := types.DecodeTransaction(stream)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2022-04-28 08:35:14 +00:00
|
|
|
|
addr := gointerfaces.ConvertH160toAddress(reply.Txs[i].Sender)
|
2022-04-28 08:02:06 +00:00
|
|
|
|
switch reply.Txs[i].TxnType {
|
2021-06-11 08:34:47 +00:00
|
|
|
|
case proto_txpool.AllReply_PENDING:
|
|
|
|
|
if _, ok := pending[addr]; !ok {
|
|
|
|
|
pending[addr] = make([]types.Transaction, 0, 4)
|
|
|
|
|
}
|
|
|
|
|
pending[addr] = append(pending[addr], txn)
|
2021-09-08 05:31:51 +00:00
|
|
|
|
case proto_txpool.AllReply_BASE_FEE:
|
|
|
|
|
if _, ok := baseFee[addr]; !ok {
|
|
|
|
|
baseFee[addr] = make([]types.Transaction, 0, 4)
|
|
|
|
|
}
|
|
|
|
|
baseFee[addr] = append(baseFee[addr], txn)
|
2021-06-11 08:34:47 +00:00
|
|
|
|
case proto_txpool.AllReply_QUEUED:
|
|
|
|
|
if _, ok := queued[addr]; !ok {
|
|
|
|
|
queued[addr] = make([]types.Transaction, 0, 4)
|
|
|
|
|
}
|
|
|
|
|
queued[addr] = append(queued[addr], txn)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tx, err := api.db.BeginRo(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer tx.Rollback()
|
2021-07-22 14:21:55 +00:00
|
|
|
|
cc, err := api.chainConfig(tx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2021-06-11 08:34:47 +00:00
|
|
|
|
|
2021-07-22 14:21:55 +00:00
|
|
|
|
curHeader := rawdb.ReadCurrentHeader(tx)
|
2021-10-25 10:14:45 +00:00
|
|
|
|
if curHeader == nil {
|
2021-10-22 03:10:38 +00:00
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
2021-06-11 08:34:47 +00:00
|
|
|
|
// Flatten the pending transactions
|
|
|
|
|
for account, txs := range pending {
|
|
|
|
|
dump := make(map[string]*RPCTransaction)
|
|
|
|
|
for _, txn := range txs {
|
2021-07-22 14:21:55 +00:00
|
|
|
|
dump[fmt.Sprintf("%d", txn.GetNonce())] = newRPCPendingTransaction(txn, curHeader, cc)
|
2021-06-11 08:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
content["pending"][account.Hex()] = dump
|
|
|
|
|
}
|
2021-09-08 05:31:51 +00:00
|
|
|
|
// Flatten the baseFee transactions
|
|
|
|
|
for account, txs := range baseFee {
|
|
|
|
|
dump := make(map[string]*RPCTransaction)
|
|
|
|
|
for _, txn := range txs {
|
|
|
|
|
dump[fmt.Sprintf("%d", txn.GetNonce())] = newRPCPendingTransaction(txn, curHeader, cc)
|
|
|
|
|
}
|
|
|
|
|
content["baseFee"][account.Hex()] = dump
|
|
|
|
|
}
|
2021-06-11 08:34:47 +00:00
|
|
|
|
// Flatten the queued transactions
|
|
|
|
|
for account, txs := range queued {
|
|
|
|
|
dump := make(map[string]*RPCTransaction)
|
|
|
|
|
for _, txn := range txs {
|
2021-07-22 14:21:55 +00:00
|
|
|
|
dump[fmt.Sprintf("%d", txn.GetNonce())] = newRPCPendingTransaction(txn, curHeader, cc)
|
2021-06-11 08:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
content["queued"][account.Hex()] = dump
|
|
|
|
|
}
|
|
|
|
|
return content, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Status returns the number of pending and queued transaction in the pool.
|
2021-08-06 02:45:44 +00:00
|
|
|
|
func (api *TxPoolAPIImpl) Status(ctx context.Context) (map[string]hexutil.Uint, error) {
|
|
|
|
|
reply, err := api.pool.Status(ctx, &proto_txpool.StatusRequest{})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2021-06-11 08:34:47 +00:00
|
|
|
|
}
|
2021-08-06 02:45:44 +00:00
|
|
|
|
return map[string]hexutil.Uint{
|
|
|
|
|
"pending": hexutil.Uint(reply.PendingCount),
|
2021-09-08 05:31:51 +00:00
|
|
|
|
"baseFee": hexutil.Uint(reply.BaseFeeCount),
|
2021-08-06 02:45:44 +00:00
|
|
|
|
"queued": hexutil.Uint(reply.QueuedCount),
|
|
|
|
|
}, nil
|
2021-06-11 08:34:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-06 02:45:44 +00:00
|
|
|
|
/*
|
|
|
|
|
|
2021-06-11 08:34:47 +00:00
|
|
|
|
// Inspect retrieves the content of the transaction pool and flattens it into an
|
|
|
|
|
// easily inspectable list.
|
|
|
|
|
func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string {
|
|
|
|
|
content := map[string]map[string]map[string]string{
|
|
|
|
|
"pending": make(map[string]map[string]string),
|
|
|
|
|
"queued": make(map[string]map[string]string),
|
|
|
|
|
}
|
|
|
|
|
pending, queue := s.b.TxPoolContent()
|
|
|
|
|
|
|
|
|
|
// Define a formatter to flatten a transaction into a string
|
|
|
|
|
var format = func(tx *types.Transaction) string {
|
|
|
|
|
if to := tx.To(); to != nil {
|
|
|
|
|
return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("contract creation: %v wei + %v gas × %v wei", tx.Value(), tx.Gas(), tx.GasPrice())
|
|
|
|
|
}
|
|
|
|
|
// Flatten the pending transactions
|
|
|
|
|
for account, txs := range pending {
|
|
|
|
|
dump := make(map[string]string)
|
|
|
|
|
for _, tx := range txs {
|
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = format(tx)
|
|
|
|
|
}
|
|
|
|
|
content["pending"][account.Hex()] = dump
|
|
|
|
|
}
|
|
|
|
|
// Flatten the queued transactions
|
|
|
|
|
for account, txs := range queue {
|
|
|
|
|
dump := make(map[string]string)
|
|
|
|
|
for _, tx := range txs {
|
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = format(tx)
|
|
|
|
|
}
|
|
|
|
|
content["queued"][account.Hex()] = dump
|
|
|
|
|
}
|
|
|
|
|
return content
|
|
|
|
|
}
|
|
|
|
|
*/
|