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"
"sync"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/mining"
"github.com/btcsuite/btcutil"
"github.com/roasbeef/btcd/chaincfg/chainhash"
"github.com/roasbeef/btcd/mining"
"github.com/roasbeef/btcutil"
)
// TODO incorporate Alex Morcos' modifications to Gavin's initial model

View file

@ -8,10 +8,10 @@ import (
"math/rand"
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/mining"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/roasbeef/btcd/chaincfg/chainhash"
"github.com/roasbeef/btcd/mining"
"github.com/roasbeef/btcd/wire"
"github.com/roasbeef/btcutil"
)
// 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()
}
// 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
// VerifyChainAsync, VerifyChainLevelAsyncRPC, or VerifyChainBlocksAsync
// invocation (or an applicable error).

View file

@ -132,6 +132,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"debuglevel": handleDebugLevel,
"decoderawtransaction": handleDecodeRawTransaction,
"decodescript": handleDecodeScript,
"estimatefee": handleEstimateFee,
"generate": handleGenerate,
"getaddednodeinfo": handleGetAddedNodeInfo,
"getbestblock": handleGetBestBlock,
@ -224,7 +225,6 @@ var rpcAskWallet = map[string]struct{}{
// Commands that are currently unimplemented, but should ultimately be.
var rpcUnimplemented = map[string]struct{}{
"estimatefee": {},
"estimatepriority": {},
"getchaintips": {},
"getmempoolentry": {},
@ -254,6 +254,7 @@ var rpcLimited = map[string]struct{}{
"createrawtransaction": {},
"decoderawtransaction": {},
"decodescript": {},
"estimatefee": {},
"getbestblock": {},
"getbestblockhash": {},
"getblock": {},
@ -853,6 +854,28 @@ func handleDecodeScript(s *rpcServer, cmd interface{}, closeChan <-chan struct{}
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.
func handleGenerate(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
// Respond with an error if there are no addresses to pay the
@ -4247,6 +4270,10 @@ type rpcserverConfig struct {
TxIndex *indexers.TxIndex
AddrIndex *indexers.AddrIndex
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.

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-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
"generate--synopsis": "Generates a set number of blocks (simnet or regtest only) and returns a JSON\n" +
" array of their hashes.",
@ -663,6 +672,7 @@ var rpcResultTypes = map[string][]interface{}{
"debuglevel": {(*string)(nil), (*string)(nil)},
"decoderawtransaction": {(*btcjson.TxRawDecodeResult)(nil)},
"decodescript": {(*btcjson.DecodeScriptResult)(nil)},
"estimatefee": {(*float64)(nil)},
"generate": {(*[]string)(nil)},
"getaddednodeinfo": {(*[]string)(nil), (*[]btcjson.GetAddedNodeInfoResult)(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{
Listeners: rpcListeners,
StartupTime: s.startupTime,
ConnMgr: &rpcConnManager{&s},
SyncMgr: &rpcSyncMgr{&s, s.syncManager},
TimeSource: s.timeSource,
Chain: s.chain,
ChainParams: chainParams,
DB: db,
TxMemPool: s.txMemPool,
Generator: blockTemplateGenerator,
CPUMiner: s.cpuMiner,
TxIndex: s.txIndex,
AddrIndex: s.addrIndex,
CfIndex: s.cfIndex,
Listeners: rpcListeners,
StartupTime: s.startupTime,
ConnMgr: &rpcConnManager{&s},
SyncMgr: &rpcSyncMgr{&s, s.syncManager},
TimeSource: s.timeSource,
Chain: s.chain,
ChainParams: chainParams,
DB: db,
TxMemPool: s.txMemPool,
Generator: blockTemplateGenerator,
CPUMiner: s.cpuMiner,
TxIndex: s.txIndex,
AddrIndex: s.addrIndex,
CfIndex: s.cfIndex,
FeeEstimator: feeEstimator,
})
if err != nil {
return nil, err