Enable estimatefee rpc command.

This commit is contained in:
Daniel Krawisz 2017-11-13 16:39:16 -06:00 committed by Olaoluwa Osuntokun
parent 1333ad7f78
commit 4fd446028f
6 changed files with 97 additions and 22 deletions

View file

@ -12,9 +12,9 @@ import (
"sort" "sort"
"sync" "sync"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/roasbeef/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/mining" "github.com/roasbeef/btcd/mining"
"github.com/btcsuite/btcutil" "github.com/roasbeef/btcutil"
) )
// TODO incorporate Alex Morcos' modifications to Gavin's initial model // TODO incorporate Alex Morcos' modifications to Gavin's initial model

View file

@ -8,10 +8,10 @@ import (
"math/rand" "math/rand"
"testing" "testing"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/roasbeef/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/mining" "github.com/roasbeef/btcd/mining"
"github.com/btcsuite/btcd/wire" "github.com/roasbeef/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/roasbeef/btcutil"
) )
// newTestFeeEstimator creates a feeEstimator with some different parameters // newTestFeeEstimator creates a feeEstimator with some different parameters

View file

@ -557,6 +557,43 @@ func (c *Client) GetRawMempoolVerbose() (map[string]btcjson.GetRawMempoolVerbose
return c.GetRawMempoolVerboseAsync().Receive() return c.GetRawMempoolVerboseAsync().Receive()
} }
// FutureEstimateFeeResult is a future promise to deliver the result of a
// EstimateFeeAsync RPC invocation (or an applicable error).
type FutureEstimateFeeResult chan *response
// Receive waits for the response promised by the future and returns the info
// provided by the server.
func (r FutureEstimateFeeResult) Receive() (float64, error) {
res, err := receiveFuture(r)
if err != nil {
return -1, err
}
// Unmarshal result as a getinfo result object.
var fee float64
err = json.Unmarshal(res, &fee)
if err != nil {
return -1, err
}
return fee, nil
}
// EstimateFeeAsync returns an instance of a type that can be used to get the result
// of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See EstimateFee for the blocking version and more details.
func (c *Client) EstimateFeeAsync(numBlocks int64) FutureEstimateFeeResult {
cmd := btcjson.NewEstimateFeeCmd(numBlocks)
return c.sendCmd(cmd)
}
// EstimateFee provides an estimated fee in bitcoins per kilobyte.
func (c *Client) EstimateFee(numBlocks int64) (float64, error) {
return c.EstimateFeeAsync(numBlocks).Receive()
}
// FutureVerifyChainResult is a future promise to deliver the result of a // FutureVerifyChainResult is a future promise to deliver the result of a
// VerifyChainAsync, VerifyChainLevelAsyncRPC, or VerifyChainBlocksAsync // VerifyChainAsync, VerifyChainLevelAsyncRPC, or VerifyChainBlocksAsync
// invocation (or an applicable error). // invocation (or an applicable error).

View file

