Browse Source

Expose RPC calls for estimatesmart functions

Also add testing for estimatesmartfee in smartfees.py
0.13
Alex Morcos 9 years ago
parent
commit
56106a3300
  1. 52
      qa/rpc-tests/smartfees.py
  2. 2
      src/rpcclient.cpp
  3. 72
      src/rpcmining.cpp
  4. 2
      src/rpcserver.cpp
  5. 2
      src/rpcserver.h

52
qa/rpc-tests/smartfees.py

@ -120,15 +120,26 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
last_e = e last_e = e
valid_estimate = False valid_estimate = False
invalid_estimates = 0 invalid_estimates = 0
for e in all_estimates: for i,e in enumerate(all_estimates): # estimate is for i+1
if e >= 0: if e >= 0:
valid_estimate = True valid_estimate = True
# estimatesmartfee should return the same result
assert_equal(node.estimatesmartfee(i+1)["feerate"], e)
else: else:
invalid_estimates += 1 invalid_estimates += 1
# Once we're at a high enough confirmation count that we can give an estimate
# We should have estimates for all higher confirmation counts # estimatesmartfee should still be valid
if valid_estimate and e < 0: approx_estimate = node.estimatesmartfee(i+1)["feerate"]
raise AssertionError("Invalid estimate appears at higher confirm count than valid estimate") answer_found = node.estimatesmartfee(i+1)["blocks"]
assert(approx_estimate > 0)
assert(answer_found > i+1)
# Once we're at a high enough confirmation count that we can give an estimate
# We should have estimates for all higher confirmation counts
if valid_estimate:
raise AssertionError("Invalid estimate appears at higher confirm count than valid estimate")
# Check on the expected number of different confirmation counts # Check on the expected number of different confirmation counts
# that we might not have valid estimates for # that we might not have valid estimates for
if invalid_estimates > max_invalid: if invalid_estimates > max_invalid:
@ -184,13 +195,13 @@ class EstimateFeeTest(BitcoinTestFramework):
# NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
# (17k is room enough for 110 or so transactions) # (17k is room enough for 110 or so transactions)
self.nodes.append(start_node(1, self.options.tmpdir, self.nodes.append(start_node(1, self.options.tmpdir,
["-blockprioritysize=1500", "-blockmaxsize=18000", ["-blockprioritysize=1500", "-blockmaxsize=17000",
"-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"])) "-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"]))
connect_nodes(self.nodes[1], 0) connect_nodes(self.nodes[1], 0)
# Node2 is a stingy miner, that # Node2 is a stingy miner, that
# produces too small blocks (room for only 70 or so transactions) # produces too small blocks (room for only 55 or so transactions)
node2args = ["-blockprioritysize=0", "-blockmaxsize=12000", "-maxorphantx=1000", "-relaypriority=0"] node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000", "-relaypriority=0"]
self.nodes.append(start_node(2, self.options.tmpdir, node2args)) self.nodes.append(start_node(2, self.options.tmpdir, node2args))
connect_nodes(self.nodes[0], 2) connect_nodes(self.nodes[0], 2)
@ -229,22 +240,19 @@ class EstimateFeeTest(BitcoinTestFramework):
self.fees_per_kb = [] self.fees_per_kb = []
self.memutxo = [] self.memutxo = []
self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting
print("Checking estimates for 1/2/3/6/15/25 blocks") print("Will output estimates for 1/2/3/6/15/25 blocks")
print("Creating transactions and mining them with a huge block size")
# Create transactions and mine 20 big blocks with node 0 such that the mempool is always emptied
self.transact_and_mine(30, self.nodes[0])
check_estimates(self.nodes[1], self.fees_per_kb, 1)
print("Creating transactions and mining them with a block size that can't keep up") for i in xrange(2):
# Create transactions and mine 30 small blocks with node 2, but create txs faster than we can mine print("Creating transactions and mining them with a block size that can't keep up")
self.transact_and_mine(20, self.nodes[2]) # Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine
check_estimates(self.nodes[1], self.fees_per_kb, 3) self.transact_and_mine(10, self.nodes[2])
check_estimates(self.nodes[1], self.fees_per_kb, 14)
print("Creating transactions and mining them at a block size that is just big enough") print("Creating transactions and mining them at a block size that is just big enough")
# Generate transactions while mining 40 more blocks, this time with node1 # Generate transactions while mining 10 more blocks, this time with node1
# which mines blocks with capacity just above the rate that transactions are being created # which mines blocks with capacity just above the rate that transactions are being created
self.transact_and_mine(40, self.nodes[1]) self.transact_and_mine(10, self.nodes[1])
check_estimates(self.nodes[1], self.fees_per_kb, 2) check_estimates(self.nodes[1], self.fees_per_kb, 2)
# Finish by mining a normal-sized block: # Finish by mining a normal-sized block:
while len(self.nodes[1].getrawmempool()) > 0: while len(self.nodes[1].getrawmempool()) > 0:

