Merge pull request #2098 from karalabe/rpc-txpool-queue-inspection

core, eth, rpc/api: rpc method to inspect the txpool queue
This commit is contained in:
Jeffrey Wilcke 2016-02-02 10:53:23 +01:00
commit 6005dcef5b
3 changed files with 113 additions and 1 deletions

@ -169,6 +169,36 @@ func (pool *TxPool) Stats() (pending int, queued int) {
return return
} }
// Content retrieves the data content of the transaction pool, returning all the
// pending as well as queued transactions, grouped by account and nonce.
func (pool *TxPool) Content() (map[common.Address]map[uint64][]*types.Transaction, map[common.Address]map[uint64][]*types.Transaction) {
pool.mu.RLock()
defer pool.mu.RUnlock()
// Retrieve all the pending transactions and sort by account and by nonce
pending := make(map[common.Address]map[uint64][]*types.Transaction)
for _, tx := range pool.pending {
account, _ := tx.From()
owned, ok := pending[account]
if !ok {
owned = make(map[uint64][]*types.Transaction)
pending[account] = owned
}
owned[tx.Nonce()] = append(owned[tx.Nonce()], tx)
}
// Retrieve all the queued transactions and sort by account and by nonce
queued := make(map[common.Address]map[uint64][]*types.Transaction)
for account, txs := range pool.queue {
owned := make(map[uint64][]*types.Transaction)
for _, tx := range txs {
owned[tx.Nonce()] = append(owned[tx.Nonce()], tx)
}
queued[account] = owned
}
return pending, queued
}
// SetLocal marks a transaction as local, skipping gas price // SetLocal marks a transaction as local, skipping gas price
// check against local miner minimum in the future // check against local miner minimum in the future
func (pool *TxPool) SetLocal(tx *types.Transaction) { func (pool *TxPool) SetLocal(tx *types.Transaction) {

@ -227,6 +227,39 @@ func NewPublicTxPoolAPI(e *Ethereum) *PublicTxPoolAPI {
return &PublicTxPoolAPI{e} return &PublicTxPoolAPI{e}
} }
// Content returns the transactions contained within the transaction pool.
func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string][]*RPCTransaction {
content := map[string]map[string]map[string][]*RPCTransaction{
"pending": make(map[string]map[string][]*RPCTransaction),
"queued": make(map[string]map[string][]*RPCTransaction),
}
pending, queue := s.e.TxPool().Content()
// Flatten the pending transactions
for account, batches := range pending {
dump := make(map[string][]*RPCTransaction)
for nonce, txs := range batches {
nonce := fmt.Sprintf("%d", nonce)
for _, tx := range txs {
dump[nonce] = append(dump[nonce], newRPCPendingTransaction(tx))
}
}
content["pending"][account.Hex()] = dump
}
// Flatten the queued transactions
for account, batches := range queue {
dump := make(map[string][]*RPCTransaction)
for nonce, txs := range batches {
nonce := fmt.Sprintf("%d", nonce)
for _, tx := range txs {
dump[nonce] = append(dump[nonce], newRPCPendingTransaction(tx))
}
}
content["queued"][account.Hex()] = dump
}
return content
}
// Status returns the number of pending and queued transaction in the pool. // Status returns the number of pending and queued transaction in the pool.
func (s *PublicTxPoolAPI) Status() map[string]*rpc.HexNumber { func (s *PublicTxPoolAPI) Status() map[string]*rpc.HexNumber {
pending, queue := s.e.TxPool().Stats() pending, queue := s.e.TxPool().Stats()
@ -236,6 +269,47 @@ func (s *PublicTxPoolAPI) Status() map[string]*rpc.HexNumber {
} }
} }
// 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.e.TxPool().Content()
// 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 × %v gas", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
}
return fmt.Sprintf("contract creation: %v wei + %v × %v gas", tx.Value(), tx.Gas(), tx.GasPrice())
}
// Flatten the pending transactions
for account, batches := range pending {
dump := make(map[string][]string)
for nonce, txs := range batches {
nonce := fmt.Sprintf("%d", nonce)
for _, tx := range txs {
dump[nonce] = append(dump[nonce], format(tx))
}
}
content["pending"][account.Hex()] = dump
}
// Flatten the queued transactions
for account, batches := range queue {
dump := make(map[string][]string)
for nonce, txs := range batches {
nonce := fmt.Sprintf("%d", nonce)
for _, tx := range txs {
dump[nonce] = append(dump[nonce], format(tx))
}
}
content["queued"][account.Hex()] = dump
}
return content
}
// PublicAccountAPI provides an API to access accounts managed by this node. // PublicAccountAPI provides an API to access accounts managed by this node.
// It offers only methods that can retrieve accounts. // It offers only methods that can retrieve accounts.
type PublicAccountAPI struct { type PublicAccountAPI struct {

@ -70,9 +70,17 @@ web3._extend({
], ],
properties: properties:
[ [
new web3._extend.Property({
name: 'content',
getter: 'txpool_content'
}),
new web3._extend.Property({
name: 'inspect',
getter: 'txpool_inspect'
}),
new web3._extend.Property({ new web3._extend.Property({
name: 'status', name: 'status',
getter: 'txpool_status' getter: 'txpool_status',
outputFormatter: function(status) { outputFormatter: function(status) {
status.pending = web3._extend.utils.toDecimal(status.pending); status.pending = web3._extend.utils.toDecimal(status.pending);
status.queued = web3._extend.utils.toDecimal(status.queued); status.queued = web3._extend.utils.toDecimal(status.queued);