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
72
mempool.go
72
mempool.go
|
@ -81,10 +81,11 @@ const (
|
||||||
// TxDesc is a descriptor containing a transaction in the mempool and the
|
// TxDesc is a descriptor containing a transaction in the mempool and the
|
||||||
// metadata we store about it.
|
// metadata we store about it.
|
||||||
type TxDesc struct {
|
type TxDesc struct {
|
||||||
Tx *btcutil.Tx // Transaction.
|
Tx *btcutil.Tx // Transaction.
|
||||||
Added time.Time // Time when added to pool.
|
Added time.Time // Time when added to pool.
|
||||||
Height int64 // Blockheight when added to pool.
|
Height int64 // Blockheight when added to pool.
|
||||||
Fee int64 // Transaction fees.
|
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
|
// 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()
|
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
|
// checkPoolDoubleSpend checks whether or not the passed transaction is
|
||||||
// attempting to spend coins already spent by other transactions in the pool.
|
// 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
|
// 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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the input value age sum for the transaction. This
|
// Setup dependencies for any transactions which reference
|
||||||
// is comprised of the sum all of input amounts multiplied by
|
// other transactions in the mempool so they can be properly
|
||||||
// their respective age (number of confirmations since the
|
// ordered below.
|
||||||
// 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.
|
|
||||||
prioItem := &txPrioItem{tx: txDesc.Tx}
|
prioItem := &txPrioItem{tx: txDesc.Tx}
|
||||||
inputValueAge := float64(0.0)
|
|
||||||
for _, txIn := range tx.MsgTx().TxIn {
|
for _, txIn := range tx.MsgTx().TxIn {
|
||||||
originHash := &txIn.PreviousOutPoint.Hash
|
originHash := &txIn.PreviousOutPoint.Hash
|
||||||
originIndex := txIn.PreviousOutPoint.Index
|
originIndex := txIn.PreviousOutPoint.Index
|
||||||
|
@ -550,9 +545,8 @@ mempoolLoop:
|
||||||
}
|
}
|
||||||
prioItem.dependsOn[*originHash] = struct{}{}
|
prioItem.dependsOn[*originHash] = struct{}{}
|
||||||
|
|
||||||
// No need to calculate or sum input value age
|
// Skip the check below. We already know the
|
||||||
// for this input since it's zero due to
|
// referenced transaction is available.
|
||||||
// the input age multiplier of 0.
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,25 +560,19 @@ mempoolLoop:
|
||||||
originIndex, originHash)
|
originIndex, originHash)
|
||||||
continue mempoolLoop
|
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
|
// Calculate the final transaction priority using the input
|
||||||
// value age sum as well as the adjusted transaction size. The
|
// value age sum as well as the adjusted transaction size. The
|
||||||
// formula is: sum(inputValue * inputAge) / adjustedTxSize
|
// formula is: sum(inputValue * inputAge) / adjustedTxSize
|
||||||
txSize := tx.MsgTx().SerializeSize()
|
prioItem.priority = txDesc.CurrentPriority(txStore, nextBlockHeight)
|
||||||
prioItem.priority = calcPriority(tx, txSize, inputValueAge)
|
|
||||||
|
|
||||||
// Calculate the fee in Satoshi/KB.
|
// Calculate the fee in Satoshi/KB.
|
||||||
// NOTE: This is a more precise value than the one calculated
|
// NOTE: This is a more precise value than the one calculated
|
||||||
// during calcMinRelayFee which rounds up to the nearest full
|
// during calcMinRelayFee which rounds up to the nearest full
|
||||||
// kilobyte boundary. This is beneficial since it provides an
|
// kilobyte boundary. This is beneficial since it provides an
|
||||||
// incentive to create smaller transactions.
|
// incentive to create smaller transactions.
|
||||||
|
txSize := tx.MsgTx().SerializeSize()
|
||||||
prioItem.feePerKB = float64(txDesc.Fee) / (float64(txSize) / 1000)
|
prioItem.feePerKB = float64(txDesc.Fee) / (float64(txSize) / 1000)
|
||||||
prioItem.fee = txDesc.Fee
|
prioItem.fee = txDesc.Fee
|
||||||
|
|
||||||
|
|
32
rpcserver.go
32
rpcserver.go
|
@ -2290,19 +2290,39 @@ func handleGetPeerInfo(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{})
|
||||||
// handleGetRawMempool implements the getrawmempool command.
|
// handleGetRawMempool implements the getrawmempool command.
|
||||||
func handleGetRawMempool(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (interface{}, error) {
|
func handleGetRawMempool(s *rpcServer, cmd btcjson.Cmd, closeChan <-chan struct{}) (interface{}, error) {
|
||||||
c := cmd.(*btcjson.GetRawMempoolCmd)
|
c := cmd.(*btcjson.GetRawMempoolCmd)
|
||||||
descs := s.server.txMemPool.TxDescs()
|
mp := s.server.txMemPool
|
||||||
|
descs := mp.TxDescs()
|
||||||
|
|
||||||
if c.Verbose {
|
if c.Verbose {
|
||||||
result := make(map[string]*btcjson.GetRawMempoolResult, len(descs))
|
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 {
|
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{
|
mpd := &btcjson.GetRawMempoolResult{
|
||||||
Size: int32(desc.Tx.MsgTx().SerializeSize()),
|
Size: int32(desc.Tx.MsgTx().SerializeSize()),
|
||||||
Fee: float64(desc.Fee) /
|
Fee: btcutil.Amount(desc.Fee).ToUnit(btcutil.AmountSatoshi),
|
||||||
btcutil.SatoshiPerBitcoin,
|
|
||||||
Time: desc.Added.Unix(),
|
Time: desc.Added.Unix(),
|
||||||
Height: desc.Height,
|
Height: desc.Height,
|
||||||
StartingPriority: 0, // We don't mine.
|
StartingPriority: startingPriority,
|
||||||
CurrentPriority: 0, // We don't mine.
|
CurrentPriority: endingPriority,
|
||||||
Depends: make([]string, 0),
|
Depends: make([]string, 0),
|
||||||
}
|
}
|
||||||
for _, txIn := range desc.Tx.MsgTx().TxIn {
|
for _, txIn := range desc.Tx.MsgTx().TxIn {
|
||||||
|
|
Loading…
Add table
Reference in a new issue