diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -546,30 +546,35 @@ std::vector hits; bitmap.resize((vOutPoints.size() + 7) / 8); { - LOCK2(cs_main, g_mempool.cs); - - CCoinsView viewDummy; - CCoinsViewCache view(&viewDummy); - - CCoinsViewCache &viewChain = *pcoinsTip; - CCoinsViewMemPool viewMempool(&viewChain, g_mempool); + auto process_utxos = [&vOutPoints, &outs, + &hits](const CCoinsView &view, + const CTxMemPool &mempool) { + for (const COutPoint &vOutPoint : vOutPoints) { + Coin coin; + bool hit = !mempool.isSpent(vOutPoint) && + view.GetCoin(vOutPoint, coin); + hits.push_back(hit); + if (hit) { + outs.emplace_back(std::move(coin)); + } + } + }; if (fCheckMemPool) { - // switch cache backend to db+mempool in case user likes to query - // mempool. - view.SetBackend(viewMempool); - } - - for (size_t i = 0; i < vOutPoints.size(); i++) { - Coin coin; - bool hit = false; - if (view.GetCoin(vOutPoints[i], coin) && - !g_mempool.isSpent(vOutPoints[i])) { - hit = true; - outs.emplace_back(std::move(coin)); - } + // use db+mempool as cache backend in case user likes to query + // mempool + LOCK2(cs_main, g_mempool.cs); + CCoinsViewCache &viewChain = *pcoinsTip; + CCoinsViewMemPool viewMempool(&viewChain, g_mempool); + process_utxos(viewMempool, g_mempool); + } else { + // no need to lock mempool! + LOCK(cs_main); + process_utxos(*pcoinsTip, CTxMemPool()); + } - hits.push_back(hit); + for (size_t i = 0; i < hits.size(); ++i) { + const bool hit = hits[i]; // form a binary string representation (human-readable for json // output) bitmapStringRepresentation.append(hit ? "1" : "0"); diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -579,7 +579,7 @@ void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); bool CompareDepthAndScore(const uint256 &hasha, const uint256 &hashb); void queryHashes(std::vector &vtxid); - bool isSpent(const COutPoint &outpoint); + bool isSpent(const COutPoint &outpoint) const; unsigned int GetTransactionsUpdated() const; void AddTransactionsUpdated(unsigned int n); /** diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -394,7 +394,7 @@ CTxMemPool::~CTxMemPool() {} -bool CTxMemPool::isSpent(const COutPoint &outpoint) { +bool CTxMemPool::isSpent(const COutPoint &outpoint) const { LOCK(cs); return mapNextTx.count(outpoint); } diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -100,7 +100,7 @@ # # GETUTXOS: query an unspent outpoint # # - json_request = '/checkmempool/' + txid + '-' + str(n) + json_request = '/' + txid + '-' + str(n) json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) @@ -115,7 +115,7 @@ # # GETUTXOS: now query an already spent outpoint # # - json_request = '/checkmempool/' + vintx + '-0' + json_request = '/' + vintx + '-0' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) @@ -133,8 +133,7 @@ # # GETUTXOS: now check both with the same request # # - json_request = '/checkmempool/' + \ - txid + '-' + str(n) + '/' + vintx + '-0' + json_request = '/' + txid + '-' + str(n) + '/' + vintx + '-0' json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) @@ -171,23 +170,25 @@ json_string = http_get_call( url.hostname, url.port, '/rest/tx/' + txid + self.FORMAT_SEPARATOR + "json") json_obj = json.loads(json_string) - vintx = json_obj['vin'][0]['txid'] - # get the vin to later check for utxo (should be spent by then) + # get the spent output to later check for utxo (should be spent by then) + spent = '{}-{}'.format(json_obj['vin'][0] + ['txid'], json_obj['vin'][0]['vout']) # get n of 0.1 outpoint n = 0 for vout in json_obj['vout']: if vout['value'] == 0.1: n = vout['n'] + spending = '{}-{}'.format(txid, n) - json_request = '/' + txid + '-' + str(n) + json_request = '/' + spending json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) - # there should be an outpoint because it has just added to + # there should be no outpoint because it has just added to # the mempool assert_equal(len(json_obj['utxos']), 0) - json_request = '/checkmempool/' + txid + '-' + str(n) + json_request = '/checkmempool/' + spending json_string = http_get_call( url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') json_obj = json.loads(json_string) @@ -195,6 +196,37 @@ # the mempool assert_equal(len(json_obj['utxos']), 1) + json_request = '/' + spent + json_string = http_get_call( + url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') + json_obj = json.loads(json_string) + # there should be an outpoint because its spending tx is not confirmed + assert_equal(len(json_obj['utxos']), 1) + + json_request = '/checkmempool/' + spent + json_string = http_get_call( + url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') + json_obj = json.loads(json_string) + # there should be no outpoint because it has just spent (by mempool tx) + assert_equal(len(json_obj['utxos']), 0) + + self.nodes[0].generate(1) + self.sync_all() + + json_request = '/' + spending + json_string = http_get_call( + url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') + json_obj = json.loads(json_string) + # there should be an outpoint because it was mined + assert_equal(len(json_obj['utxos']), 1) + + json_request = '/checkmempool/' + spending + json_string = http_get_call( + url.hostname, url.port, '/rest/getutxos' + json_request + self.FORMAT_SEPARATOR + 'json') + json_obj = json.loads(json_string) + # there should be an outpoint because it was mined + assert_equal(len(json_obj['utxos']), 1) + # do some invalid requests json_request = '{"checkmempool' response = http_post_call(