diff --git a/mempool/mempool.go b/mempool/mempool.go index 963a89591..0b0c12056 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -459,7 +459,7 @@ func (mp *TxPool) removeTransactions(txs []*util.Tx) error { for _, tx := range txs { txID := tx.ID() - if _, exists := mp.fetchTransaction(txID); !exists { + if _, exists := mp.fetchTxDesc(txID); !exists { continue } @@ -498,7 +498,7 @@ func (mp *TxPool) removeTransaction(tx *util.Tx, removeDependants bool, restoreI } } - if _, exists := mp.fetchTransaction(txID); !exists { + if _, exists := mp.fetchTxDesc(txID); !exists { return nil } @@ -535,7 +535,7 @@ func (mp *TxPool) removeTransactionWithDiff(tx *util.Tx, diff *blockdag.UTXODiff return errors.Errorf("could not mark transaction output as unspent: %s", err) } - txDesc, _ := mp.fetchTransaction(txID) + txDesc, _ := mp.fetchTxDesc(txID) if txDesc.depCount == 0 { delete(mp.pool, *txID) } else { @@ -734,7 +734,7 @@ func (mp *TxPool) CheckSpend(op wire.Outpoint) *util.Tx { } // This function MUST be called with the mempool lock held (for reads). -func (mp *TxPool) fetchTransaction(txID *daghash.TxID) (*TxDesc, bool) { +func (mp *TxPool) fetchTxDesc(txID *daghash.TxID) (*TxDesc, bool) { txDesc, exists := mp.pool[*txID] if !exists { txDesc, exists = mp.depends[*txID] @@ -742,6 +742,22 @@ func (mp *TxPool) fetchTransaction(txID *daghash.TxID) (*TxDesc, bool) { return txDesc, exists } +// FetchTxDesc returns the requested TxDesc from the transaction pool. +// This only fetches from the main transaction pool and does not include +// orphans. +// +// This function is safe for concurrent access. +func (mp *TxPool) FetchTxDesc(txID *daghash.TxID) (*TxDesc, error) { + mp.mtx.RLock() + defer mp.mtx.RUnlock() + + if txDesc, exists := mp.fetchTxDesc(txID); exists { + return txDesc, nil + } + + return nil, errors.Errorf("transaction is not in the pool") +} + // FetchTransaction returns the requested transaction from the transaction pool. // This only fetches from the main transaction pool and does not include // orphans. @@ -752,7 +768,7 @@ func (mp *TxPool) FetchTransaction(txID *daghash.TxID) (*util.Tx, error) { mp.mtx.RLock() defer mp.mtx.RUnlock() - if txDesc, exists := mp.fetchTransaction(txID); exists { + if txDesc, exists := mp.fetchTxDesc(txID); exists { return txDesc.Tx, nil } diff --git a/rpcmodel/rpc_results.go b/rpcmodel/rpc_results.go index 895d89a12..68d767995 100644 --- a/rpcmodel/rpc_results.go +++ b/rpcmodel/rpc_results.go @@ -171,23 +171,12 @@ type GetBlockTemplateResult struct { RejectReasion string `json:"rejectReason,omitempty"` } -// GetMempoolEntryResult models the data returned from the getmempoolentry +// GetMempoolEntryResult models the data returned from the getMempoolEntry // command. type GetMempoolEntryResult struct { - Size int32 `json:"size"` - Fee float64 `json:"fee"` - ModifiedFee float64 `json:"modifiedFee"` - Time int64 `json:"time"` - Height uint64 `json:"height"` - StartingPriority float64 `json:"startingPriority"` - CurrentPriority float64 `json:"currentPriority"` - DescendantCount int64 `json:"descendantCount"` - DescendantSize int64 `json:"descendantSize"` - DescendantFees float64 `json:"descendantFees"` - AncestorCount int64 `json:"ancestorCount"` - AncestorSize int64 `json:"ancestorSize"` - AncestorFees float64 `json:"ancestorFees"` - Depends []string `json:"depends"` + Fee uint64 `json:"fee"` + Time int64 `json:"time"` + RawTx TxRawResult `json:"rawTx"` } // GetMempoolInfoResult models the data returned from the getmempoolinfo diff --git a/server/rpc/handle_get_mempool_entry.go b/server/rpc/handle_get_mempool_entry.go new file mode 100644 index 000000000..67a554a5f --- /dev/null +++ b/server/rpc/handle_get_mempool_entry.go @@ -0,0 +1,32 @@ +package rpc + +import ( + "github.com/kaspanet/kaspad/rpcmodel" + "github.com/kaspanet/kaspad/util/daghash" +) + +func handleGetMempoolEntry(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + c := cmd.(*rpcmodel.GetMempoolEntryCmd) + txID, err := daghash.NewTxIDFromStr(c.TxID) + if err != nil { + return nil, err + } + + txDesc, err := s.cfg.TxMemPool.FetchTxDesc(txID) + if err != nil { + return nil, err + } + + tx := txDesc.Tx + rawTx, err := createTxRawResult(s.cfg.DAGParams, tx.MsgTx(), tx.ID().String(), + nil, "", nil, true) + if err != nil { + return nil, err + } + + return &rpcmodel.GetMempoolEntryResult{ + Fee: txDesc.Fee, + Time: txDesc.Added.Unix(), + RawTx: *rawTx, + }, nil +} diff --git a/server/rpc/rpcserver.go b/server/rpc/rpcserver.go index 1b24096f4..54dbb8b4c 100644 --- a/server/rpc/rpcserver.go +++ b/server/rpc/rpcserver.go @@ -82,6 +82,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "getInfo": handleGetInfo, "getManualNodeInfo": handleGetManualNodeInfo, "getMempoolInfo": handleGetMempoolInfo, + "getMempoolEntry": handleGetMempoolEntry, "getNetTotals": handleGetNetTotals, "getPeerInfo": handleGetPeerInfo, "getRawMempool": handleGetRawMempool, diff --git a/server/rpc/rpcserverhelp.go b/server/rpc/rpcserverhelp.go index 5c4e4d81e..93d965598 100644 --- a/server/rpc/rpcserverhelp.go +++ b/server/rpc/rpcserverhelp.go @@ -227,7 +227,7 @@ var helpDescsEnUS = map[string]string{ "txRawResult-time": "Transaction time in seconds since 1 Jan 1970 GMT", "txRawResult-blockTime": "Block time in seconds since the 1 Jan 1970 GMT", "txRawResult-size": "The size of the transaction in bytes", - "txRawResult-hash": "The wtxid of the transaction", + "txRawResult-hash": "The hash of the transaction", "txRawResult-acceptedBy": "The block in which the transaction got accepted in", // GetBlockVerboseResult help. @@ -390,6 +390,15 @@ var helpDescsEnUS = map[string]string{ // GetInfoCmd help. "getInfo--synopsis": "Returns a JSON object containing various state info.", + // getMempoolEntry help. + "getMempoolEntry--synopsis": "Returns mempool data for given transaction", + "getMempoolEntry-txId": "The transaction ID", + + // getMempoolEntryResult help. + "getMempoolEntryResult-fee": "Transaction fee in sompis", + "getMempoolEntryResult-time": "Local time transaction entered pool in seconds since 1 Jan 1970 GMT", + "getMempoolEntryResult-rawTx": "The transaction as a JSON object", + // GetMempoolInfoCmd help. "getMempoolInfo--synopsis": "Returns memory pool information", @@ -603,6 +612,7 @@ var rpcResultTypes = map[string][]interface{}{ "getInfo": {(*rpcmodel.InfoDAGResult)(nil)}, "getManualNodeInfo": {(*string)(nil), (*rpcmodel.GetManualNodeInfoResult)(nil)}, "getMempoolInfo": {(*rpcmodel.GetMempoolInfoResult)(nil)}, + "getMempoolEntry": {(*rpcmodel.GetMempoolEntryResult)(nil)}, "getNetTotals": {(*rpcmodel.GetNetTotalsResult)(nil)}, "getPeerInfo": {(*[]rpcmodel.GetPeerInfoResult)(nil)}, "getRawMempool": {(*[]string)(nil), (*rpcmodel.GetRawMempoolVerboseResult)(nil)},