From ba32ad862085c52ba77d457f2adf0121057d0bbf Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 27 Mar 2018 21:04:22 +0200 Subject: [PATCH 01/13] Merge #12653: Allow to optional specify the directory for the blocks storage a192636 -blocksdir: keep blockindex leveldb database in datadir (Jonas Schnelli) f38e4fd QA: Add -blocksdir test (Jonas Schnelli) 386a6b6 Allow to optional specify the directory for the blocks storage (Jonas Schnelli) Pull request description: Since the actual block files taking up more and more space, it may be desirable to have them stored in a different location then the data directory (use case: SSD for chainstate, etc., HD for blocks). This PR adds a `-blocksdir` option that allows one to keep the blockfiles and the blockindex external from the data directory (instead of creating symlinks). I fist had an option to keep the blockindex within the datadir, but seems to make no sense since accessing the index will (always) lead to access (r/w) the block files. Tree-SHA512: f8b9e1a681679eac25076dc30e45e6e12d4b2d9ac4be907cbea928a75af081dbcb0f1dd3e97169ab975f73d0bd15824c00c2a34638f3b284b39017171fce2409 --- src/init.cpp | 9 ++++++-- src/qt/dash.cpp | 2 +- src/txdb.cpp | 2 +- src/util.cpp | 33 +++++++++++++++++++++++++++ src/util.h | 1 + src/validation.cpp | 12 +++++----- src/validation.h | 2 +- test/functional/feature_blocksdir.py | 34 ++++++++++++++++++++++++++++ test/functional/test_runner.py | 1 + 9 files changed, 85 insertions(+), 11 deletions(-) create mode 100755 test/functional/feature_blocksdir.py diff --git a/src/init.cpp b/src/init.cpp index 14453622e838..0892a3580f92 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -456,6 +456,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-?", _("Print this help message and exit")); strUsage += HelpMessageOpt("-alertnotify=", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage +=HelpMessageOpt("-assumevalid=", strprintf(_("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)"), defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex())); + strUsage += HelpMessageOpt("-blocksdir=", _("Specify blocks directory (default: /blocks)")); strUsage += HelpMessageOpt("-blocknotify=", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); strUsage += HelpMessageOpt("-blockreconstructionextratxn=", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN)); if (showDebug) @@ -734,7 +735,7 @@ void CleanupBlockRevFiles() // Remove the rev files immediately and insert the blk file paths into an // ordered map keyed by block file index. LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n"); - fs::path blocksdir = GetDataDir() / "blocks"; + fs::path blocksdir = GetBlocksDir(); for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) { if (fs::is_regular_file(*it) && it->path().filename().string().length() == 12 && @@ -1111,6 +1112,10 @@ bool AppInitParameterInteraction() // also see: InitParameterInteraction() + if (!fs::is_directory(GetBlocksDir(false))) { + return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist.\n"), gArgs.GetArg("-blocksdir", "").c_str())); + } + // if using block pruning, then disallow txindex and require disabling governance validation if (gArgs.GetArg("-prune", 0)) { if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) @@ -2206,7 +2211,7 @@ bool AppInitMain() // ********************************************************* Step 11: import blocks - if (!CheckDiskSpace()) + if (!CheckDiskSpace() && !CheckDiskSpace(0, true)) return false; // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp index cb8ac4eaed45..f51f17dea3ca 100644 --- a/src/qt/dash.cpp +++ b/src/qt/dash.cpp @@ -597,7 +597,7 @@ int main(int argc, char *argv[]) if (!Intro::pickDataDirectory(*node)) return EXIT_SUCCESS; - /// 6. Determine availability of data directory and parse dash.conf + /// 6. Determine availability of data and blocks directory and parse dash.conf /// - Do not call GetDataDir(true) before this step finishes if (!fs::is_directory(GetDataDir(false))) { diff --git a/src/txdb.cpp b/src/txdb.cpp index 1672d34ff2f0..04f58cb8a1de 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -151,7 +151,7 @@ size_t CCoinsViewDB::EstimateSize() const return db.EstimateSize(DB_COIN, (char)(DB_COIN+1)); } -CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe), mapHasTxIndexCache(10000, 20000) { +CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(gArgs.IsArgSet("-blocksdir") ? GetDataDir() / "blocks" / "index" : GetBlocksDir() / "index", nCacheSize, fMemory, fWipe), mapHasTxIndexCache(10000, 20000) { } bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) { diff --git a/src/util.cpp b/src/util.cpp index 04093880bd0f..6dc6fe25a6f3 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -609,10 +609,41 @@ fs::path GetDefaultDataDir() #endif } +static fs::path g_blocks_path_cached; +static fs::path g_blocks_path_cache_net_specific; static fs::path pathCached; static fs::path pathCachedNetSpecific; static CCriticalSection csPathCached; +const fs::path &GetBlocksDir(bool fNetSpecific) +{ + + LOCK(csPathCached); + + fs::path &path = fNetSpecific ? g_blocks_path_cache_net_specific : g_blocks_path_cached; + + // This can be called during exceptions by LogPrintf(), so we cache the + // value so we don't have to do memory allocations after that. + if (!path.empty()) + return path; + + if (gArgs.IsArgSet("-blocksdir")) { + path = fs::system_complete(gArgs.GetArg("-blocksdir", "")); + if (!fs::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDataDir(false); + } + if (fNetSpecific) + path /= BaseParams().DataDir(); + + path /= "blocks"; + fs::create_directories(path); + return path; +} + const fs::path &GetDataDir(bool fNetSpecific) { @@ -659,6 +690,8 @@ void ClearDatadirCache() pathCached = fs::path(); pathCachedNetSpecific = fs::path(); + g_blocks_path_cached = fs::path(); + g_blocks_path_cache_net_specific = fs::path(); } fs::path GetConfigFile(const std::string& confPath) diff --git a/src/util.h b/src/util.h index 5dc45d4b7de0..38582daa950d 100644 --- a/src/util.h +++ b/src/util.h @@ -105,6 +105,7 @@ void ReleaseDirectoryLocks(); bool TryCreateDirectories(const fs::path& p); fs::path GetDefaultDataDir(); +const fs::path &GetBlocksDir(bool fNetSpecific = true); const fs::path &GetDataDir(bool fNetSpecific = true); fs::path GetBackupsDir(); void ClearDatadirCache(); diff --git a/src/validation.cpp b/src/validation.cpp index 21320431eaa2..7eee43c189f5 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2474,7 +2474,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState & // Write blocks and block index to disk. if (fDoFullFlush || fPeriodicWrite) { // Depend on nMinDiskSpace to ensure we can write block index - if (!CheckDiskSpace(0)) + if (!CheckDiskSpace(0, true)) return state.Error("out of disk space"); // First make sure all block and undo data is flushed to disk. FlushBlockFile(); @@ -3373,7 +3373,7 @@ static bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int if (nNewChunks > nOldChunks) { if (fPruneMode) fCheckForPruning = true; - if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) { + if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos, true)) { FILE *file = OpenBlockFile(pos); if (file) { LogPrintf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); @@ -3406,7 +3406,7 @@ static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, if (nNewChunks > nOldChunks) { if (fPruneMode) fCheckForPruning = true; - if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { + if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos, true)) { FILE *file = OpenUndoFile(pos); if (file) { LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); @@ -4056,9 +4056,9 @@ static void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfte nLastBlockWeCanPrune, count); } -bool CheckDiskSpace(uint64_t nAdditionalBytes) +bool CheckDiskSpace(uint64_t nAdditionalBytes, bool blocks_dir) { - uint64_t nFreeBytesAvailable = fs::space(GetDataDir()).available; + uint64_t nFreeBytesAvailable = fs::space(blocks_dir ? GetBlocksDir() : GetDataDir()).available; // Check for nMinDiskSpace bytes (currently 50MB) if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) @@ -4101,7 +4101,7 @@ static FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) { fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix) { - return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile); + return GetBlocksDir() / strprintf("%s%05u.dat", prefix, pos.nFile); } CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash) diff --git a/src/validation.h b/src/validation.h index c6ee9ca12388..a2a435457554 100644 --- a/src/validation.h +++ b/src/validation.h @@ -258,7 +258,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr, CBlockHeader* first_invalid = nullptr) LOCKS_EXCLUDED(cs_main); /** Check whether enough disk space is available for an incoming block */ -bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); +bool CheckDiskSpace(uint64_t nAdditionalBytes = 0, bool blocks_dir = false); /** Open a block file (blk?????.dat) */ FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false); /** Translation to a filesystem path */ diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py new file mode 100755 index 000000000000..6ee6cb9a3e69 --- /dev/null +++ b/test/functional/feature_blocksdir.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test the blocksdir option. +""" + +from test_framework.test_framework import BitcoinTestFramework, initialize_datadir + +import shutil +import os + +class BlocksdirTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 1 + + def run_test(self): + self.stop_node(0) + node0path = os.path.join(self.options.tmpdir, "node0") + shutil.rmtree(node0path) + initialize_datadir(self.options.tmpdir, 0) + self.log.info("Starting with non exiting blocksdir ...") + self.assert_start_raises_init_error(0, ["-blocksdir="+self.options.tmpdir+ "/blocksdir"], "Specified blocks director") + os.mkdir(self.options.tmpdir+ "/blocksdir") + self.log.info("Starting with exiting blocksdir ...") + self.start_node(0, ["-blocksdir="+self.options.tmpdir+ "/blocksdir"]) + self.log.info("mining blocks..") + self.nodes[0].generate(10) + assert(os.path.isfile(os.path.join(self.options.tmpdir, "blocksdir", "regtest", "blocks", "blk00000.dat"))) + assert(os.path.isdir(os.path.join(self.options.tmpdir, "node0", "regtest", "blocks", "index"))) + +if __name__ == '__main__': + BlocksdirTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 95067e71e40c..cf93fcbb538f 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -157,6 +157,7 @@ 'p2p_unrequested_blocks.py', 'feature_logging.py', 'p2p_node_network_limited.py', + 'feature_blocksdir.py', 'feature_config_args.py', 'feature_help.py', # Don't append tests at the end to avoid merge conflicts From af08c755798b3d7ee6822c0349b877b7a0360d29 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 27 Jul 2018 14:38:45 -0400 Subject: [PATCH 02/13] Merge #13775: doc: Remove newlines from error message 620361fce8 Fix accidental use of the addition assignment operator ("+="). Remove newlines from error message. (practicalswift) Pull request description: Fix accidental use of the addition assignment operator (`+=`). _Note to reviewers:_ Perhaps the `\n`:s should be removed too? Tree-SHA512: 4e8c2dfd6025d78ef9d60522297994829dacc447e6b6782e15c0bdd5dd2daa17ca9a8948bfa9a15be57d9286092356381d7e6747980303852d273eb0df0dd76b --- src/init.cpp | 2 +- src/wallet/wallet.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 0892a3580f92..1b1853b37d81 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1113,7 +1113,7 @@ bool AppInitParameterInteraction() // also see: InitParameterInteraction() if (!fs::is_directory(GetBlocksDir(false))) { - return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist.\n"), gArgs.GetArg("-blocksdir", "").c_str())); + return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), gArgs.GetArg("-blocksdir", "").c_str())); } // if using block pruning, then disallow txindex and require disabling governance validation diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 06cf28f731bc..4eb96e1a11e5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5188,7 +5188,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& // Top up the keypool if (!walletInstance->TopUpKeyPool()) { - return error(_("Unable to generate initial keys") += "\n"); + return error(_("Unable to generate initial keys")); } walletInstance->SetBestChain(chainActive.GetLocator()); From 9909c3aca715b413d86102ca8db62f7994024e29 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 27 Mar 2018 21:31:27 +0200 Subject: [PATCH 03/13] 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 --- src/rest.cpp | 38 ++++++++++++++++-------------- src/txmempool.cpp | 2 +- src/txmempool.h | 2 +- test/functional/interface_rest.py | 39 +++++++++++++++++++++++++------ 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/rest.cpp b/src/rest.cpp index c1337de64ded..0c94fdcb9ec1 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -487,26 +487,28 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) std::vector hits; bitmap.resize((vOutPoints.size() + 7) / 8); { - LOCK2(cs_main, mempool.cs); - - CCoinsView viewDummy; - CCoinsViewCache view(&viewDummy); - - CCoinsViewCache& viewChain = *pcoinsTip; - CCoinsViewMemPool viewMempool(&viewChain, mempool); - - if (fCheckMemPool) - view.SetBackend(viewMempool); // switch cache backend to db+mempool in case user likes to query mempool - - for (size_t i = 0; i < vOutPoints.size(); i++) { - bool hit = false; - Coin coin; - if (view.GetCoin(vOutPoints[i], coin) && !mempool.isSpent(vOutPoints[i])) { - hit = true; - outs.emplace_back(std::move(coin)); + 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) { + // use db+mempool as cache backend in case user likes to query mempool + LOCK2(cs_main, mempool.cs); + CCoinsViewCache& viewChain = *pcoinsTip; + CCoinsViewMemPool viewMempool(&viewChain, mempool); + process_utxos(viewMempool, mempool); + } else { + LOCK(cs_main); // no need to lock mempool! + process_utxos(*pcoinsTip, CTxMemPool()); + } - hits.push_back(hit); + for (size_t i = 0; i < hits.size(); ++i) { + const bool hit = hits[i]; bitmapStringRepresentation.append(hit ? "1" : "0"); // form a binary string representation (human-readable for json output) bitmap[i / 8] |= ((uint8_t)hit) << (i % 8); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 32e723a8a662..3b01199834df 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -340,7 +340,7 @@ CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) : nCheckFrequency = 0; } -bool CTxMemPool::isSpent(const COutPoint& outpoint) +bool CTxMemPool::isSpent(const COutPoint& outpoint) const { LOCK(cs); return mapNextTx.count(outpoint); diff --git a/src/txmempool.h b/src/txmempool.h index c89069154b57..1186b9466e5c 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -589,7 +589,7 @@ class CTxMemPool void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free 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/test/functional/interface_rest.py b/test/functional/interface_rest.py index 30d60299ba4e..7b8e00d57946 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -84,7 +84,7 @@ def run_test(self): ####################################### # 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) @@ -99,7 +99,7 @@ def run_test(self): ################################################# # 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) @@ -116,7 +116,7 @@ def run_test(self): ################################################## # 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) assert_equal(len(json_obj['utxos']), 1) @@ -150,23 +150,48 @@ def run_test(self): txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) 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) - assert_equal(len(json_obj['utxos']), 0) #there should be an outpoint because it has just added to the mempool + assert_equal(len(json_obj['utxos']), 0) #there should be no outpoint because it has just added to the mempool - 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) assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it has just added to the mempool + 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) + assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because its spending tx is not confirmed + + 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) + assert_equal(len(json_obj['utxos']), 0) #there should be no outpoint because it has just spent (by mempool tx) + + 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) + assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it was mined + + 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) + assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it was mined + #do some invalid requests json_request = '{"checkmempool' response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True) From f8a2413b4995a723601a99f004ef67cb3686c5f3 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 27 Mar 2018 20:16:45 +0200 Subject: [PATCH 04/13] Merge #12714: Introduce interface for signing providers d40f06a Introduce interface for signing providers (Pieter Wuille) Pull request description: `CKeyStore` is a rich interface that provides many features, including knowledge of scripts and pubkeys for solving, private keys for signing, in addition to watch-only keys and scripts, and distinguishing lack of keys from them just being encrypted. The signing logic in script/sign does not actually need most of these features. Here we introduce a simpler interface (`SigningProvider`) which *only* provides keys and scripts. This is actually sufficient for signing. In addtion, we swap the dependency between keystore and script/sign (keystore now depends on script/script with `CKeyStore` deriving from `SigningProvider`, rather than `CKeyStore` being the interface that signing relies on). This is a very early step towards the design in https://gist.github.com/sipa/125cfa1615946d0c3f3eec2ad7f250a2, separating the concern between deciding what outputs are ours and signing. Tree-SHA512: d511b7b03eec0e513530db1d9ae5aacf6d0bfa1d3e1c03d06c5bde396bafb5824c4491b227d32bcda9288530caf49835da18e846ccf66538d6c0cc6ae27291c9 Signed-off-by: pasta # Conflicts: # src/script/sign.cpp # src/script/sign.h --- src/keystore.h | 8 ++------ src/script/sign.cpp | 17 ++++++++--------- src/script/sign.h | 29 ++++++++++++++++++++--------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/keystore.h b/src/keystore.h index 234d68dee483..9eb66b9b7d01 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -10,35 +10,31 @@ #include #include #include