Skip to content

Commit

Permalink
Enable estimatefee rpc command.
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Krawisz authored and Roasbeef committed May 23, 2018
1 parent 1333ad7 commit 4fd4460
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 22 deletions.
6 changes: 3 additions & 3 deletions mempool/estimatefee.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions mempool/estimatefee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 37 additions & 0 deletions rpcclient/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
29 changes: 28 additions & 1 deletion rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"debuglevel": handleDebugLevel,
"decoderawtransaction": handleDecodeRawTransaction,
"decodescript": handleDecodeScript,
"estimatefee": handleEstimateFee,
"generate": handleGenerate,
"getaddednodeinfo": handleGetAddedNodeInfo,
"getbestblock": handleGetBestBlock,
Expand Down Expand Up @@ -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": {},
Expand Down Expand Up @@ -254,6 +254,7 @@ var rpcLimited = map[string]struct{}{
"createrawtransaction": {},
"decoderawtransaction": {},
"decodescript": {},
"estimatefee": {},
"getbestblock": {},
"getbestblockhash": {},
"getblock": {},
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
10 changes: 10 additions & 0 deletions rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down Expand Up @@ -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)},
Expand Down
29 changes: 15 additions & 14 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 4fd4460

Please sign in to comment.