erigon-pulse/cmd/rpcdaemon/commands/txpool_api.go

167 lines
5.0 KiB
Go
Raw Normal View History

package commands
import (
"bytes"
"context"
"fmt"
proto_txpool "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool"
2021-07-29 11:53:13 +00:00
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/hexutil"
2021-07-22 14:21:55 +00:00
"github.com/ledgerwatch/erigon/core/rawdb"
"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
db kv.RoDB
}
// NewTxPoolAPI returns NetAPIImplImpl instance
func NewTxPoolAPI(base *BaseAPI, db kv.RoDB, pool proto_txpool.TxpoolClient) *TxPoolAPIImpl {
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),
"baseFee": make(map[string]map[string]*RPCTransaction),
"queued": make(map[string]map[string]*RPCTransaction),
}
pending := make(map[common.Address][]types.Transaction, 8)
2021-09-08 05:31:51 +00:00
baseFee := make(map[common.Address][]types.Transaction, 8)
queued := make(map[common.Address][]types.Transaction, 8)
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
}
addr := common.BytesToAddress(reply.Txs[i].Sender)
switch reply.Txs[i].Type {
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)
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-07-22 14:21:55 +00:00
curHeader := rawdb.ReadCurrentHeader(tx)
// 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)
}
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
}
// 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)
}
content["queued"][account.Hex()] = 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{})
if err != nil {
return nil, err
}
return map[string]hexutil.Uint{
"pending": hexutil.Uint(reply.PendingCount),
2021-09-08 05:31:51 +00:00
"baseFee": hexutil.Uint(reply.BaseFeeCount),
"queued": hexutil.Uint(reply.QueuedCount),
}, nil
}
/*
// 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
}
*/