2
src/rpcclient.cpp

@ -96,6 +96,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getrawmempool", 0 }, { "getrawmempool", 0 },
{ "estimatefee", 0 }, { "estimatefee", 0 },
{ "estimatepriority", 0 }, { "estimatepriority", 0 },
{ "estimatesmartfee", 0 },
{ "estimatesmartpriority", 0 },
{ "prioritisetransaction", 1 }, { "prioritisetransaction", 1 },
{ "prioritisetransaction", 2 }, { "prioritisetransaction", 2 },
{ "setban", 2 }, { "setban", 2 },

72
src/rpcmining.cpp

@ -726,3 +726,75 @@ UniValue estimatepriority(const UniValue& params, bool fHelp)
return mempool.estimatePriority(nBlocks); return mempool.estimatePriority(nBlocks);
} }
UniValue estimatesmartfee(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"estimatesmartfee nblocks\n"
"\nWARNING: This interface is unstable and may disappear or change!\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
"confirmation within nblocks blocks if possible and return the number of blocks\n"
"for which the estimate is valid.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
"{\n"
" \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
"\n"
"A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
"However it will not return a value below the mempool reject fee.\n"
"\nExample:\n"
+ HelpExampleCli("estimatesmartfee", "6")
);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int();
UniValue result(UniValue::VOBJ);
int answerFound;
CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound);
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
result.push_back(Pair("blocks", answerFound));
return result;
}
UniValue estimatesmartpriority(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"estimatesmartpriority nblocks\n"
"\nWARNING: This interface is unstable and may disappear or change!\n"
"\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
"confirmation within nblocks blocks if possible and return the number of blocks\n"
"for which the estimate is valid.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
"{\n"
" \"priority\" : x.x, (numeric) estimated priority\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
"\n"
"A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
"However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n"
"\nExample:\n"
+ HelpExampleCli("estimatesmartpriority", "6")
);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int();
UniValue result(UniValue::VOBJ);
int answerFound;
double priority = mempool.estimateSmartPriority(nBlocks, &answerFound);
result.push_back(Pair("priority", priority));
result.push_back(Pair("blocks", answerFound));
return result;
}

2
src/rpcserver.cpp

@ -319,6 +319,8 @@ static const CRPCCommand vRPCCommands[] =
{ "util", "verifymessage", &verifymessage, true }, { "util", "verifymessage", &verifymessage, true },
{ "util", "estimatefee", &estimatefee, true }, { "util", "estimatefee", &estimatefee, true },
{ "util", "estimatepriority", &estimatepriority, true }, { "util", "estimatepriority", &estimatepriority, true },
{ "util", "estimatesmartfee", &estimatesmartfee, true },
{ "util", "estimatesmartpriority", &estimatesmartpriority, true },
/* Not shown in help */ /* Not shown in help */
{ "hidden", "invalidateblock", &invalidateblock, true }, { "hidden", "invalidateblock", &invalidateblock, true },

2
src/rpcserver.h

@ -193,6 +193,8 @@ extern UniValue getblocktemplate(const UniValue& params, bool fHelp);
extern UniValue submitblock(const UniValue& params, bool fHelp); extern UniValue submitblock(const UniValue& params, bool fHelp);
extern UniValue estimatefee(const UniValue& params, bool fHelp); extern UniValue estimatefee(const UniValue& params, bool fHelp);
extern UniValue estimatepriority(const UniValue& params, bool fHelp); extern UniValue estimatepriority(const UniValue& params, bool fHelp);
extern UniValue estimatesmartfee(const UniValue& params, bool fHelp);
extern UniValue estimatesmartpriority(const UniValue& params, bool fHelp);
extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
extern UniValue getaccountaddress(const UniValue& params, bool fHelp); extern UniValue getaccountaddress(const UniValue& params, bool fHelp);

Loading…
Cancel
Save