Expose RPC calls for estimatesmart functions
Also add testing for estimatesmartfee in smartfees.py
This commit is contained in:
parent
e93a236d7a
commit
56106a3300
5 changed files with 108 additions and 22 deletions
|
@ -120,15 +120,26 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
|
|||
last_e = e
|
||||
valid_estimate = False
|
||||
invalid_estimates = 0
|
||||
for e in all_estimates:
|
||||
for i,e in enumerate(all_estimates): # estimate is for i+1
|
||||
if e >= 0:
|
||||
valid_estimate = True
|
||||
# estimatesmartfee should return the same result
|
||||
assert_equal(node.estimatesmartfee(i+1)["feerate"], e)
|
||||
|
||||
else:
|
||||
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
|
||||
if valid_estimate and e < 0:
|
||||
raise AssertionError("Invalid estimate appears at higher confirm count than valid estimate")
|
||||
|
||||
# estimatesmartfee should still be valid
|
||||
approx_estimate = node.estimatesmartfee(i+1)["feerate"]
|
||||
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
|
||||
# that we might not have valid estimates for
|
||||
if invalid_estimates > max_invalid:
|
||||
|
@ -184,13 +195,13 @@ class EstimateFeeTest(BitcoinTestFramework):
|
|||
# NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
|
||||
# (17k is room enough for 110 or so transactions)
|
||||
self.nodes.append(start_node(1, self.options.tmpdir,
|
||||
["-blockprioritysize=1500", "-blockmaxsize=18000",
|
||||
["-blockprioritysize=1500", "-blockmaxsize=17000",
|
||||
"-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"]))
|
||||
connect_nodes(self.nodes[1], 0)
|
||||
|
||||
# Node2 is a stingy miner, that
|
||||
# produces too small blocks (room for only 70 or so transactions)
|
||||
node2args = ["-blockprioritysize=0", "-blockmaxsize=12000", "-maxorphantx=1000", "-relaypriority=0"]
|
||||
# produces too small blocks (room for only 55 or so transactions)
|
||||
node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000", "-relaypriority=0"]
|
||||
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, node2args))
|
||||
connect_nodes(self.nodes[0], 2)
|
||||
|
@ -229,22 +240,19 @@ class EstimateFeeTest(BitcoinTestFramework):
|
|||
self.fees_per_kb = []
|
||||
self.memutxo = []
|
||||
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("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("Will output estimates for 1/2/3/6/15/25 blocks")
|
||||
|
||||
print("Creating transactions and mining them with a block size that can't keep up")
|
||||
# Create transactions and mine 30 small blocks with node 2, but create txs faster than we can mine
|
||||
self.transact_and_mine(20, self.nodes[2])
|
||||
check_estimates(self.nodes[1], self.fees_per_kb, 3)
|
||||
for i in xrange(2):
|
||||
print("Creating transactions and mining them with a block size that can't keep up")
|
||||
# Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine
|
||||
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")
|
||||
# Generate transactions while mining 40 more blocks, this time with node1
|
||||
# which mines blocks with capacity just above the rate that transactions are being created
|
||||
self.transact_and_mine(40, self.nodes[1])
|
||||
check_estimates(self.nodes[1], self.fees_per_kb, 2)
|
||||
print("Creating transactions and mining them at a block size that is just big enough")
|
||||
# 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
|
||||
self.transact_and_mine(10, self.nodes[1])
|
||||
check_estimates(self.nodes[1], self.fees_per_kb, 2)
|
||||
|
||||
# Finish by mining a normal-sized block:
|
||||
while len(self.nodes[1].getrawmempool()) > 0:
|
||||
|
|
|
@ -96,6 +96,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "getrawmempool", 0 },
|
||||
{ "estimatefee", 0 },
|
||||
{ "estimatepriority", 0 },
|
||||
{ "estimatesmartfee", 0 },
|
||||
{ "estimatesmartpriority", 0 },
|
||||
{ "prioritisetransaction", 1 },
|
||||
{ "prioritisetransaction", 2 },
|
||||
{ "setban", 2 },
|
||||
|
|
|
@ -726,3 +726,75 @@ UniValue estimatepriority(const UniValue& params, bool fHelp)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -319,6 +319,8 @@ static const CRPCCommand vRPCCommands[] =
|
|||
{ "util", "verifymessage", &verifymessage, true },
|
||||
{ "util", "estimatefee", &estimatefee, true },
|
||||
{ "util", "estimatepriority", &estimatepriority, true },
|
||||
{ "util", "estimatesmartfee", &estimatesmartfee, true },
|
||||
{ "util", "estimatesmartpriority", &estimatesmartpriority, true },
|
||||
|
||||
/* Not shown in help */
|
||||
{ "hidden", "invalidateblock", &invalidateblock, true },
|
||||
|
|
|
@ -193,6 +193,8 @@ extern UniValue getblocktemplate(const UniValue& params, bool fHelp);
|
|||
extern UniValue submitblock(const UniValue& params, bool fHelp);
|
||||
extern UniValue estimatefee(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 getaccountaddress(const UniValue& params, bool fHelp);
|
||||
|
|
Loading…
Reference in a new issue