@ -132,6 +132,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"debuglevel": handleDebugLevel, "debuglevel": handleDebugLevel,
"decoderawtransaction": handleDecodeRawTransaction, "decoderawtransaction": handleDecodeRawTransaction,
"decodescript": handleDecodeScript, "decodescript": handleDecodeScript,
"estimatefee": handleEstimateFee,
"generate": handleGenerate, "generate": handleGenerate,
"getaddednodeinfo": handleGetAddedNodeInfo, "getaddednodeinfo": handleGetAddedNodeInfo,
"getbestblock": handleGetBestBlock, "getbestblock": handleGetBestBlock,
@ -224,7 +225,6 @@ var rpcAskWallet = map[string]struct{}{
// Commands that are currently unimplemented, but should ultimately be. // Commands that are currently unimplemented, but should ultimately be.
var rpcUnimplemented = map[string]struct{}{ var rpcUnimplemented = map[string]struct{}{
"estimatefee": {},
"estimatepriority": {}, "estimatepriority": {},
"getchaintips": {}, "getchaintips": {},
"getmempoolentry": {}, "getmempoolentry": {},
@ -254,6 +254,7 @@ var rpcLimited = map[string]struct{}{
"createrawtransaction": {}, "createrawtransaction": {},
"decoderawtransaction": {}, "decoderawtransaction": {},
"decodescript": {}, "decodescript": {},
"estimatefee": {},
"getbestblock": {}, "getbestblock": {},
"getbestblockhash": {}, "getbestblockhash": {},
"getblock": {}, "getblock": {},
@ -853,6 +854,28 @@ func handleDecodeScript(s *rpcServer, cmd interface{}, closeChan <-chan struct{}
return reply, nil return reply, nil
} }
// handleEstimateFee handles estimatefee commands.
func handleEstimateFee(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
c := cmd.(*btcjson.EstimateFeeCmd)
if s.cfg.FeeEstimator == nil {
return nil, errors.New("Fee estimation disabled")
}
if c.NumBlocks <= 0 {
return -1.0, errors.New("Parameter NumBlocks must be positive")
}
feeRate, err := s.cfg.FeeEstimator.EstimateFee(uint32(c.NumBlocks))
if err != nil {
return -1.0, err
}
// Convert to satoshis per kb.
return float64(feeRate.ToSatoshiPerKb()), nil
}
// handleGenerate handles generate commands. // handleGenerate handles generate commands.
func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
// Respond with an error if there are no addresses to pay the // Respond with an error if there are no addresses to pay the
@ -4247,6 +4270,10 @@ type rpcserverConfig struct {
TxIndex *indexers.TxIndex TxIndex *indexers.TxIndex
AddrIndex *indexers.AddrIndex AddrIndex *indexers.AddrIndex
CfIndex *indexers.CfIndex CfIndex *indexers.CfIndex
// The fee estimator keeps track of how long transactions are left in
// the mempool before they are mined into blocks.
FeeEstimator *mempool.FeeEstimator
} }
// newRPCServer returns a new instance of the rpcServer struct. // newRPCServer returns a new instance of the rpcServer struct.

View file

@ -115,6 +115,15 @@ var helpDescsEnUS = map[string]string{
"decodescript--synopsis": "Returns a JSON object with information about the provided hex-encoded script.", "decodescript--synopsis": "Returns a JSON object with information about the provided hex-encoded script.",
"decodescript-hexscript": "Hex-encoded script", "decodescript-hexscript": "Hex-encoded script",
// EstimateFeeCmd help.
"estimatefee--synopsis": "Estimate the fee per kilobyte in satoshis " +
"required for a transaction to be mined before a certain number of " +
"blocks have been generated.",
"estimatefee-numblocks": "The maximum number of blocks which can be " +
"generated before the transaction is mined.",
"estimatefee--result0": "Estimated fee per kilobyte in satoshis for a block to " +
"be mined in the next NumBlocks blocks.",
// GenerateCmd help // GenerateCmd help
"generate--synopsis": "Generates a set number of blocks (simnet or regtest only) and returns a JSON\n" + "generate--synopsis": "Generates a set number of blocks (simnet or regtest only) and returns a JSON\n" +
" array of their hashes.", " array of their hashes.",
@ -663,6 +672,7 @@ var rpcResultTypes = map[string][]interface{}{
"debuglevel": {(*string)(nil), (*string)(nil)}, "debuglevel": {(*string)(nil), (*string)(nil)},
"decoderawtransaction": {(*btcjson.TxRawDecodeResult)(nil)}, "decoderawtransaction": {(*btcjson.TxRawDecodeResult)(nil)},
"decodescript": {(*btcjson.DecodeScriptResult)(nil)}, "decodescript": {(*btcjson.DecodeScriptResult)(nil)},
"estimatefee": {(*float64)(nil)},
"generate": {(*[]string)(nil)}, "generate": {(*[]string)(nil)},
"getaddednodeinfo": {(*[]string)(nil), (*[]btcjson.GetAddedNodeInfoResult)(nil)}, "getaddednodeinfo": {(*[]string)(nil), (*[]btcjson.GetAddedNodeInfoResult)(nil)},
"getbestblock": {(*btcjson.GetBestBlockResult)(nil)}, "getbestblock": {(*btcjson.GetBestBlockResult)(nil)},

View file

@ -2572,20 +2572,21 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
} }
s.rpcServer, err = newRPCServer(&rpcserverConfig{ s.rpcServer, err = newRPCServer(&rpcserverConfig{
Listeners: rpcListeners, Listeners: rpcListeners,
StartupTime: s.startupTime, StartupTime: s.startupTime,
ConnMgr: &rpcConnManager{&s}, ConnMgr: &rpcConnManager{&s},
SyncMgr: &rpcSyncMgr{&s, s.syncManager}, SyncMgr: &rpcSyncMgr{&s, s.syncManager},
TimeSource: s.timeSource, TimeSource: s.timeSource,
Chain: s.chain, Chain: s.chain,
ChainParams: chainParams, ChainParams: chainParams,
DB: db, DB: db,
TxMemPool: s.txMemPool, TxMemPool: s.txMemPool,
Generator: blockTemplateGenerator, Generator: blockTemplateGenerator,
CPUMiner: s.cpuMiner, CPUMiner: s.cpuMiner,
TxIndex: s.txIndex, TxIndex: s.txIndex,
AddrIndex: s.addrIndex, AddrIndex: s.addrIndex,
CfIndex: s.cfIndex, CfIndex: s.cfIndex,
FeeEstimator: feeEstimator,
}) })
if err != nil { if err != nil {
return nil, err return nil, err