Add support for verbose in getrawmempool.

Closes #55.
This commit is contained in:
Owain G. Ainsworth 2013-12-11 17:32:16 +00:00
parent e4fa45ff08
commit 8aaad1e97b
3 changed files with 92 additions and 16 deletions

View File

@ -78,13 +78,22 @@ const (
blockPrioritySize = 27000
)
// TxDesc is a descriptor containing a transaction in the mempool and the
// metadata we store about it.
type TxDesc struct {
Tx *btcutil.Tx // Transaction.
Added time.Time // Time when added to pool.
Height int64 // Blockheight when added to pool.
Fee int64 // Transaction fees.
}
// txMemPool is used as a source of transactions that need to be mined into
// blocks and relayed to other peers. It is safe for concurrent access from
// multiple peers.
type txMemPool struct {
sync.RWMutex
server *server
pool map[btcwire.ShaHash]*btcutil.Tx
pool map[btcwire.ShaHash]*TxDesc
orphans map[btcwire.ShaHash]*btcutil.Tx
orphansByPrev map[btcwire.ShaHash]*list.List
outpoints map[btcwire.OutPoint]*btcutil.Tx
@ -581,8 +590,8 @@ func (mp *txMemPool) removeTransaction(tx *btcutil.Tx) {
// Remove the transaction and mark the referenced outpoints as unspent
// by the pool.
if tx, exists := mp.pool[*txHash]; exists {
for _, txIn := range tx.MsgTx().TxIn {
if txDesc, exists := mp.pool[*txHash]; exists {
for _, txIn := range txDesc.Tx.MsgTx().TxIn {
delete(mp.outpoints, txIn.PreviousOutpoint)
}
delete(mp.pool, *txHash)
@ -627,10 +636,15 @@ func (mp *txMemPool) RemoveDoubleSpends(tx *btcutil.Tx) {
// helper for maybeAcceptTransaction.
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *txMemPool) addTransaction(tx *btcutil.Tx) {
func (mp *txMemPool) addTransaction(tx *btcutil.Tx, height, fee int64) {
// Add the transaction to the pool and mark the referenced outpoints
// as spent by the pool.
mp.pool[*tx.Sha()] = tx
mp.pool[*tx.Sha()] = &TxDesc{
Tx: tx,
Added: time.Now(),
Height: height,
Fee: fee,
}
for _, txIn := range tx.MsgTx().TxIn {
mp.outpoints[txIn.PreviousOutpoint] = tx
}
@ -668,7 +682,8 @@ func (mp *txMemPool) fetchInputTransactions(tx *btcutil.Tx) (btcchain.TxStore, e
// Attempt to populate any missing inputs from the transaction pool.
for _, txD := range txStore {
if txD.Err == btcdb.TxShaMissing || txD.Tx == nil {
if poolTx, exists := mp.pool[*txD.Hash]; exists {
if poolTxDesc, exists := mp.pool[*txD.Hash]; exists {
poolTx := poolTxDesc.Tx
txD.Tx = poolTx
txD.BlockHeight = mempoolHeight
txD.Spent = make([]bool, len(poolTx.MsgTx().TxOut))
@ -690,8 +705,8 @@ func (mp *txMemPool) FetchTransaction(txHash *btcwire.ShaHash) (*btcutil.Tx, err
mp.RLock()
defer mp.RUnlock()
if tx, exists := mp.pool[*txHash]; exists {
return tx, nil
if txDesc, exists := mp.pool[*txHash]; exists {
return txDesc.Tx, nil
}
return nil, fmt.Errorf("transaction is not in the pool")
@ -856,7 +871,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isOrphan *bool) erro
}
// Add to transaction pool.
mp.addTransaction(tx)
mp.addTransaction(tx, nextBlockHeight-1, txFee)
txmpLog.Debugf("Accepted transaction %v (pool size: %v)", txHash,
len(mp.pool))
@ -1005,12 +1020,30 @@ func (mp *txMemPool) TxShas() []*btcwire.ShaHash {
return hashes
}
// TxDescs returns a slice of descriptors for all the transactions in the pool.
// The descriptors are to be treated as read only.
//
// This function is safe for concurrent access.
func (mp *txMemPool) TxDescs() []*TxDesc {
mp.RLock()
defer mp.RUnlock()
descs := make([]*TxDesc, len(mp.pool))
i := 0
for _, desc := range mp.pool {
descs[i] = desc
i++
}
return descs
}
// newTxMemPool returns a new memory pool for validating and storing standalone
// transactions until they are mined into a block.
func newTxMemPool(server *server) *txMemPool {
return &txMemPool{
server: server,
pool: make(map[btcwire.ShaHash]*btcutil.Tx),
pool: make(map[btcwire.ShaHash]*TxDesc),
orphans: make(map[btcwire.ShaHash]*btcutil.Tx),
orphansByPrev: make(map[btcwire.ShaHash]*list.List),
outpoints: make(map[btcwire.OutPoint]*btcutil.Tx),

View File

@ -870,13 +870,52 @@ func handleGetPeerInfo(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []
return s.server.PeerInfo(), nil
}
type mempoolDescriptor struct {
Size int `json:"size"`
Fee int64 `json:"fee"`
Time int64 `json:"time"`
Height int64 `json:"height"`
StartingPriority int `json:"startingpriority"`
CurrentPriority int `json:"currentpriority"`
Depends []string `json:"depends"`
}
// handleGetRawMempool implements the getrawmempool command.
func handleGetRawMempool(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) {
hashes := s.server.txMemPool.TxShas()
hashStrings := make([]string, len(hashes))
for i := 0; i < len(hashes); i++ {
hashStrings[i] = hashes[i].String()
c := cmd.(*btcjson.GetRawMempoolCmd)
descs := s.server.txMemPool.TxDescs()
if c.Verbose {
result := make(map[string]*mempoolDescriptor, len(descs))
for _, desc := range descs {
mpd := &mempoolDescriptor{
Size: desc.Tx.MsgTx().SerializeSize(),
Fee: desc.Fee,
Time: desc.Added.Unix(),
Height: desc.Height,
StartingPriority: 0, // We don't mine.
CurrentPriority: 0, // We don't mine.
}
for _, txIn := range desc.Tx.MsgTx().TxIn {
hash := &txIn.PreviousOutpoint.Hash
if s.server.txMemPool.HaveTransaction(hash) {
mpd.Depends = append(mpd.Depends,
hash.String())
}
}
result[desc.Tx.Sha().String()] = mpd
}
return result, nil
}
hashStrings := make([]string, len(descs))
for i := range(hashStrings) {
hashStrings[i] = descs[i].Tx.Sha().String()
}
return hashStrings, nil
}

View File

@ -56,7 +56,7 @@ var commandHandlers = map[string]*handlerData{
"getdifficulty": &handlerData{0, 0, displayFloat64, nil, makeGetDifficulty, ""},
"getgenerate": &handlerData{0, 0, displayGeneric, nil, makeGetGenerate, ""},
"getpeerinfo": &handlerData{0, 0, displaySpewDump, nil, makeGetPeerInfo, ""},
"getrawmempool": &handlerData{0, 0, displaySpewDump, nil, makeGetRawMempool, ""},
"getrawmempool": &handlerData{0, 1, displaySpewDump, []conversionHandler{toBool}, makeGetRawMempool, "[verbose=false]"},
"getrawtransaction": &handlerData{1, 1, displaySpewDump, []conversionHandler{nil, toInt}, makeGetRawTransaction, "<txhash> [verbose=0]"},
"importprivkey": &handlerData{1, 2, displayGeneric, []conversionHandler{nil, nil, toBool}, makeImportPrivKey, "<wifprivkey> [label] [rescan=true]"},
"listtransactions": &handlerData{0, 3, displaySpewDump, []conversionHandler{nil, toInt, toInt}, makeListTransactions, "[account] [count=10] [from=0]"},
@ -209,7 +209,11 @@ func makeGetPeerInfo(args []interface{}) (btcjson.Cmd, error) {
// makeRawMempool generates the cmd structure for
// getrawmempool comands.
func makeGetRawMempool(args []interface{}) (btcjson.Cmd, error) {
return btcjson.NewGetRawMempoolCmd("btcctl")
opt := make([]bool, 0, 1)
if len(args) > 0 {
opt = append(opt, args[0].(bool))
}
return btcjson.NewGetRawMempoolCmd("btcctl", opt...)
}
// makeRawTransaction generates the cmd structure for