Skip to content

Commit ac898b6

Browse files
committed
Merge #12717: [REST] Handle UTXO retrieval when ignoring the mempool
9cb9af8 [REST] Handle UTXO retrieval when ignoring the mempool (Roman Zeyde) 1fdc7c4 Make CTxMemPool::isSpent() const (Roman Zeyde) Pull request description: Current REST API always returns empty UTXO when invoked without `/checkmempool/` URL part. After the fix: ``` $ curl -s http://localhost:8332/rest/getutxos/0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098-0.json | jq { "chainHeight": 514109, "chaintipHash": "0000000000000000001fe76d1445e8a6432fd2de04261dc9c5915311dc7ad6de", "bitmap": "1", "utxos": [ { "height": 1, "value": 50, "scriptPubKey": { "asm": "0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee OP_CHECKSIG", "hex": "410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac", "reqSigs": 1, "type": "pubkey", "addresses": [ "12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX" ] } } ] } ``` Before the fix: ``` $ curl -s http://localhost:8332/rest/getutxos/0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098-0.json | jq { "chainHeight": 514109, "chaintipHash": "0000000000000000001fe76d1445e8a6432fd2de04261dc9c5915311dc7ad6de", "bitmap": "0", "utxos": [] } ``` Tree-SHA512: 994a350cb34a3c8f5a7afbc169c6b177c5be6cf223b2071c62d63644819d416d3e10d1c58b244d9d351bae7233d2974aa5e9ebadd1b5d6218f5245558675be0d
2 parents 534b8fa + 9cb9af8 commit ac898b6

File tree

4 files changed

+54
-27
lines changed

4 files changed

+54
-27
lines changed

src/rest.cpp

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -487,26 +487,28 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
487487
std::vector<bool> hits;
488488
bitmap.resize((vOutPoints.size() + 7) / 8);
489489
{
490-
LOCK2(cs_main, mempool.cs);
491-
492-
CCoinsView viewDummy;
493-
CCoinsViewCache view(&viewDummy);
494-
495-
CCoinsViewCache& viewChain = *pcoinsTip;
496-
CCoinsViewMemPool viewMempool(&viewChain, mempool);
497-
498-
if (fCheckMemPool)
499-
view.SetBackend(viewMempool); // switch cache backend to db+mempool in case user likes to query mempool
500-
501-
for (size_t i = 0; i < vOutPoints.size(); i++) {
502-
bool hit = false;
503-
Coin coin;
504-
if (view.GetCoin(vOutPoints[i], coin) && !mempool.isSpent(vOutPoints[i])) {
505-
hit = true;
506-
outs.emplace_back(std::move(coin));
490+
auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView& view, const CTxMemPool& mempool) {
491+
for (const COutPoint& vOutPoint : vOutPoints) {
492+
Coin coin;
493+
bool hit = !mempool.isSpent(vOutPoint) && view.GetCoin(vOutPoint, coin);
494+
hits.push_back(hit);
495+
if (hit) outs.emplace_back(std::move(coin));
507496
}
497+
};
498+
499+
if (fCheckMemPool) {
500+
// use db+mempool as cache backend in case user likes to query mempool
501+
LOCK2(cs_main, mempool.cs);
502+
CCoinsViewCache& viewChain = *pcoinsTip;
503+
CCoinsViewMemPool viewMempool(&viewChain, mempool);
504+
process_utxos(viewMempool, mempool);
505+
} else {
506+
LOCK(cs_main); // no need to lock mempool!
507+
process_utxos(*pcoinsTip, CTxMemPool());
508+
}
508509

509-
hits.push_back(hit);
510+
for (size_t i = 0; i < hits.size(); ++i) {
511+
const bool hit = hits[i];
510512
bitmapStringRepresentation.append(hit ? "1" : "0"); // form a binary string representation (human-readable for json output)
511513
bitmap[i / 8] |= ((uint8_t)hit) << (i % 8);
512514
}

src/txmempool.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) :
339339
nCheckFrequency = 0;
340340
}
341341

