Add the starting+current priority to getrawmempool.
This commit is contained in:
parent
c36b00c078
commit
a49b0d05b3
3 changed files with 101 additions and 29 deletions
64
mempool.go
64
mempool.go
|
@ -85,6 +85,7 @@ type TxDesc struct {
|
|||
Added time.Time // Time when added to pool.
|
||||
Height int64 // Blockheight when added to pool.
|
||||
Fee int64 // Transaction fees.
|
||||
startingPriority float64 // Priority when added to the pool.
|
||||
}
|
||||
|
||||
// txMemPool is used as a source of transactions that need to be mined into
|
||||
|
@ -670,6 +671,69 @@ func (mp *txMemPool) addTransaction(tx *btcutil.Tx, height, fee int64) {
|
|||
mp.lastUpdated = time.Now()
|
||||
}
|
||||
|
||||
// StartingPriority calculates the priority of this tx descriptor's
|
||||
// underlying transaction relative to when it was first added to the mempool.
|
||||
// The result is lazily computed and then cached for subsequent function
|
||||
// calls.
|
||||
func (txD *TxDesc) StartingPriority(txStore btcchain.TxStore) float64 {
|
||||
// Return our cached result.
|
||||
if txD.startingPriority != float64(0) {
|
||||
return txD.startingPriority
|
||||
}
|
||||
|
||||
// Compute our starting priority caching the result.
|
||||
inputAge := calcInputValueAge(txD, txStore, txD.Height)
|
||||
txSize := txD.Tx.MsgTx().SerializeSize()
|
||||
txD.startingPriority = calcPriority(txD.Tx, txSize, inputAge)
|
||||
|
||||
return txD.startingPriority
|
||||
}
|
||||
|
||||
// CurrentPriority calculates the current priority of this tx descriptor's
|
||||
// underlying transaction relative to the next block height.
|
||||
func (txD *TxDesc) CurrentPriority(txStore btcchain.TxStore, nextBlockHeight int64) float64 {
|
||||
inputAge := calcInputValueAge(txD, txStore, nextBlockHeight)
|
||||
txSize := txD.Tx.MsgTx().SerializeSize()
|
||||
return calcPriority(txD.Tx, txSize, inputAge)
|
||||
}
|
||||
|
||||
// calcInputValueAge is a helper function used to calculate the input age of
|
||||
// a transaction. The input age for a txin is the number of confirmations
|
||||
// since the referenced txout multiplied by its output value.
|
||||
// The total input age is the sum of this value for each txin. If the tx
|
||||
// depends on one currently in the mempool, then its input age is zero.
|
||||
func calcInputValueAge(txDesc *TxDesc, txStore btcchain.TxStore,
|
||||
nextBlockHeight int64) float64 {
|
||||
var totalInputAge float64
|
||||
for _, txIn := range txDesc.Tx.MsgTx().TxIn {
|
||||
originHash := &txIn.PreviousOutPoint.Hash
|
||||
originIndex := txIn.PreviousOutPoint.Index
|
||||
|
||||
// Don't attempt to accumulate the total input age if the txIn
|
||||
// in question doesn't exist.
|
||||
if txData, exists := txStore[*originHash]; exists && txData.Tx != nil {
|
||||
originTxOut := txData.Tx.MsgTx().TxOut[originIndex]
|
||||
|
||||
// Transactions with dependencies currently in the
|
||||
// mempool have their block height set to a special
|
||||
// constant. Their input age should computed as zero
|
||||
// since their parent hasn't made it into a block yet.
|
||||
var inputAge int64
|
||||
if txData.BlockHeight == mempoolHeight {
|
||||
inputAge = 0
|
||||
} else {
|
||||
inputAge = nextBlockHeight - txData.BlockHeight
|
||||
}
|
||||
|
||||
// Sum the input value times age.
|
||||
inputValue := originTxOut.Value
|
||||
totalInputAge += float64(inputValue * inputAge)
|
||||
}
|
||||
}
|
||||
|
||||
return totalInputAge
|
||||
}
|
||||
|
||||
// checkPoolDoubleSpend checks whether or not the passed transaction is
|
||||
// attempting to spend coins already spent by other transactions in the pool.
|
||||
// Note it does not check for double spends against transactions already in the
|
||||
|
|
26
mining.go
26
mining.go
|
@ -513,15 +513,10 @@ mempoolLoop:
|
|||
continue
|
||||
}
|
||||
|
||||
// Calculate the input value age sum for the transaction. This
|
||||
// is comprised of the sum all of input amounts multiplied by
|
||||
// their respective age (number of confirmations since the
|
||||
// referenced input transaction). While doing the above, also
|
||||
// setup dependencies for any transactions which reference other
|
||||
// transactions in the mempool so they can be properly ordered
|
||||
// below.
|
||||
// Setup dependencies for any transactions which reference
|
||||
// other transactions in the mempool so they can be properly
|
||||
// ordered below.
|
||||
prioItem := &txPrioItem{tx: txDesc.Tx}
|
||||
inputValueAge := float64(0.0)
|
||||
for _, txIn := range tx.MsgTx().TxIn {
|
||||
originHash := &txIn.PreviousOutPoint.Hash
|
||||
originIndex := txIn.PreviousOutPoint.Index
|
||||
|
@ -550,9 +545,8 @@ mempoolLoop:
|
|||
}
|
||||
prioItem.dependsOn[*originHash] = struct{}{}
|
||||
|
||||
// No need to calculate or sum input value age
|
||||
// for this input since it's zero due to
|
||||
// the input age multiplier of 0.
|
||||
// Skip the check below. We already know the
|
||||
// referenced transaction is available.
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -566,25 +560,19 @@ mempoolLoop:
|
|||
originIndex, originHash)
|
||||
continue mempoolLoop
|
||||
}
|
||||
|
||||
// Sum the input value times age.
|
||||
originTxOut := txData.Tx.MsgTx().TxOut[originIndex]
|
||||
inputValue := originTxOut.Value
|
||||
inputAge := nextBlockHeight - txData.BlockHeight
|
||||
inputValueAge += float64(inputValue * inputAge)
|
||||
}
|
||||
|
||||
// Calculate the final transaction priority using the input
|
||||
// value age sum as well as the adjusted transaction size. The
|
||||
// formula is: sum(inputValue * inputAge) / adjustedTxSize
|
||||
txSize := tx.MsgTx().SerializeSize()
|
||||
prioItem.priority = calcPriority(tx, txSize, inputValueAge)
|
||||
prioItem.priority = txDesc.CurrentPriority(txStore, nextBlockHeight)
|
||||
|
||||
// Calculate the fee in Satoshi/KB.
|
||||
// NOTE: This is a more precise value than the one calculated
|
||||
// during calcMinRelayFee which rounds up to the nearest full
|
||||
// kilobyte boundary. This is beneficial since it provides an
|
||||
// incentive to create smaller transactions.
|
||||
txSize := tx.MsgTx().SerializeSize()
|
||||
prioItem.feePerKB = float64(txDesc.Fee) / (float64(txSize) / 1000)
|
||||
prioItem.fee = txDesc.Fee
|
||||
|
||||
|
|
30
rpcserver.go
30
rpcserver.go
|
@ -2290,19 +2290,39 @@ func handleGetPeerInfo(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{})
|
|||
// handleGetRawMempool implements the getrawmempool command.
|
||||
func handleGetRawMempool(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (interface{}, error) {
|
||||
c := cmd.(*btcjson.GetRawMempoolCmd)
|
||||
descs := s.server.txMemPool.TxDescs()
|
||||
mp := s.server.txMemPool
|
||||
descs := mp.TxDescs()
|
||||
|
||||
if c.Verbose {
|
||||
result := make(map[string]*btcjson.GetRawMempoolResult, len(descs))
|
||||
|
||||
_, newestHeight, err := s.server.db.NewestSha()
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("Cannot get newest sha: %v", err)
|
||||
return nil, btcjson.ErrBlockNotFound
|
||||
}
|
||||
|
||||
mp.RLock()
|
||||
defer mp.RUnlock()
|
||||
for _, desc := range descs {
|
||||
// Calculate the starting and ending priority from the
|
||||
// the tx's inputs. If we can't find the input for some
|
||||
// reason, then we display zero in place.
|
||||
inputTxs, err := mp.fetchInputTransactions(desc.Tx)
|
||||
var startingPriority, endingPriority float64
|
||||
if err == nil {
|
||||
startingPriority = desc.StartingPriority(inputTxs)
|
||||
endingPriority = desc.CurrentPriority(inputTxs,
|
||||
newestHeight+1)
|
||||
}
|
||||
|
||||
mpd := &btcjson.GetRawMempoolResult{
|
||||
Size: int32(desc.Tx.MsgTx().SerializeSize()),
|
||||
Fee: float64(desc.Fee) /
|
||||
btcutil.SatoshiPerBitcoin,
|
||||
Fee: btcutil.Amount(desc.Fee).ToUnit(btcutil.AmountSatoshi),
|
||||
Time: desc.Added.Unix(),
|
||||
Height: desc.Height,
|
||||
StartingPriority: 0, // We don't mine.
|
||||
CurrentPriority: 0, // We don't mine.
|
||||
StartingPriority: startingPriority,
|
||||
CurrentPriority: endingPriority,
|
||||
Depends: make([]string, 0),
|
||||
}
|
||||
for _, txIn := range desc.Tx.MsgTx().TxIn {
|
||||
|
|
Loading…
Reference in a new issue