342-
bool CTxMemPool::isSpent(const COutPoint& outpoint)
342+
bool CTxMemPool::isSpent(const COutPoint& outpoint) const
343343
{
344344
LOCK(cs);
345345
return mapNextTx.count(outpoint);

src/txmempool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ class CTxMemPool
550550
void _clear(); //lock free
551551
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
552552
void queryHashes(std::vector<uint256>& vtxid);
553-
bool isSpent(const COutPoint& outpoint);
553+
bool isSpent(const COutPoint& outpoint) const;
554554
unsigned int GetTransactionsUpdated() const;
555555
void AddTransactionsUpdated(unsigned int n);
556556
/**

test/functional/interface_rest.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def run_test(self):
8585
#######################################
8686
# GETUTXOS: query an unspent outpoint #
8787
#######################################
88-
json_request = '/checkmempool/'+txid+'-'+str(n)
88+
json_request = '/'+txid+'-'+str(n)
8989
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
9090
json_obj = json.loads(json_string)
9191

@@ -100,7 +100,7 @@ def run_test(self):
100100
#################################################
101101
# GETUTXOS: now query an already spent outpoint #
102102
#################################################
103-
json_request = '/checkmempool/'+vintx+'-0'
103+
json_request = '/'+vintx+'-0'
104104
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
105105
json_obj = json.loads(json_string)
106106

@@ -117,7 +117,7 @@ def run_test(self):
117117
##################################################
118118
# GETUTXOS: now check both with the same request #
119119
##################################################
120-
json_request = '/checkmempool/'+txid+'-'+str(n)+'/'+vintx+'-0'
120+
json_request = '/'+txid+'-'+str(n)+'/'+vintx+'-0'
121121
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
122122
json_obj = json.loads(json_string)
123123
assert_equal(len(json_obj['utxos']), 1)
@@ -151,23 +151,48 @@ def run_test(self):
151151
txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
152152
json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+txid+self.FORMAT_SEPARATOR+"json")
153153
json_obj = json.loads(json_string)
154-
vintx = json_obj['vin'][0]['txid'] # get the vin to later check for utxo (should be spent by then)
154+
# get the spent output to later check for utxo (should be spent by then)
155+
spent = '{}-{}'.format(json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout'])
155156
# get n of 0.1 outpoint
156157
n = 0
157158
for vout in json_obj['vout']:
158159
if vout['value'] == 0.1:
159160
n = vout['n']
161+
spending = '{}-{}'.format(txid, n)
160162

161-
json_request = '/'+txid+'-'+str(n)
163+
json_request = '/'+spending
162164
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
163165
json_obj = json.loads(json_string)
164-
assert_equal(len(json_obj['utxos']), 0) #there should be an outpoint because it has just added to the mempool
166+
assert_equal(len(json_obj['utxos']), 0) #there should be no outpoint because it has just added to the mempool
165167

166-
json_request = '/checkmempool/'+txid+'-'+str(n)
168+
json_request = '/checkmempool/'+spending
167169
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
168170
json_obj = json.loads(json_string)
169171
assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it has just added to the mempool
170172

173+
json_request = '/'+spent
174+
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
175+
json_obj = json.loads(json_string)
176+
assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because its spending tx is not confirmed
177+
178+
json_request = '/checkmempool/'+spent
179+
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
180+
json_obj = json.loads(json_string)
181+
assert_equal(len(json_obj['utxos']), 0) #there should be no outpoint because it has just spent (by mempool tx)
182+
183+
self.nodes[0].generate(1)
184+
self.sync_all()
185+
186+
json_request = '/'+spending
187+
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
188+
json_obj = json.loads(json_string)
189+
assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it was mined
190+
191+
json_request = '/checkmempool/'+spending
192+
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
193+
json_obj = json.loads(json_string)
194+
assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it was mined
195+
171196
#do some invalid requests
172197
json_request = '{"checkmempool'
173198
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True)

0 commit comments

Comments
 (0)