From ac51a26bdc69dc35e1f4f89b62c3134047e93bc1 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 11 Nov 2017 09:05:36 +0000 Subject: [PATCH 001/900] During IBD, when doing pruning, prune 10% extra to avoid pruning again soon after Pruning forces a chainstate flush, which can defeat the dbcache and harm performance significantly. --- src/validation.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 4ce0723b2..7f447d4fc 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3391,6 +3391,15 @@ void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight int count=0; if (nCurrentUsage + nBuffer >= nPruneTarget) { + // On a prune event, the chainstate DB is flushed. + // To avoid excessive prune events negating the benefit of high dbcache + // values, we should not prune too rapidly. + // So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon. + if (IsInitialBlockDownload()) { + // Since this is only relevant during IBD, we use a fixed 10% + nBuffer += nPruneTarget / 10; + } + for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize; From c198dc00e1611b43d031920e7f9912fc25a359c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Capek?= Date: Sun, 24 Dec 2017 11:00:30 +0000 Subject: [PATCH 002/900] [Doc] Clarify the meaning of fee delta not being a fee rate in prioritisetransaction RPC --- src/rpc/mining.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index d003be495..caa9a7d53 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -240,6 +240,7 @@ UniValue prioritisetransaction(const JSONRPCRequest& request) "2. dummy (numeric, optional) API-Compatibility for previous API. Must be zero or null.\n" " DEPRECATED. For forward compatibility use named arguments and omit this parameter.\n" "3. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n" + " Note, that this value is not a fee rate. It is a value to modify absolute fee of the TX.\n" " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" " considers the transaction as it would have paid a higher (or lower) fee.\n" "\nResult:\n" From 1e0ee9095ce87a3cee0b44a120f6297ac672f5d0 Mon Sep 17 00:00:00 2001 From: Martin Ankerl Date: Fri, 29 Dec 2017 11:36:11 +0100 Subject: [PATCH 003/900] Use best-fit strategy in Arena, now O(log(n)) instead O(n) This replaces the first-fit algorithm used in the Arena with a best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review", Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, both startegies work well in practice. The advantage of using best-fit is that we can switch the slow O(n) algorithm to O(log(n)) operations. Additionally, some previously O(log(n)) operations are now replaced with O(1) operations by using a hash map. The end effect is that the benchmark runs about 2.5 times faster on my machine: old: BenchLockedPool, 5, 530, 5.25749, 0.00196938, 0.00199755, 0.00198172 new: BenchLockedPool, 5, 1300, 5.11313, 0.000781493, 0.000793314, 0.00078606 I've run all unit tests and benchmarks. --- src/bench/lockedpool.cpp | 2 +- src/support/lockedpool.cpp | 70 ++++++++++++++++++++++++-------------- src/support/lockedpool.h | 19 ++++++++--- 3 files changed, 60 insertions(+), 31 deletions(-) diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp index 914e37a2e..8b7fe5f60 100644 --- a/src/bench/lockedpool.cpp +++ b/src/bench/lockedpool.cpp @@ -43,4 +43,4 @@ static void BenchLockedPool(benchmark::State& state) addr.clear(); } -BENCHMARK(BenchLockedPool, 530); +BENCHMARK(BenchLockedPool, 1300); diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index 98e869418..ddb84b652 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -47,7 +47,9 @@ Arena::Arena(void *base_in, size_t size_in, size_t alignment_in): base(static_cast(base_in)), end(static_cast(base_in) + size_in), alignment(alignment_in) { // Start with one free chunk that covers the entire arena - chunks_free.emplace(base, size_in); + auto it = size_to_free_chunk.emplace(size_in, base); + chunks_free.emplace(base, it); + chunks_free_end.emplace(base + size_in, it); } Arena::~Arena() @@ -63,26 +65,30 @@ void* Arena::alloc(size_t size) if (size == 0) return nullptr; - // Pick a large enough free-chunk - auto it = std::find_if(chunks_free.begin(), chunks_free.end(), - [=](const std::map::value_type& chunk){ return chunk.second >= size; }); - if (it == chunks_free.end()) + // Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key. + // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review", + // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit + // policies seem to work well in practice. + auto sizePtrIt = size_to_free_chunk.lower_bound(size); + if (sizePtrIt == size_to_free_chunk.end()) return nullptr; // Create the used-chunk, taking its space from the end of the free-chunk - auto alloced = chunks_used.emplace(it->first + it->second - size, size).first; - if (!(it->second -= size)) - chunks_free.erase(it); - return reinterpret_cast(alloced->first); -} - -/* extend the Iterator if other begins at its end */ -template bool extend(Iterator it, const Pair& other) { - if (it->first + it->second == other.first) { - it->second += other.second; - return true; + const size_t sizeRemaining = sizePtrIt->first - size; + auto alloced = chunks_used.emplace(sizePtrIt->second + sizeRemaining, size).first; + chunks_free_end.erase(sizePtrIt->second + sizePtrIt->first); + if (sizePtrIt->first == size) { + // whole chunk is used up + chunks_free.erase(sizePtrIt->second); + } else { + // still some memory left in the chunk + auto itRemaining = size_to_free_chunk.emplace(sizeRemaining, sizePtrIt->second); + chunks_free[sizePtrIt->second] = itRemaining; + chunks_free_end.emplace(sizePtrIt->second + sizeRemaining, itRemaining); } - return false; + size_to_free_chunk.erase(sizePtrIt); + + return reinterpret_cast(alloced->first); } void Arena::free(void *ptr) @@ -97,16 +103,30 @@ void Arena::free(void *ptr) if (i == chunks_used.end()) { throw std::runtime_error("Arena: invalid or double free"); } - auto freed = *i; + std::pair freed = *i; chunks_used.erase(i); - // Add space to free map, coalescing contiguous chunks - auto next = chunks_free.upper_bound(freed.first); - auto prev = (next == chunks_free.begin()) ? chunks_free.end() : std::prev(next); - if (prev == chunks_free.end() || !extend(prev, freed)) - prev = chunks_free.emplace_hint(next, freed); - if (next != chunks_free.end() && extend(prev, *next)) + // Coalesc freed with previous chunk + auto prev = chunks_free_end.find(freed.first); + if (prev != chunks_free_end.end()) { + freed.first -= prev->second->first; + freed.second += prev->second->first; + size_to_free_chunk.erase(prev->second); + chunks_free_end.erase(prev); + } + + // Coalesc freed with chunk after freed + auto next = chunks_free.find(freed.first + freed.second); + if (next != chunks_free.end()) { + freed.second += next->second->first; + size_to_free_chunk.erase(next->second); chunks_free.erase(next); + } + + // Add/set space with coalesced free chunk + auto it = size_to_free_chunk.emplace(freed.second, freed.first); + chunks_free[freed.first] = it; + chunks_free_end[freed.first + freed.second] = it; } Arena::Stats Arena::stats() const @@ -115,7 +135,7 @@ Arena::Stats Arena::stats() const for (const auto& chunk: chunks_used) r.used += chunk.second; for (const auto& chunk: chunks_free) - r.free += chunk.second; + r.free += chunk.second->first; r.total = r.used + r.free; return r; } diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h index 834f0371e..3b6f82c6c 100644 --- a/src/support/lockedpool.h +++ b/src/support/lockedpool.h @@ -10,6 +10,7 @@ #include #include #include +#include /** * OS-dependent allocation and deallocation of locked/pinned memory pages. @@ -88,11 +89,19 @@ class Arena */ bool addressInArena(void *ptr) const { return ptr >= base && ptr < end; } private: - /** Map of chunk address to chunk information. This class makes use of the - * sorted order to merge previous and next chunks during deallocation. - */ - std::map chunks_free; - std::map chunks_used; + typedef std::multimap SizeToChunkSortedMap; + /** Map to enable O(log(n)) best-fit allocation, as it's sorted by size */ + SizeToChunkSortedMap size_to_free_chunk; + + typedef std::unordered_map ChunkToSizeMap; + /** Map from begin of free chunk to its node in size_to_free_chunk */ + ChunkToSizeMap chunks_free; + /** Map from end of free chunk to its node in size_to_free_chunk */ + ChunkToSizeMap chunks_free_end; + + /** Map from begin of used chunk to its size */ + std::unordered_map chunks_used; + /** Base address of arena */ char* base; /** End address of arena */ From 5fbf7c478a996974502d5d787b2ccf2fcc91ac78 Mon Sep 17 00:00:00 2001 From: Martin Ankerl Date: Sat, 6 Jan 2018 09:13:41 +0100 Subject: [PATCH 004/900] fix nits: variable naming, typos --- src/support/lockedpool.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index ddb84b652..195412985 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -69,24 +69,24 @@ void* Arena::alloc(size_t size) // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review", // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit // policies seem to work well in practice. - auto sizePtrIt = size_to_free_chunk.lower_bound(size); - if (sizePtrIt == size_to_free_chunk.end()) + auto size_ptr_it = size_to_free_chunk.lower_bound(size); + if (size_ptr_it == size_to_free_chunk.end()) return nullptr; // Create the used-chunk, taking its space from the end of the free-chunk - const size_t sizeRemaining = sizePtrIt->first - size; - auto alloced = chunks_used.emplace(sizePtrIt->second + sizeRemaining, size).first; - chunks_free_end.erase(sizePtrIt->second + sizePtrIt->first); - if (sizePtrIt->first == size) { + const size_t size_remaining = size_ptr_it->first - size; + auto alloced = chunks_used.emplace(size_ptr_it->second + size_remaining, size).first; + chunks_free_end.erase(size_ptr_it->second + size_ptr_it->first); + if (size_ptr_it->first == size) { // whole chunk is used up - chunks_free.erase(sizePtrIt->second); + chunks_free.erase(size_ptr_it->second); } else { // still some memory left in the chunk - auto itRemaining = size_to_free_chunk.emplace(sizeRemaining, sizePtrIt->second); - chunks_free[sizePtrIt->second] = itRemaining; - chunks_free_end.emplace(sizePtrIt->second + sizeRemaining, itRemaining); + auto it_remaining = size_to_free_chunk.emplace(size_remaining, size_ptr_it->second); + chunks_free[size_ptr_it->second] = it_remaining; + chunks_free_end.emplace(size_ptr_it->second + size_remaining, it_remaining); } - size_to_free_chunk.erase(sizePtrIt); + size_to_free_chunk.erase(size_ptr_it); return reinterpret_cast(alloced->first); } @@ -106,7 +106,7 @@ void Arena::free(void *ptr) std::pair freed = *i; chunks_used.erase(i); - // Coalesc freed with previous chunk + // coalesce freed with previous chunk auto prev = chunks_free_end.find(freed.first); if (prev != chunks_free_end.end()) { freed.first -= prev->second->first; @@ -115,7 +115,7 @@ void Arena::free(void *ptr) chunks_free_end.erase(prev); } - // Coalesc freed with chunk after freed + // coalesce freed with chunk after freed auto next = chunks_free.find(freed.first + freed.second); if (next != chunks_free.end()) { freed.second += next->second->first; From 1e747e3c1e04a38c5ed6e8f8cd14077b8b7377c9 Mon Sep 17 00:00:00 2001 From: Mark Friedenbach Date: Fri, 12 Jan 2018 16:31:22 +0900 Subject: [PATCH 005/900] Make segwit failure due to CLEANSTACK violation return a SCRIPT_ERR_CLEANSTACK error code. --- src/script/interpreter.cpp | 2 +- src/test/data/script_tests.json | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 2cdff7ee5..c08b071e0 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1400,7 +1400,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, // Scripts inside witness implicitly require cleanstack behaviour if (stack.size() != 1) - return set_error(serror, SCRIPT_ERR_EVAL_FALSE); + return set_error(serror, SCRIPT_ERR_CLEANSTACK); if (!CastToBool(stack.back())) return set_error(serror, SCRIPT_ERR_EVAL_FALSE); return true; diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index 63f43c0fc..c2ec041f8 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -2541,22 +2541,22 @@ [["01", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "OK"], [["02", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "OK"], [["0100", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "OK"], -[["", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "EVAL_FALSE"], -[["00", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "EVAL_FALSE"], +[["", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "CLEANSTACK"], +[["00", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "CLEANSTACK"], [["01", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "OK"], [["02", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], [["0100", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], -[["", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"], +[["", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "CLEANSTACK"], [["00", "635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], [["635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS", "UNBALANCED_CONDITIONAL"], [["635168", 0.00000001], "", "0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "P2SH,WITNESS,MINIMALIF", "UNBALANCED_CONDITIONAL"], ["P2WSH NOTIF 1 ENDIF"], -[["01", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "EVAL_FALSE"], -[["02", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "EVAL_FALSE"], -[["0100", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "EVAL_FALSE"], +[["01", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "CLEANSTACK"], +[["02", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "CLEANSTACK"], +[["0100", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "CLEANSTACK"], [["", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "OK"], [["00", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS", "OK"], -[["01", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"], +[["01", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "CLEANSTACK"], [["02", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], [["0100", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], [["", "645168", 0.00000001], "", "0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "P2SH,WITNESS,MINIMALIF", "OK"], @@ -2570,22 +2570,22 @@ [["01", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "OK"], [["02", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "OK"], [["0100", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "OK"], -[["", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "EVAL_FALSE"], -[["00", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "EVAL_FALSE"], +[["", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "CLEANSTACK"], +[["00", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "CLEANSTACK"], [["01", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"], [["02", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], [["0100", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], -[["", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"], +[["", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "CLEANSTACK"], [["00", "635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], [["635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS", "UNBALANCED_CONDITIONAL"], [["635168", 0.00000001], "0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d", "HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL", "P2SH,WITNESS,MINIMALIF", "UNBALANCED_CONDITIONAL"], ["P2SH-P2WSH NOTIF 1 ENDIF"], -[["01", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "EVAL_FALSE"], -[["02", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "EVAL_FALSE"], -[["0100", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "EVAL_FALSE"], +[["01", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "CLEANSTACK"], +[["02", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "CLEANSTACK"], +[["0100", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "CLEANSTACK"], [["", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "OK"], [["00", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS", "OK"], -[["01", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "EVAL_FALSE"], +[["01", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "CLEANSTACK"], [["02", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], [["0100", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "MINIMALIF"], [["", "645168", 0.00000001], "0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8", "HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL", "P2SH,WITNESS,MINIMALIF", "OK"], From ffcc687c556692de9dd368872d5361faa9aba0e4 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 20 Dec 2017 19:47:02 +0100 Subject: [PATCH 006/900] [net] add seed.bitcoin.sprovoost.nl to DNS seeds --- src/chainparams.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 96e9b2727..f4160f0a4 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -135,6 +135,7 @@ class CMainParams : public CChainParams { vSeeds.emplace_back("seed.bitcoinstats.com"); // Christian Decker, supports x1 - xf vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch"); // Jonas Schnelli, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.btc.petertodd.org"); // Peter Todd, only supports x1, x5, x9, and xd + vSeeds.emplace_back("seed.bitcoin.sprovoost.nl"); // Sjors Provoost base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,0); base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,5); From 0851a75b5aad7b05a1cfb4a285ddc9e3319f887b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Fri, 16 Feb 2018 12:57:47 +0000 Subject: [PATCH 007/900] rpc: Interrupt block generation on shutdown request --- src/rpc/mining.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 3f3bfa0cf..28b16a402 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -116,7 +116,7 @@ UniValue generateBlocks(std::shared_ptr coinbaseScript, int nGen } unsigned int nExtraNonce = 0; UniValue blockHashes(UniValue::VARR); - while (nHeight < nHeightEnd) + while (nHeight < nHeightEnd && !ShutdownRequested()) { std::unique_ptr pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) From f8c249ab918b0b4d326b8c441816c64d046455bf Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Fri, 16 Feb 2018 20:28:03 +0000 Subject: [PATCH 008/900] Assert CPubKey::ValidLength to the pubkey's header-relevent size Previously this was an inline test where the specificity was probably judged overly specific. As a class method it makes sense to maintain consistency. And replace some magic values with their constant equivalents. --- src/keystore.cpp | 2 +- src/pubkey.h | 5 +++++ src/script/interpreter.cpp | 8 ++++---- src/script/standard.cpp | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/keystore.cpp b/src/keystore.cpp index fab1b81c9..e3f2a1700 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -131,7 +131,7 @@ static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut) CScript::const_iterator pc = dest.begin(); opcodetype opcode; std::vector vch; - if (!dest.GetOp(pc, opcode, vch) || vch.size() < 33 || vch.size() > 65) + if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch)) return false; pubKeyOut = CPubKey(vch); if (!pubKeyOut.IsFullyValid()) diff --git a/src/pubkey.h b/src/pubkey.h index 59bf56395..9c6c6b085 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -70,6 +70,11 @@ class CPubKey } public: + + bool static ValidSize(const std::vector &vch) { + return vch.size() > 0 && GetLen(vch[0]) == vch.size(); + } + //! Construct an invalid public key. CPubKey() { diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 2cdff7ee5..de9e3b3b1 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -61,17 +61,17 @@ static inline void popstack(std::vector& stack) } bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { - if (vchPubKey.size() < 33) { + if (vchPubKey.size() < CPubKey::COMPRESSED_PUBLIC_KEY_SIZE) { // Non-canonical public key: too short return false; } if (vchPubKey[0] == 0x04) { - if (vchPubKey.size() != 65) { + if (vchPubKey.size() != CPubKey::PUBLIC_KEY_SIZE) { // Non-canonical public key: invalid length for uncompressed key return false; } } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) { - if (vchPubKey.size() != 33) { + if (vchPubKey.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE) { // Non-canonical public key: invalid length for compressed key return false; } @@ -83,7 +83,7 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { } bool static IsCompressedPubKey(const valtype &vchPubKey) { - if (vchPubKey.size() != 33) { + if (vchPubKey.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE) { // Non-canonical public key: invalid length for compressed key return false; } diff --git a/src/script/standard.cpp b/src/script/standard.cpp index cfb3c5858..0b9053d7f 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -132,7 +132,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector= 33 && vch1.size() <= 65) + while (CPubKey::ValidSize(vch1)) { vSolutionsRet.push_back(vch1); if (!script1.GetOp(pc1, opcode1, vch1)) @@ -146,7 +146,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector 65) + if (!CPubKey::ValidSize(vch1)) break; vSolutionsRet.push_back(vch1); } From 08b17def58d4135c1dc904a6068670c3c92a3768 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Mon, 26 Feb 2018 15:34:53 +0900 Subject: [PATCH 009/900] [arith_uint256] Do not destroy *this content if passed-in operator may reference it --- src/arith_uint256.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 65de63230..c7ddb17eb 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -69,16 +69,16 @@ base_uint& base_uint::operator*=(uint32_t b32) template base_uint& base_uint::operator*=(const base_uint& b) { - base_uint a = *this; - *this = 0; + base_uint a; for (int j = 0; j < WIDTH; j++) { uint64_t carry = 0; for (int i = 0; i + j < WIDTH; i++) { - uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i]; - pn[i + j] = n & 0xffffffff; + uint64_t n = carry + a.pn[i + j] + (uint64_t)pn[j] * b.pn[i]; + a.pn[i + j] = n & 0xffffffff; carry = n >> 32; } } + *this = a; return *this; } From b120f7bdbee83c00e46a9ec6d0cd09a816631f45 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Mon, 26 Feb 2018 15:34:11 +0900 Subject: [PATCH 010/900] [test] Add tests for self usage in arith_uint256 --- src/test/uint256_tests.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index ad5478e82..20ed29f59 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -266,4 +266,17 @@ BOOST_AUTO_TEST_CASE( conversion ) BOOST_CHECK(R2L.GetHex() == UintToArith256(R2L).GetHex()); } +BOOST_AUTO_TEST_CASE( operator_with_self ) +{ + arith_uint256 v = UintToArith256(uint256S("02")); + v *= v; + BOOST_CHECK(v == UintToArith256(uint256S("04"))); + v /= v; + BOOST_CHECK(v == UintToArith256(uint256S("01"))); + v += v; + BOOST_CHECK(v == UintToArith256(uint256S("02"))); + v -= v; + BOOST_CHECK(v == UintToArith256(uint256S("0"))); +} + BOOST_AUTO_TEST_SUITE_END() From 0e7c52dc6cbb8fd881a0dd57a6167a812fe71dc4 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 5 Mar 2018 10:42:26 -0500 Subject: [PATCH 011/900] Shut down if trying to connect a corrupted block The call to CheckBlock() in ConnectBlock() is redundant with calls to it prior to storing a block on disk. If CheckBlock() fails with an error indicating the block is potentially corrupted, then shut down immediately, as this is an indication that the node is experiencing hardware issues. (If we didn't shut down, we could go into an infinite loop trying to reconnect this same bad block, as we're not setting the block's status to FAILED in the case where there is potential corruption.) If CheckBlock() fails for some other reason, we'll end up flagging this block as bad (perhaps some prior software version "let a bad block in", as the comment indicates), and not trying to connect it again, so this case should be properly handled. --- src/validation.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index d2438b060..8ec30cac3 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1791,8 +1791,15 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // is enforced in ContextualCheckBlockHeader(); we wouldn't want to // re-enforce that rule here (at least until we make it impossible for // GetAdjustedTime() to go backward). - if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck)) + if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck)) { + if (state.CorruptionPossible()) { + // We don't write down blocks to disk if they may have been + // corrupted, so this should be impossible unless we're having hardware + // problems. + return AbortNode(state, "Corrupt block found indicating potential hardware failure; shutting down"); + } return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); + } // verify that the view's current state corresponds to the previous block uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); From 3dba3c3ac1679cf0086ee7734eee12268004ace7 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 9 Sep 2016 09:25:13 +0000 Subject: [PATCH 012/900] Qt: Load all wallets into WalletModels --- src/qt/bitcoin.cpp | 31 +++++++++++++++++++++---------- src/qt/bitcoingui.cpp | 4 ---- src/qt/bitcoingui.h | 1 - 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index ab381bfb5..424d82ae1 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -251,7 +251,7 @@ public Q_SLOTS: QTimer *pollShutdownTimer; #ifdef ENABLE_WALLET PaymentServer* paymentServer; - WalletModel *walletModel; + std::vector m_wallet_models; #endif int returnValue; const PlatformStyle *platformStyle; @@ -333,7 +333,7 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv): pollShutdownTimer(0), #ifdef ENABLE_WALLET paymentServer(0), - walletModel(0), + m_wallet_models(), #endif returnValue(0) { @@ -451,8 +451,10 @@ void BitcoinApplication::requestShutdown() #ifdef ENABLE_WALLET window->removeAllWallets(); - delete walletModel; - walletModel = 0; + for (WalletModel *walletModel : m_wallet_models) { + delete walletModel; + } + m_wallet_models.clear(); #endif delete clientModel; clientModel = 0; @@ -481,16 +483,25 @@ void BitcoinApplication::initializeResult(bool success) window->setClientModel(clientModel); #ifdef ENABLE_WALLET - // TODO: Expose secondary wallets - if (!vpwallets.empty()) - { - walletModel = new WalletModel(platformStyle, vpwallets[0], optionsModel); + bool fFirstWallet = true; + for (CWalletRef pwallet : vpwallets) { + WalletModel * const walletModel = new WalletModel(platformStyle, pwallet, optionsModel); - window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel); - window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET); + QString WalletName = QString::fromStdString(pwallet->GetName()); + if (WalletName.endsWith(".dat")) { + WalletName.truncate(WalletName.size() - 4); + } + + window->addWallet(WalletName, walletModel); + if (fFirstWallet) { + window->setCurrentWallet(WalletName); + fFirstWallet = false; + } connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)), paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray))); + + m_wallet_models.push_back(walletModel); } #endif diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 4e868b7c1..0bf1d5c55 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -70,10 +70,6 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM = #endif ; -/** Display name for default wallet name. Uses tilde to avoid name - * collisions in the future with additional wallets */ -const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; - BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), enableWallet(false), diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index ddb7ecb76..b1ec6540c 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -46,7 +46,6 @@ class BitcoinGUI : public QMainWindow Q_OBJECT public: - static const QString DEFAULT_WALLET; static const std::string DEFAULT_UIPLATFORM; explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0); From e449f9a9e620fb909eb7b32d815b413d235f05ad Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 9 Sep 2016 10:43:54 +0000 Subject: [PATCH 013/900] Qt: Add a combobox to toolbar to select from multiple wallets --- src/qt/bitcoingui.cpp | 23 +++++++++++++++++++++++ src/qt/bitcoingui.h | 8 +++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 0bf1d5c55..92fb3f190 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -459,6 +460,23 @@ void BitcoinGUI::createToolBars() toolbar->addAction(receiveCoinsAction); toolbar->addAction(historyAction); overviewAction->setChecked(true); + +#ifdef ENABLE_WALLET + QWidget *spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + toolbar->addWidget(spacer); + + m_wallet_selector_label = new QLabel(); + m_wallet_selector_label->setText(tr("Wallet:") + " "); + toolbar->addWidget(m_wallet_selector_label); + m_wallet_selector_label->setVisible(false); + m_wallet_selector = new QComboBox(); + toolbar->addWidget(m_wallet_selector); + m_wallet_selector->setVisible(false); + m_wallet_selector_label->setBuddy(m_wallet_selector); + + connect(m_wallet_selector, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(setCurrentWallet(const QString&))); +#endif } } @@ -530,6 +548,11 @@ bool BitcoinGUI::addWallet(const QString& name, WalletModel *walletModel) if(!walletFrame) return false; setWalletActionsEnabled(true); + m_wallet_selector->addItem(name); + if (m_wallet_selector->count() == 2) { + m_wallet_selector->setVisible(true); + m_wallet_selector->setVisible(true); + } return walletFrame->addWallet(name, walletModel); } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index b1ec6540c..42581e7d1 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -33,6 +33,7 @@ class ModalOverlay; QT_BEGIN_NAMESPACE class QAction; +class QComboBox; class QProgressBar; class QProgressDialog; QT_END_NAMESPACE @@ -62,7 +63,6 @@ class BitcoinGUI : public QMainWindow functionality. */ bool addWallet(const QString& name, WalletModel *walletModel); - bool setCurrentWallet(const QString& name); void removeAllWallets(); #endif // ENABLE_WALLET bool enableWallet; @@ -111,6 +111,9 @@ class BitcoinGUI : public QMainWindow QAction *openAction; QAction *showHelpMessageAction; + QLabel *m_wallet_selector_label; + QComboBox *m_wallet_selector; + QSystemTrayIcon *trayIcon; QMenu *trayIconMenu; Notificator *notificator; @@ -170,6 +173,9 @@ public Q_SLOTS: void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr); #ifdef ENABLE_WALLET + bool setCurrentWallet(const QString& name); + +private: /** Set the encryption status as shown in the UI. @param[in] status current encryption status @see WalletModel::EncryptionStatus From 85d5319716b7b31b27bc7950d756465ae472f11d Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 24 Oct 2016 07:21:51 +0000 Subject: [PATCH 014/900] Qt: Ensure UI updates only come from the currently selected walletView --- src/qt/bitcoingui.cpp | 15 +++++++++++++++ src/qt/bitcoingui.h | 4 ++++ src/qt/walletframe.h | 1 + src/qt/walletmodel.cpp | 5 +++-- src/qt/walletmodel.h | 2 +- src/qt/walletview.cpp | 10 +++++----- src/qt/walletview.h | 5 +++-- 7 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 92fb3f190..b39aaef46 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -21,6 +21,7 @@ #ifdef ENABLE_WALLET #include #include +#include #endif // ENABLE_WALLET #ifdef Q_OS_MAC @@ -1097,6 +1098,20 @@ void BitcoinGUI::setEncryptionStatus(int status) break; } } + +void BitcoinGUI::updateWalletStatus() +{ + if (!walletFrame) { + return; + } + WalletView * const walletView = walletFrame->currentWalletView(); + if (!walletView) { + return; + } + WalletModel * const walletModel = walletView->getWalletModel(); + setEncryptionStatus(walletModel->getEncryptionStatus()); + setHDStatus(walletModel->hdEnabled()); +} #endif // ENABLE_WALLET void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 42581e7d1..597c583ef 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -174,6 +174,9 @@ public Q_SLOTS: #ifdef ENABLE_WALLET bool setCurrentWallet(const QString& name); + /** Set the UI status indicators based on the currently selected wallet. + */ + void updateWalletStatus(); private: /** Set the encryption status as shown in the UI. @@ -188,6 +191,7 @@ public Q_SLOTS: */ void setHDStatus(int hdEnabled); +public Q_SLOTS: bool handlePaymentRequest(const SendCoinsRecipient& recipient); /** Show incoming transaction notification for new transactions. */ diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 42ce69fea..ce37e456f 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -59,6 +59,7 @@ class WalletFrame : public QFrame const PlatformStyle *platformStyle; +public: WalletView *currentWalletView(); public Q_SLOTS: diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 34954a6bf..df1a996af 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -110,8 +110,9 @@ void WalletModel::updateStatus() { EncryptionStatus newEncryptionStatus = getEncryptionStatus(); - if(cachedEncryptionStatus != newEncryptionStatus) - Q_EMIT encryptionStatusChanged(newEncryptionStatus); + if(cachedEncryptionStatus != newEncryptionStatus) { + Q_EMIT encryptionStatusChanged(); + } } void WalletModel::pollBalanceChanged() diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 9e13de79b..b0045fa27 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -255,7 +255,7 @@ class WalletModel : public QObject const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); // Encryption status of wallet changed - void encryptionStatusChanged(int status); + void encryptionStatusChanged(); // Signal emitted when wallet needs to be unlocked // It is valid behaviour for listeners to keep the wallet locked after this signal; diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 64497a343..afc5fb263 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -101,13 +101,13 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui) connect(this, SIGNAL(message(QString,QString,unsigned int)), gui, SLOT(message(QString,QString,unsigned int))); // Pass through encryption status changed signals - connect(this, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); + connect(this, SIGNAL(encryptionStatusChanged()), gui, SLOT(updateWalletStatus())); // Pass through transaction notifications connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString))); // Connect HD enabled state signal - connect(this, SIGNAL(hdEnabledStatusChanged(int)), gui, SLOT(setHDStatus(int))); + connect(this, SIGNAL(hdEnabledStatusChanged()), gui, SLOT(updateWalletStatus())); } } @@ -137,11 +137,11 @@ void WalletView::setWalletModel(WalletModel *_walletModel) connect(_walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); // Handle changes in encryption status - connect(_walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int))); + connect(_walletModel, SIGNAL(encryptionStatusChanged()), this, SIGNAL(encryptionStatusChanged())); updateEncryptionStatus(); // update HD status - Q_EMIT hdEnabledStatusChanged(_walletModel->hdEnabled()); + Q_EMIT hdEnabledStatusChanged(); // Balloon pop-up for new transaction connect(_walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), @@ -234,7 +234,7 @@ void WalletView::showOutOfSyncWarning(bool fShow) void WalletView::updateEncryptionStatus() { - Q_EMIT encryptionStatusChanged(walletModel->getEncryptionStatus()); + Q_EMIT encryptionStatusChanged(); } void WalletView::encryptWallet(bool status) diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 30d68e4ef..739b3a0b6 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -44,6 +44,7 @@ class WalletView : public QStackedWidget The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. */ void setClientModel(ClientModel *clientModel); + WalletModel *getWalletModel() { return walletModel; } /** Set the wallet model. The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending functionality. @@ -119,9 +120,9 @@ public Q_SLOTS: /** Fired when a message should be reported to the user */ void message(const QString &title, const QString &message, unsigned int style); /** Encryption status of wallet changed */ - void encryptionStatusChanged(int status); + void encryptionStatusChanged(); /** HD-Enabled status of wallet changed (only possible during startup) */ - void hdEnabledStatusChanged(int hdEnabled); + void hdEnabledStatusChanged(); /** Notify that a new transaction appeared */ void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label); /** Notify that the out of sync warning icon has been pressed */ From d558f44c58b61671899d6ef897df271de3f4f20a Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 14 Dec 2017 03:13:34 +0000 Subject: [PATCH 015/900] Bugfix: RPC: Add missing UnregisterHTTPHandler for /wallet/ --- src/httprpc.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 5e9e41974..0abab55b5 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -252,6 +252,9 @@ void StopHTTPRPC() { LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n"); UnregisterHTTPHandler("/", true); +#ifdef ENABLE_WALLET + UnregisterHTTPHandler("/wallet/", false); +#endif if (httpRPCTimerInterface) { RPCUnsetTimerInterface(httpRPCTimerInterface.get()); httpRPCTimerInterface.reset(); From 4f933b3d23010d3b03998460290faed97cd6f236 Mon Sep 17 00:00:00 2001 From: fivepiece Date: Thu, 1 Feb 2018 02:40:47 +0200 Subject: [PATCH 016/900] p2wpkh, p2wsh and p2sh-nested scripts in decodescript plus tests --- src/rpc/rawtransaction.cpp | 32 +++++++++++++++ test/functional/rpc_decodescript.py | 60 +++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 803cd2864..b99906edf 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -563,6 +563,38 @@ UniValue decodescript(const JSONRPCRequest& request) // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH, // don't return the address for a P2SH of the P2SH. r.pushKV("p2sh", EncodeDestination(CScriptID(script))); + // P2SH and witness programs cannot be wrapped in P2WSH, if this script + // is a witness program, don't return addresses for a segwit programs. + if (type.get_str().find("witness") == std::string::npos) { + txnouttype which_type; + std::vector> solutions_data; + Solver(script, which_type, solutions_data); + // Uncompressed pubkeys cannot be used with segwit checksigs. + // If the script contains an uncompressed pubkey, skip encoding of a segwit program. + if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) { + for (const auto& solution : solutions_data) { + if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) { + return r; + } + } + } + UniValue sr(UniValue::VOBJ); + CScript segwitScr; + if (which_type == TX_PUBKEY) { + segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0].begin(), solutions_data[0].end()))); + } else if (which_type == TX_PUBKEYHASH) { + segwitScr = GetScriptForDestination(WitnessV0KeyHash(solutions_data[0])); + } else { + // Scripts that are not fit for P2WPKH are encoded as P2WSH. + // Newer segwit program versions should be considered when then become available. + uint256 scriptHash; + CSHA256().Write(script.data(), script.size()).Finalize(scriptHash.begin()); + segwitScr = GetScriptForDestination(WitnessV0ScriptHash(scriptHash)); + } + ScriptPubKeyToUniv(segwitScr, sr, true); + sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr))); + r.pushKV("segwit", sr); + } } return r; diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py index 1ffc57043..d58815176 100755 --- a/test/functional/rpc_decodescript.py +++ b/test/functional/rpc_decodescript.py @@ -50,8 +50,11 @@ def decodescript_script_sig(self): def decodescript_script_pub_key(self): public_key = '03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2' push_public_key = '21' + public_key - public_key_hash = '11695b6cd891484c2d49ec5aa738ec2b2f897777' + public_key_hash = '5dd1d3a048119c27b28293056724d9522f26d945' push_public_key_hash = '14' + public_key_hash + uncompressed_public_key = '04b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb25e01fc8fde47c96c98a4f3a8123e33a38a50cf9025cc8c4494a518f991792bb7' + push_uncompressed_public_key = '41' + uncompressed_public_key + p2wsh_p2pk_script_hash = 'd8590cf8ea0674cf3d49fd7ca249b85ef7485dea62c138468bddeb20cd6519f7' # below are test cases for all of the standard transaction types @@ -59,18 +62,26 @@ def decodescript_script_pub_key(self): # OP_CHECKSIG rpc_result = self.nodes[0].decodescript(push_public_key + 'ac') assert_equal(public_key + ' OP_CHECKSIG', rpc_result['asm']) + # P2PK is translated to P2WPKH + assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm']) # 2) P2PKH scriptPubKey # OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG rpc_result = self.nodes[0].decodescript('76a9' + push_public_key_hash + '88ac') assert_equal('OP_DUP OP_HASH160 ' + public_key_hash + ' OP_EQUALVERIFY OP_CHECKSIG', rpc_result['asm']) + # P2PKH is translated to P2WPKH + assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm']) # 3) multisig scriptPubKey # OP_CHECKMULTISIG # just imagine that the pub keys used below are different. # for our purposes here it does not matter that they are the same even though it is unrealistic. - rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_public_key + push_public_key + '53ae') + multisig_script = '52' + push_public_key + push_public_key + push_public_key + '53ae' + rpc_result = self.nodes[0].decodescript(multisig_script) assert_equal('2 ' + public_key + ' ' + public_key + ' ' + public_key + ' 3 OP_CHECKMULTISIG', rpc_result['asm']) + # multisig in P2WSH + multisig_script_hash = bytes_to_hex_str(sha256(hex_str_to_bytes(multisig_script))) + assert_equal('0 ' + multisig_script_hash, rpc_result['segwit']['asm']) # 4) P2SH scriptPubKey # OP_HASH160 OP_EQUAL. @@ -78,6 +89,8 @@ def decodescript_script_pub_key(self): # but this works the same for purposes of this test. rpc_result = self.nodes[0].decodescript('a9' + push_public_key_hash + '87') assert_equal('OP_HASH160 ' + public_key_hash + ' OP_EQUAL', rpc_result['asm']) + # P2SH does not work in segwit secripts. decodescript should not return a result for it. + assert 'segwit' not in rpc_result # 5) null data scriptPubKey # use a signature look-alike here to make sure that we do not decode random data as a signature. @@ -101,8 +114,49 @@ def decodescript_script_pub_key(self): # OP_CHECKSIG # # lock until block 500,000 - rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac') + cltv_script = '63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac' + rpc_result = self.nodes[0].decodescript(cltv_script) assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm']) + # CLTV script in P2WSH + cltv_script_hash = bytes_to_hex_str(sha256(hex_str_to_bytes(cltv_script))) + assert_equal('0 ' + cltv_script_hash, rpc_result['segwit']['asm']) + + # 7) P2PK scriptPubKey + # OP_CHECKSIG + rpc_result = self.nodes[0].decodescript(push_uncompressed_public_key + 'ac') + assert_equal(uncompressed_public_key + ' OP_CHECKSIG', rpc_result['asm']) + # uncompressed pubkeys are invalid for checksigs in segwit scripts. + # decodescript should not return a P2WPKH equivalent. + assert 'segwit' not in rpc_result + + # 8) multisig scriptPubKey with an uncompressed pubkey + # OP_CHECKMULTISIG + # just imagine that the pub keys used below are different. + # the purpose of this test is to check that a segwit script is not returned for bare multisig scripts + # with an uncompressed pubkey in them. + rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_uncompressed_public_key +'52ae') + assert_equal('2 ' + public_key + ' ' + uncompressed_public_key + ' 2 OP_CHECKMULTISIG', rpc_result['asm']) + # uncompressed pubkeys are invalid for checksigs in segwit scripts. + # decodescript should not return a P2WPKH equivalent. + assert 'segwit' not in rpc_result + + # 9) P2WPKH scriptpubkey + # 0 + rpc_result = self.nodes[0].decodescript('00' + push_public_key_hash) + assert_equal('0 ' + public_key_hash, rpc_result['asm']) + # segwit scripts do not work nested into each other. + # a nested segwit script should not be returned in the results. + assert 'segwit' not in rpc_result + + # 10) P2WSH scriptpubkey + # 0 + # even though this hash is of a P2PK script which is better used as bare P2WPKH, it should not matter + # for the purpose of this test. + rpc_result = self.nodes[0].decodescript('0020' + p2wsh_p2pk_script_hash) + assert_equal('0 ' + p2wsh_p2pk_script_hash, rpc_result['asm']) + # segwit scripts do not work nested into each other. + # a nested segwit script should not be returned in the results. + assert 'segwit' not in rpc_result def decoderawtransaction_asm_sighashtype(self): """Test decoding scripts via RPC command "decoderawtransaction". From de04fde534997f15235ded46912806d47c615c23 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Fri, 9 Mar 2018 06:09:57 +0100 Subject: [PATCH 017/900] bitcoin-cli: Provide a better error message when bitcoind is not running Before this patch: ``` $ bitcoin-cli -testnet echo 'hello world' error: Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (/root/.bitcoin/bitcoin.conf) ``` After this patch: ``` $ bitcoin-cli -testnet echo 'hello world' error: Could not connect to the server 127.0.0.1:18332 Make sure the bitcoind server is running and that you are connecting to the correct RPC port. ``` --- src/bitcoin-cli.cpp | 26 ++++++++++++++++-------- test/functional/interface_bitcoin_cli.py | 4 ++-- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 41f1e5786..8bdc21099 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -313,13 +313,11 @@ static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, co // Get credentials std::string strRPCUserColonPass; + bool failedToGetAuthCookie = false; if (gArgs.GetArg("-rpcpassword", "") == "") { // Try fall back to cookie-based authentication if no password is provided if (!GetAuthCookie(&strRPCUserColonPass)) { - throw std::runtime_error(strprintf( - _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"), - GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str())); - + failedToGetAuthCookie = true; } } else { strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", ""); @@ -358,11 +356,21 @@ static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, co event_base_dispatch(base.get()); - if (response.status == 0) - throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error)); - else if (response.status == HTTP_UNAUTHORIZED) - throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); - else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) + if (response.status == 0) { + std::string responseErrorMessage; + if (response.error != -1) { + responseErrorMessage = strprintf(" (error code %d - \"%s\")", response.error, http_errorstring(response.error)); + } + throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\nMake sure the bitcoind server is running and that you are connecting to the correct RPC port.", host, port, responseErrorMessage)); + } else if (response.status == HTTP_UNAUTHORIZED) { + if (failedToGetAuthCookie) { + throw std::runtime_error(strprintf( + _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"), + GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str())); + } else { + throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword"); + } + } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) throw std::runtime_error(strprintf("server returned HTTP error %d", response.status)); else if (response.body.empty()) throw std::runtime_error("no response from server"); diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index d8c80ab34..a349e2379 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -29,11 +29,11 @@ def run_test(self): self.log.info("Test -stdinrpcpass option") assert_equal(0, self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=password).getblockcount()) - assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input="foo").echo) + assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input="foo").echo) self.log.info("Test -stdin and -stdinrpcpass") assert_equal(["foo", "bar"], self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input=password + "\nfoo\nbar").echo()) - assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input="foo").echo) + assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input="foo").echo) self.log.info("Make sure that -getinfo with arguments fails") assert_raises_process_error(1, "-getinfo takes no arguments", self.nodes[0].cli('-getinfo').help) From 1f45e2164a7674f716b425a6658c41ca7c30265b Mon Sep 17 00:00:00 2001 From: practicalswift Date: Fri, 9 Mar 2018 15:03:40 +0100 Subject: [PATCH 018/900] scripted-diff: Convert 11 enums into scoped enums (C++11) -BEGIN VERIFY SCRIPT- sed -i 's/enum DBErrors/enum class DBErrors/g' src/wallet/walletdb.h git grep -l DB_ | xargs sed -i 's/DB_\(LOAD_OK\|CORRUPT\|NONCRITICAL_ERROR\|TOO_NEW\|LOAD_FAIL\|NEED_REWRITE\)/DBErrors::\1/g' sed -i 's/^ DBErrors::/ /g' src/wallet/walletdb.h sed -i 's/enum VerifyResult/enum class VerifyResult/g' src/wallet/db.h sed -i 's/\(VERIFY_OK\|RECOVER_OK\|RECOVER_FAIL\)/VerifyResult::\1/g' src/wallet/db.cpp sed -i 's/enum ThresholdState/enum class ThresholdState/g' src/versionbits.h git grep -l THRESHOLD_ | xargs sed -i 's/THRESHOLD_\(DEFINED\|STARTED\|LOCKED_IN\|ACTIVE\|FAILED\)/ThresholdState::\1/g' sed -i 's/^ ThresholdState::/ /g' src/versionbits.h sed -i 's/enum SigVersion/enum class SigVersion/g' src/script/interpreter.h git grep -l SIGVERSION_ | xargs sed -i 's/SIGVERSION_\(BASE\|WITNESS_V0\)/SigVersion::\1/g' sed -i 's/^ SigVersion::/ /g' src/script/interpreter.h sed -i 's/enum RetFormat {/enum class RetFormat {/g' src/rest.cpp sed -i 's/RF_\(UNDEF\|BINARY\|HEX\|JSON\)/RetFormat::\1/g' src/rest.cpp sed -i 's/^ RetFormat::/ /g' src/rest.cpp sed -i 's/enum HelpMessageMode {/enum class HelpMessageMode {/g' src/init.h git grep -l HMM_ | xargs sed -i 's/HMM_BITCOIN/HelpMessageMode::BITCOIN/g' sed -i 's/^ HelpMessageMode::/ /g' src/init.h sed -i 's/enum FeeEstimateHorizon/enum class FeeEstimateHorizon/g' src/policy/fees.h sed -i 's/enum RBFTransactionState/enum class RBFTransactionState/g' src/policy/rbf.h git grep -l RBF_ | xargs sed -i 's/RBF_TRANSACTIONSTATE_\(UNKNOWN\|REPLACEABLE_BIP125\|FINAL\)/RBFTransactionState::\1/g' sed -i 's/^ RBFTransactionState::/ /g' src/policy/rbf.h sed -i 's/enum BlockSource {/enum class BlockSource {/g' src/qt/clientmodel.h git grep -l BLOCK_SOURCE_ | xargs sed -i 's/BLOCK_SOURCE_\(NONE\|REINDEX\|DISK\|NETWORK\)/BlockSource::\1/g' sed -i 's/^ BlockSource::/ /g' src/qt/clientmodel.h sed -i 's/enum FlushStateMode {/enum class FlushStateMode {/g' src/validation.cpp sed -i 's/FLUSH_STATE_\(NONE\|IF_NEEDED\|PERIODIC\|ALWAYS\)/FlushStateMode::\1/g' src/validation.cpp sed -i 's/^ FlushStateMode::/ /g' src/validation.cpp sed -i 's/enum WitnessMode {/enum class WitnessMode {/g' src/test/script_tests.cpp sed -i 's/WITNESS_\(NONE\|PKH\|SH\)/WitnessMode::\1/g' src/test/script_tests.cpp sed -i 's/^ WitnessMode::/ /g' src/test/script_tests.cpp -END VERIFY SCRIPT- --- src/bench/verify_script.cpp | 2 +- src/bitcoind.cpp | 2 +- src/init.cpp | 2 +- src/init.h | 6 +- src/policy/fees.h | 2 +- src/policy/policy.cpp | 4 +- src/policy/rbf.cpp | 8 +- src/policy/rbf.h | 8 +- src/qt/bitcoingui.cpp | 8 +- src/qt/clientmodel.cpp | 8 +- src/qt/clientmodel.h | 10 +- src/qt/utilitydialog.cpp | 2 +- src/rest.cpp | 54 +++++------ src/rpc/blockchain.cpp | 14 +-- src/rpc/mining.cpp | 12 +-- src/script/interpreter.cpp | 18 ++-- src/script/interpreter.h | 6 +- src/script/ismine.cpp | 10 +- src/script/ismine.h | 10 +- src/script/sign.cpp | 16 ++-- src/test/data/tx_invalid.json | 4 +- src/test/multisig_tests.cpp | 2 +- src/test/script_tests.cpp | 134 +++++++++++++-------------- src/test/sighash_tests.cpp | 4 +- src/test/transaction_tests.cpp | 2 +- src/test/txvalidationcache_tests.cpp | 8 +- src/test/versionbits_tests.cpp | 20 ++-- src/validation.cpp | 58 ++++++------ src/versionbits.cpp | 28 +++--- src/versionbits.h | 12 +-- src/wallet/db.cpp | 10 +- src/wallet/db.h | 2 +- src/wallet/rpcdump.cpp | 2 +- src/wallet/rpcwallet.cpp | 4 +- src/wallet/test/accounting_tests.cpp | 2 +- src/wallet/wallet.cpp | 40 ++++---- src/wallet/walletdb.cpp | 42 ++++----- src/wallet/walletdb.h | 14 +-- 38 files changed, 295 insertions(+), 295 deletions(-) diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index 29dedeef0..705fa368a 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -75,7 +75,7 @@ static void VerifyScriptBench(benchmark::State& state) CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit); CScriptWitness& witness = txSpend.vin[0].scriptWitness; witness.stack.emplace_back(); - key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SIGVERSION_WITNESS_V0), witness.stack.back(), 0); + key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0), witness.stack.back(), 0); witness.stack.back().push_back(static_cast(SIGHASH_ALL)); witness.stack.push_back(ToByteVector(pubkey)); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index d3eb60725..db5e61068 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -79,7 +79,7 @@ bool AppInit(int argc, char* argv[]) strUsage += "\n" + _("Usage:") + "\n" + " bitcoind [options] " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n"; - strUsage += "\n" + HelpMessage(HMM_BITCOIND); + strUsage += "\n" + HelpMessage(HelpMessageMode::BITCOIND); } fprintf(stdout, "%s", strUsage.c_str()); diff --git a/src/init.cpp b/src/init.cpp index 659f97fec..0bf0a0b4b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -338,7 +338,7 @@ std::string HelpMessage(HelpMessageMode mode) if (showDebug) strUsage += HelpMessageOpt("-blocksonly", strprintf(_("Whether to operate in a blocks only mode (default: %u)"), DEFAULT_BLOCKSONLY)); strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)"), BITCOIN_CONF_FILENAME)); - if (mode == HMM_BITCOIND) + if (mode == HelpMessageMode::BITCOIND) { #if HAVE_DECL_DAEMON strUsage += HelpMessageOpt("-daemon", _("Run in the background as a daemon and accept commands")); diff --git a/src/init.h b/src/init.h index 33f97a55a..6f75a43e6 100644 --- a/src/init.h +++ b/src/init.h @@ -57,9 +57,9 @@ bool AppInitLockDataDirectory(); bool AppInitMain(); /** The help message mode determines what help message to show */ -enum HelpMessageMode { - HMM_BITCOIND, - HMM_BITCOIN_QT +enum class HelpMessageMode { + BITCOIND, + BITCOIN_QT }; /** Help for options shared between UI and daemon (for -help) */ diff --git a/src/policy/fees.h b/src/policy/fees.h index 5f69e989c..7f80fc92c 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -68,7 +68,7 @@ class TxConfirmStats; /* Identifier for each of the 3 different TxConfirmStats which will track * history over different time horizons. */ -enum FeeEstimateHorizon { +enum class FeeEstimateHorizon { SHORT_HALFLIFE = 0, MED_HALFLIFE = 1, LONG_HALFLIFE = 2 diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index bff58932b..f8b8b1e4a 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -179,7 +179,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { std::vector > stack; // convert the scriptSig into a stack, so we can inspect the redeemScript - if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE)) + if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE)) return false; if (stack.empty()) return false; @@ -215,7 +215,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) // If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig // into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway. // If the check fails at this stage, we know that this txid must be a bad one. - if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE)) + if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE)) return false; if (stack.empty()) return false; diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp index c5a174160..81b2a7fad 100644 --- a/src/policy/rbf.cpp +++ b/src/policy/rbf.cpp @@ -22,13 +22,13 @@ RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool) // First check the transaction itself. if (SignalsOptInRBF(tx)) { - return RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125; + return RBFTransactionState::REPLACEABLE_BIP125; } // If this transaction is not in our mempool, then we can't be sure // we will know about all its inputs. if (!pool.exists(tx.GetHash())) { - return RBF_TRANSACTIONSTATE_UNKNOWN; + return RBFTransactionState::UNKNOWN; } // If all the inputs have nSequence >= maxint-1, it still might be @@ -40,8 +40,8 @@ RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool) for (CTxMemPool::txiter it : setAncestors) { if (SignalsOptInRBF(it->GetTx())) { - return RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125; + return RBFTransactionState::REPLACEABLE_BIP125; } } - return RBF_TRANSACTIONSTATE_FINAL; + return RBFTransactionState::FINAL; } diff --git a/src/policy/rbf.h b/src/policy/rbf.h index 72f51b0f0..b10532add 100644 --- a/src/policy/rbf.h +++ b/src/policy/rbf.h @@ -9,10 +9,10 @@ static const uint32_t MAX_BIP125_RBF_SEQUENCE = 0xfffffffd; -enum RBFTransactionState { - RBF_TRANSACTIONSTATE_UNKNOWN, - RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125, - RBF_TRANSACTIONSTATE_FINAL +enum class RBFTransactionState { + UNKNOWN, + REPLACEABLE_BIP125, + FINAL }; // Check whether the sequence numbers on this transaction are signaling diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 427eb95a8..2f6a377a6 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -780,7 +780,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer // Acquire current block source enum BlockSource blockSource = clientModel->getBlockSource(); switch (blockSource) { - case BLOCK_SOURCE_NETWORK: + case BlockSource::NETWORK: if (header) { updateHeadersSyncProgressLabel(); return; @@ -788,17 +788,17 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer progressBarLabel->setText(tr("Synchronizing with network...")); updateHeadersSyncProgressLabel(); break; - case BLOCK_SOURCE_DISK: + case BlockSource::DISK: if (header) { progressBarLabel->setText(tr("Indexing blocks on disk...")); } else { progressBarLabel->setText(tr("Processing blocks on disk...")); } break; - case BLOCK_SOURCE_REINDEX: + case BlockSource::REINDEX: progressBarLabel->setText(tr("Reindexing blocks on disk...")); break; - case BLOCK_SOURCE_NONE: + case BlockSource::NONE: if (header) { return; } diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index eaf2896bc..40661d9ec 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -177,13 +177,13 @@ bool ClientModel::inInitialBlockDownload() const enum BlockSource ClientModel::getBlockSource() const { if (fReindex) - return BLOCK_SOURCE_REINDEX; + return BlockSource::REINDEX; else if (fImporting) - return BLOCK_SOURCE_DISK; + return BlockSource::DISK; else if (getNumConnections() > 0) - return BLOCK_SOURCE_NETWORK; + return BlockSource::NETWORK; - return BLOCK_SOURCE_NONE; + return BlockSource::NONE; } void ClientModel::setNetworkActive(bool active) diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 99ec2365a..1118bc31b 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -20,11 +20,11 @@ QT_BEGIN_NAMESPACE class QTimer; QT_END_NAMESPACE -enum BlockSource { - BLOCK_SOURCE_NONE, - BLOCK_SOURCE_REINDEX, - BLOCK_SOURCE_DISK, - BLOCK_SOURCE_NETWORK +enum class BlockSource { + NONE, + REINDEX, + DISK, + NETWORK }; enum NumConnections { diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 65e7775f2..c19e6aae7 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -77,7 +77,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : cursor.insertText(header); cursor.insertBlock(); - std::string strUsage = HelpMessage(HMM_BITCOIN_QT); + std::string strUsage = HelpMessage(HelpMessageMode::BITCOIN_QT); const bool showDebug = gArgs.GetBoolArg("-help-debug", false); strUsage += HelpMessageGroup(tr("UI Options:").toStdString()); if (showDebug) { diff --git a/src/rest.cpp b/src/rest.cpp index 8cba59dbb..fdd097c8a 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -24,21 +24,21 @@ static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once -enum RetFormat { - RF_UNDEF, - RF_BINARY, - RF_HEX, - RF_JSON, +enum class RetFormat { + UNDEF, + BINARY, + HEX, + JSON, }; static const struct { enum RetFormat rf; const char* name; } rf_names[] = { - {RF_UNDEF, ""}, - {RF_BINARY, "bin"}, - {RF_HEX, "hex"}, - {RF_JSON, "json"}, + {RetFormat::UNDEF, ""}, + {RetFormat::BINARY, "bin"}, + {RetFormat::HEX, "hex"}, + {RetFormat::JSON, "json"}, }; struct CCoin { @@ -163,20 +163,20 @@ static bool rest_headers(HTTPRequest* req, } switch (rf) { - case RF_BINARY: { + case RetFormat::BINARY: { std::string binaryHeader = ssHeader.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryHeader); return true; } - case RF_HEX: { + case RetFormat::HEX: { std::string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); return true; } - case RF_JSON: { + case RetFormat::JSON: { UniValue jsonHeaders(UniValue::VARR); { LOCK(cs_main); @@ -227,21 +227,21 @@ static bool rest_block(HTTPRequest* req, ssBlock << block; switch (rf) { - case RF_BINARY: { + case RetFormat::BINARY: { std::string binaryBlock = ssBlock.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryBlock); return true; } - case RF_HEX: { + case RetFormat::HEX: { std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); return true; } - case RF_JSON: { + case RetFormat::JSON: { UniValue objBlock; { LOCK(cs_main); @@ -280,7 +280,7 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart) const RetFormat rf = ParseDataFormat(param, strURIPart); switch (rf) { - case RF_JSON: { + case RetFormat::JSON: { JSONRPCRequest jsonRequest; jsonRequest.params = UniValue(UniValue::VARR); UniValue chainInfoObject = getblockchaininfo(jsonRequest); @@ -303,7 +303,7 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart) const RetFormat rf = ParseDataFormat(param, strURIPart); switch (rf) { - case RF_JSON: { + case RetFormat::JSON: { UniValue mempoolInfoObject = mempoolInfoToJSON(); std::string strJSON = mempoolInfoObject.write() + "\n"; @@ -325,7 +325,7 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar const RetFormat rf = ParseDataFormat(param, strURIPart); switch (rf) { - case RF_JSON: { + case RetFormat::JSON: { UniValue mempoolObject = mempoolToJSON(true); std::string strJSON = mempoolObject.write() + "\n"; @@ -359,21 +359,21 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) ssTx << tx; switch (rf) { - case RF_BINARY: { + case RetFormat::BINARY: { std::string binaryTx = ssTx.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryTx); return true; } - case RF_HEX: { + case RetFormat::HEX: { std::string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); return true; } - case RF_JSON: { + case RetFormat::JSON: { UniValue objTx(UniValue::VOBJ); TxToUniv(*tx, hashBlock, objTx); std::string strJSON = objTx.write() + "\n"; @@ -440,13 +440,13 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) } switch (rf) { - case RF_HEX: { + case RetFormat::HEX: { // convert hex to bin, continue then with bin part std::vector strRequestV = ParseHex(strRequestMutable); strRequestMutable.assign(strRequestV.begin(), strRequestV.end()); } - case RF_BINARY: { + case RetFormat::BINARY: { try { //deserialize only if user sent a request if (strRequestMutable.size() > 0) @@ -466,7 +466,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) break; } - case RF_JSON: { + case RetFormat::JSON: { if (!fInputParsed) return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request"); break; @@ -513,7 +513,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) } switch (rf) { - case RF_BINARY: { + case RetFormat::BINARY: { // serialize data // use exact same output as mentioned in Bip64 CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); @@ -525,7 +525,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) return true; } - case RF_HEX: { + case RetFormat::HEX: { CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n"; @@ -535,7 +535,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) return true; } - case RF_JSON: { + case RetFormat::JSON: { UniValue objGetUTXOResponse(UniValue::VOBJ); // pack in some essentials diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f2a1fd048..21a7e05d3 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1121,20 +1121,20 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse UniValue rv(UniValue::VOBJ); const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id); switch (thresholdState) { - case THRESHOLD_DEFINED: rv.pushKV("status", "defined"); break; - case THRESHOLD_STARTED: rv.pushKV("status", "started"); break; - case THRESHOLD_LOCKED_IN: rv.pushKV("status", "locked_in"); break; - case THRESHOLD_ACTIVE: rv.pushKV("status", "active"); break; - case THRESHOLD_FAILED: rv.pushKV("status", "failed"); break; + case ThresholdState::DEFINED: rv.pushKV("status", "defined"); break; + case ThresholdState::STARTED: rv.pushKV("status", "started"); break; + case ThresholdState::LOCKED_IN: rv.pushKV("status", "locked_in"); break; + case ThresholdState::ACTIVE: rv.pushKV("status", "active"); break; + case ThresholdState::FAILED: rv.pushKV("status", "failed"); break; } - if (THRESHOLD_STARTED == thresholdState) + if (ThresholdState::STARTED == thresholdState) { rv.pushKV("bit", consensusParams.vDeployments[id].bit); } rv.pushKV("startTime", consensusParams.vDeployments[id].nStartTime); rv.pushKV("timeout", consensusParams.vDeployments[id].nTimeout); rv.pushKV("since", VersionBitsTipStateSinceHeight(consensusParams, id)); - if (THRESHOLD_STARTED == thresholdState) + if (ThresholdState::STARTED == thresholdState) { UniValue statsUV(UniValue::VOBJ); BIP9Stats statsStruct = VersionBitsTipStatistics(consensusParams, id); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 3073a49d0..dba21d6e4 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -533,7 +533,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) pblock->nNonce = 0; // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration - const bool fPreSegWit = (THRESHOLD_ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); + const bool fPreSegWit = (ThresholdState::ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache)); UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); @@ -594,15 +594,15 @@ UniValue getblocktemplate(const JSONRPCRequest& request) Consensus::DeploymentPos pos = Consensus::DeploymentPos(j); ThresholdState state = VersionBitsState(pindexPrev, consensusParams, pos, versionbitscache); switch (state) { - case THRESHOLD_DEFINED: - case THRESHOLD_FAILED: + case ThresholdState::DEFINED: + case ThresholdState::FAILED: // Not exposed to GBT at all break; - case THRESHOLD_LOCKED_IN: + case ThresholdState::LOCKED_IN: // Ensure bit is set in block version pblock->nVersion |= VersionBitsMask(consensusParams, pos); // FALL THROUGH to get vbavailable set... - case THRESHOLD_STARTED: + case ThresholdState::STARTED: { const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; vbavailable.pushKV(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit); @@ -614,7 +614,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) } break; } - case THRESHOLD_ACTIVE: + case ThresholdState::ACTIVE: { // Add to rules only const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 927b0267c..4ab935903 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -219,7 +219,7 @@ bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, co return set_error(serror, SCRIPT_ERR_PUBKEYTYPE); } // Only compressed keys are accepted in segwit - if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SIGVERSION_WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) { + if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SigVersion::WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) { return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE); } return true; @@ -443,7 +443,7 @@ bool EvalScript(std::vector >& stack, const CScript& if (stack.size() < 1) return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); valtype& vch = stacktop(-1); - if (sigversion == SIGVERSION_WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) { + if (sigversion == SigVersion::WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) { if (vch.size() > 1) return set_error(serror, SCRIPT_ERR_MINIMALIF); if (vch.size() == 1 && vch[0] != 1) @@ -890,7 +890,7 @@ bool EvalScript(std::vector >& stack, const CScript& CScript scriptCode(pbegincodehash, pend); // Drop the signature in pre-segwit scripts but not segwit scripts - if (sigversion == SIGVERSION_BASE) { + if (sigversion == SigVersion::BASE) { scriptCode.FindAndDelete(CScript(vchSig)); } @@ -954,7 +954,7 @@ bool EvalScript(std::vector >& stack, const CScript& for (int k = 0; k < nSigsCount; k++) { valtype& vchSig = stacktop(-isig-k); - if (sigversion == SIGVERSION_BASE) { + if (sigversion == SigVersion::BASE) { scriptCode.FindAndDelete(CScript(vchSig)); } } @@ -1182,7 +1182,7 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig { assert(nIn < txTo.vin.size()); - if (sigversion == SIGVERSION_WITNESS_V0) { + if (sigversion == SigVersion::WITNESS_V0) { uint256 hashPrevouts; uint256 hashSequence; uint256 hashOutputs; @@ -1396,7 +1396,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } - if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_WITNESS_V0, serror)) { + if (!EvalScript(stack, scriptPubKey, flags, checker, SigVersion::WITNESS_V0, serror)) { return false; } @@ -1423,12 +1423,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C } std::vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, scriptSig, flags, checker, SigVersion::BASE, serror)) // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, scriptPubKey, flags, checker, SigVersion::BASE, serror)) // serror is set return false; if (stack.empty()) @@ -1474,7 +1474,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); - if (!EvalScript(stack, pubKey2, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, pubKey2, flags, checker, SigVersion::BASE, serror)) // serror is set return false; if (stack.empty()) diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 4dad6b44c..bb7750d78 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -123,10 +123,10 @@ struct PrecomputedTransactionData explicit PrecomputedTransactionData(const CTransaction& tx); }; -enum SigVersion +enum class SigVersion { - SIGVERSION_BASE = 0, - SIGVERSION_WITNESS_V0 = 1, + BASE = 0, + WITNESS_V0 = 1, }; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 35d794b98..05bc5e9bd 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -61,7 +61,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - if (sigversion != SIGVERSION_BASE && vSolutions[0].size() != 33) { + if (sigversion != SigVersion::BASE && vSolutions[0].size() != 33) { isInvalid = true; return ISMINE_NO; } @@ -76,14 +76,14 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& // This also applies to the P2WSH case. break; } - isminetype ret = ::IsMine(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, SIGVERSION_WITNESS_V0); + isminetype ret = ::IsMine(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, SigVersion::WITNESS_V0); if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) return ret; break; } case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - if (sigversion != SIGVERSION_BASE) { + if (sigversion != SigVersion::BASE) { CPubKey pubkey; if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) { isInvalid = true; @@ -114,7 +114,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& CScriptID scriptID = CScriptID(hash); CScript subscript; if (keystore.GetCScript(scriptID, subscript)) { - isminetype ret = IsMine(keystore, subscript, isInvalid, SIGVERSION_WITNESS_V0); + isminetype ret = IsMine(keystore, subscript, isInvalid, SigVersion::WITNESS_V0); if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid)) return ret; } @@ -129,7 +129,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. std::vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); - if (sigversion != SIGVERSION_BASE) { + if (sigversion != SigVersion::BASE) { for (size_t i = 0; i < keys.size(); i++) { if (keys[i].size() != 33) { isInvalid = true; diff --git a/src/script/ismine.h b/src/script/ismine.h index c1338c3a8..f93a66e35 100644 --- a/src/script/ismine.h +++ b/src/script/ismine.h @@ -31,11 +31,11 @@ typedef uint8_t isminefilter; /* isInvalid becomes true when the script is found invalid by consensus or policy. This will terminate the recursion * and return ISMINE_NO immediately, as an invalid script should never be considered as "mine". This is needed as * different SIGVERSION may have different network rules. Currently the only use of isInvalid is indicate uncompressed - * keys in SIGVERSION_WITNESS_V0 script, but could also be used in similar cases in the future + * keys in SigVersion::WITNESS_V0 script, but could also be used in similar cases in the future */ -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion = SIGVERSION_BASE); -isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion = SIGVERSION_BASE); -isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, bool& isInvalid, SigVersion = SIGVERSION_BASE); -isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion = SIGVERSION_BASE); +isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion = SigVersion::BASE); +isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion = SigVersion::BASE); +isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, bool& isInvalid, SigVersion = SigVersion::BASE); +isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion = SigVersion::BASE); #endif // BITCOIN_SCRIPT_ISMINE_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index aaba5e592..5c73ba0d2 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -24,7 +24,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, return false; // Signing with uncompressed keys is disabled in witness scripts - if (sigversion == SIGVERSION_WITNESS_V0 && !key.IsCompressed()) + if (sigversion == SigVersion::WITNESS_V0 && !key.IsCompressed()) return false; uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); @@ -142,7 +142,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu { std::vector result; txnouttype whichType; - bool solved = SignStep(creator, fromPubKey, result, whichType, SIGVERSION_BASE); + bool solved = SignStep(creator, fromPubKey, result, whichType, SigVersion::BASE); bool P2SH = false; CScript subscript; sigdata.scriptWitness.stack.clear(); @@ -153,7 +153,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu // the final scriptSig is the signatures from that // and then the serialized subscript: subscript = CScript(result[0].begin(), result[0].end()); - solved = solved && SignStep(creator, subscript, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH; + solved = solved && SignStep(creator, subscript, result, whichType, SigVersion::BASE) && whichType != TX_SCRIPTHASH; P2SH = true; } @@ -162,7 +162,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu CScript witnessscript; witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG; txnouttype subType; - solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0); + solved = solved && SignStep(creator, witnessscript, result, subType, SigVersion::WITNESS_V0); sigdata.scriptWitness.stack = result; result.clear(); } @@ -170,7 +170,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu { CScript witnessscript(result[0].begin(), result[0].end()); txnouttype subType; - solved = solved && SignStep(creator, witnessscript, result, subType, SIGVERSION_WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; + solved = solved && SignStep(creator, witnessscript, result, subType, SigVersion::WITNESS_V0) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; result.push_back(std::vector(witnessscript.begin(), witnessscript.end())); sigdata.scriptWitness.stack = result; result.clear(); @@ -289,7 +289,7 @@ struct Stacks Stacks() {} explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_), witness() {} explicit Stacks(const SignatureData& data) : witness(data.scriptWitness.stack) { - EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); + EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SigVersion::BASE); } SignatureData Output() const { @@ -365,7 +365,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature sigs2.witness.pop_back(); sigs2.script = sigs2.witness; sigs2.witness.clear(); - Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SIGVERSION_WITNESS_V0); + Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, SigVersion::WITNESS_V0); result.witness = result.script; result.script.clear(); result.witness.push_back(valtype(pubKey2.begin(), pubKey2.end())); @@ -383,7 +383,7 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature std::vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); - return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output(); + return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SigVersion::BASE).Output(); } namespace { diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index f8a1347c3..abb46fe53 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -321,7 +321,7 @@ ["where the pubkey is obtained through key recovery with sig and the wrong sighash."], ["This is to show that FindAndDelete is applied only to non-segwit scripts"], ["To show that the tests are 'correctly wrong', they should pass by modifying OP_CHECKSIG under interpreter.cpp"], -["by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE)"], +["by replacing (sigversion == SigVersion::BASE) with (sigversion != SigVersion::BASE)"], ["Non-segwit: wrong sighash (without FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"], [[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]], "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012103b12a1ec8428fc74166926318c15e17408fea82dbb157575e16a8c365f546248f4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"], @@ -332,7 +332,7 @@ ["Script is 2 CHECKMULTISIGVERIFY DROP"], ["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"], ["Signature is 0 2 "], -["Should pass by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE) under OP_CHECKMULTISIG"], +["Should pass by replacing (sigversion == SigVersion::BASE) with (sigversion != SigVersion::BASE) under OP_CHECKMULTISIG"], ["Non-segwit: wrong sighash (without FindAndDelete) = 4bc6a53e8e16ef508c19e38bba08831daba85228b0211f323d4cb0999cf2a5e8"], [[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]], "01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596015221023fd5dd42b44769c5653cbc5947ff30ab8871f240ad0c0e7432aefe84b5b4ff3421039d52178dbde360b83f19cf348deb04fa8360e1bf5634577be8e50fafc2b0e4ef4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"], diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 72d9d3d75..b593f9633 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -21,7 +21,7 @@ BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction, int whichIn) { - uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE); CScript result; result << OP_0; // CHECKMULTISIG bug workaround diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index c7a497f3a..46a2d1374 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -267,10 +267,10 @@ struct KeyData } }; -enum WitnessMode { - WITNESS_NONE, - WITNESS_PKH, - WITNESS_SH +enum class WitnessMode { + NONE, + PKH, + SH }; class TestBuilder @@ -308,15 +308,15 @@ class TestBuilder } public: - TestBuilder(const CScript& script_, const std::string& comment_, int flags_, bool P2SH = false, WitnessMode wm = WITNESS_NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK), nValue(nValue_) + TestBuilder(const CScript& script_, const std::string& comment_, int flags_, bool P2SH = false, WitnessMode wm = WitnessMode::NONE, int witnessversion = 0, CAmount nValue_ = 0) : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK), nValue(nValue_) { CScript scriptPubKey = script; - if (wm == WITNESS_PKH) { + if (wm == WitnessMode::PKH) { uint160 hash; CHash160().Write(&script[1], script.size() - 1).Finalize(hash.begin()); script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(hash) << OP_EQUALVERIFY << OP_CHECKSIG; scriptPubKey = CScript() << witnessversion << ToByteVector(hash); - } else if (wm == WITNESS_SH) { + } else if (wm == WitnessMode::SH) { witscript = scriptPubKey; uint256 hash; CSHA256().Write(&witscript[0], witscript.size()).Finalize(hash.begin()); @@ -361,7 +361,7 @@ class TestBuilder return *this; } - TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SIGVERSION_BASE, CAmount amount = 0) + TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SigVersion::BASE, CAmount amount = 0) { uint256 hash = SignatureHash(script, spendTx, 0, nHashType, amount, sigversion); std::vector vchSig, r, s; @@ -379,7 +379,7 @@ class TestBuilder return *this; } - TestBuilder& PushWitSig(const CKey& key, CAmount amount = -1, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SIGVERSION_WITNESS_V0) + TestBuilder& PushWitSig(const CKey& key, CAmount amount = -1, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SigVersion::WITNESS_V0) { if (amount == -1) amount = nValue; @@ -747,57 +747,57 @@ BOOST_AUTO_TEST_CASE(script_build) ).PushSig(keys.key0).PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "Basic P2WSH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH, + "Basic P2WSH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH, 0, 1).PushWitSig(keys.key0).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), - "Basic P2WPKH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_PKH, + "Basic P2WPKH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::PKH, 0, 1).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "Basic P2SH(P2WSH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH, + "Basic P2SH(P2WSH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::SH, 0, 1).PushWitSig(keys.key0).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), - "Basic P2SH(P2WPKH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_PKH, + "Basic P2SH(P2WPKH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::PKH, 0, 1).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, - "Basic P2WSH with the wrong key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH + "Basic P2WSH with the wrong key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH ).PushWitSig(keys.key0).PushWitRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1), - "Basic P2WPKH with the wrong key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_PKH + "Basic P2WPKH with the wrong key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::PKH ).PushWitSig(keys.key0).Push(keys.pubkey1).AsWit().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, - "Basic P2SH(P2WSH) with the wrong key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH + "Basic P2SH(P2WSH) with the wrong key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::SH ).PushWitSig(keys.key0).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1), - "Basic P2SH(P2WPKH) with the wrong key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_PKH + "Basic P2SH(P2WPKH) with the wrong key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::PKH ).PushWitSig(keys.key0).Push(keys.pubkey1).AsWit().PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, - "Basic P2WSH with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, false, WITNESS_SH + "Basic P2WSH with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, false, WitnessMode::SH ).PushWitSig(keys.key0).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1), - "Basic P2WPKH with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, false, WITNESS_PKH + "Basic P2WPKH with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, false, WitnessMode::PKH ).PushWitSig(keys.key0).Push(keys.pubkey1).AsWit()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, - "Basic P2SH(P2WSH) with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, true, WITNESS_SH + "Basic P2SH(P2WSH) with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, true, WitnessMode::SH ).PushWitSig(keys.key0).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1), - "Basic P2SH(P2WPKH) with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, true, WITNESS_PKH + "Basic P2SH(P2WPKH) with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, true, WitnessMode::PKH ).PushWitSig(keys.key0).Push(keys.pubkey1).AsWit().PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "Basic P2WSH with wrong value", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH, + "Basic P2WSH with wrong value", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH, 0, 0).PushWitSig(keys.key0, 1).PushWitRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), - "Basic P2WPKH with wrong value", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_PKH, + "Basic P2WPKH with wrong value", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::PKH, 0, 0).PushWitSig(keys.key0, 1).Push(keys.pubkey0).AsWit().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "Basic P2SH(P2WSH) with wrong value", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH, + "Basic P2SH(P2WSH) with wrong value", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::SH, 0, 0).PushWitSig(keys.key0, 1).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), - "Basic P2SH(P2WPKH) with wrong value", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_PKH, + "Basic P2SH(P2WPKH) with wrong value", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::PKH, 0, 0).PushWitSig(keys.key0, 1).Push(keys.pubkey0).AsWit().PushRedeem().ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), "P2WPKH with future witness version", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, false, WITNESS_PKH, 1 + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, false, WitnessMode::PKH, 1 ).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().ScriptError(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)); { CScript witscript = CScript() << ToByteVector(keys.pubkey0); @@ -810,22 +810,22 @@ BOOST_AUTO_TEST_CASE(script_build) ).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().ScriptError(SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH)); } tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "P2WSH with empty witness", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH + "P2WSH with empty witness", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH ).ScriptError(SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY)); { CScript witscript = CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG; tests.push_back(TestBuilder(witscript, - "P2WSH with witness program mismatch", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH + "P2WSH with witness program mismatch", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH ).PushWitSig(keys.key0).Push(witscript).DamagePush(0).AsWit().ScriptError(SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH)); } tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), - "P2WPKH with witness program mismatch", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_PKH + "P2WPKH with witness program mismatch", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::PKH ).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().Push("0").AsWit().ScriptError(SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), - "P2WPKH with non-empty scriptSig", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_PKH + "P2WPKH with non-empty scriptSig", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::PKH ).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().Num(11).ScriptError(SCRIPT_ERR_WITNESS_MALLEATED)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1), - "P2SH(P2WPKH) with superfluous push in scriptSig", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_PKH + "P2SH(P2WPKH) with superfluous push in scriptSig", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::PKH ).PushWitSig(keys.key0).Push(keys.pubkey1).AsWit().Num(11).PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_MALLEATED_P2SH)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with witness", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH @@ -833,95 +833,95 @@ BOOST_AUTO_TEST_CASE(script_build) // Compressed keys should pass SCRIPT_VERIFY_WITNESS_PUBKEYTYPE tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, - "Basic P2WSH with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH, + "Basic P2WSH with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::SH, 0, 1).PushWitSig(keys.key0C).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C), - "Basic P2WPKH with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_PKH, + "Basic P2WPKH with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::PKH, 0, 1).PushWitSig(keys.key0C).Push(keys.pubkey0C).AsWit()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, - "Basic P2SH(P2WSH) with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH, + "Basic P2SH(P2WSH) with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::SH, 0, 1).PushWitSig(keys.key0C).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C), - "Basic P2SH(P2WPKH) with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_PKH, + "Basic P2SH(P2WPKH) with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::PKH, 0, 1).PushWitSig(keys.key0C).Push(keys.pubkey0C).AsWit().PushRedeem()); // Testing uncompressed key in witness with SCRIPT_VERIFY_WITNESS_PUBKEYTYPE tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "Basic P2WSH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH, + "Basic P2WSH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::SH, 0, 1).PushWitSig(keys.key0).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), - "Basic P2WPKH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_PKH, + "Basic P2WPKH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::PKH, 0, 1).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, - "Basic P2SH(P2WSH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH, + "Basic P2SH(P2WSH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::SH, 0, 1).PushWitSig(keys.key0).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0), - "Basic P2SH(P2WPKH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_PKH, + "Basic P2SH(P2WPKH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::PKH, 0, 1).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); // P2WSH 1-of-2 multisig with compressed keys tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem()); // P2WSH 1-of-2 multisig with first key uncompressed tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); // P2WSH 1-of-2 multisig with second key uncompressed tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG second key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG second key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH, + "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG, - "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH, + "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WitnessMode::SH, 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE)); std::set tests_set; @@ -1009,21 +1009,21 @@ BOOST_AUTO_TEST_CASE(script_PushData) ScriptError err; std::vector > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); + BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } @@ -1031,7 +1031,7 @@ BOOST_AUTO_TEST_CASE(script_PushData) CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) { - uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SigVersion::BASE); CScript result; // @@ -1227,15 +1227,15 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) // A couple of partially-signed versions: std::vector sig1; - uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); std::vector sig2; - uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE); + uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SigVersion::BASE); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); std::vector sig3; - uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE); + uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SigVersion::BASE); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 32cd3a50b..a2bd8998b 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(sighash_test) uint256 sh, sho; sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); - sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SIGVERSION_BASE); + sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SigVersion::BASE); #if defined(PRINT_SIGHASH_JSON) CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << txTo; @@ -204,7 +204,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data) continue; } - sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SIGVERSION_BASE); + sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SigVersion::BASE); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); } } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index edfb35d15..b222392ee 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -407,7 +407,7 @@ static CScript PushAll(const std::vector& values) void ReplaceRedeemScript(CScript& script, const CScript& redeemScript) { std::vector stack; - EvalScript(stack, script, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); + EvalScript(stack, script, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SigVersion::BASE); assert(stack.size() > 0); stack.back() = std::vector(redeemScript.begin(), redeemScript.end()); script = PushAll(stack); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 9ec9d6cba..8a6ca9e51 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -56,7 +56,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) // Sign: std::vector vchSig; - uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); spends[i].vin[0].scriptSig << vchSig; @@ -182,7 +182,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign, with a non-DER signature { std::vector vchSig; - uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char) 0); // padding byte makes this non-DER vchSig.push_back((unsigned char)SIGHASH_ALL); @@ -256,7 +256,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign std::vector vchSig; - uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; @@ -284,7 +284,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign std::vector vchSig; - uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index 5d6f78140..92ef58e51 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -101,8 +101,8 @@ class VersionBitsTester VersionBitsTester& TestDefined() { for (int i = 0; i < CHECKERS; i++) { if (InsecureRandBits(i) == 0) { - BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num)); - BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::DEFINED, strprintf("Test %i for DEFINED", num)); + BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); } } num++; @@ -112,8 +112,8 @@ class VersionBitsTester VersionBitsTester& TestStarted() { for (int i = 0; i < CHECKERS; i++) { if (InsecureRandBits(i) == 0) { - BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num)); - BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::STARTED, strprintf("Test %i for STARTED", num)); + BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); } } num++; @@ -123,8 +123,8 @@ class VersionBitsTester VersionBitsTester& TestLockedIn() { for (int i = 0; i < CHECKERS; i++) { if (InsecureRandBits(i) == 0) { - BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num)); - BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::LOCKED_IN, strprintf("Test %i for LOCKED_IN", num)); + BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); } } num++; @@ -134,8 +134,8 @@ class VersionBitsTester VersionBitsTester& TestActive() { for (int i = 0; i < CHECKERS; i++) { if (InsecureRandBits(i) == 0) { - BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num)); - BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE", num)); + BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); } } num++; @@ -145,8 +145,8 @@ class VersionBitsTester VersionBitsTester& TestFailed() { for (int i = 0; i < CHECKERS; i++) { if (InsecureRandBits(i) == 0) { - BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num)); - BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); + BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::FAILED, strprintf("Test %i for FAILED", num)); + BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num)); } } num++; diff --git a/src/validation.cpp b/src/validation.cpp index 51e40c17b..28a14ed3c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -280,11 +280,11 @@ std::unique_ptr pcoinsdbview; std::unique_ptr pcoinsTip; std::unique_ptr pblocktree; -enum FlushStateMode { - FLUSH_STATE_NONE, - FLUSH_STATE_IF_NEEDED, - FLUSH_STATE_PERIODIC, - FLUSH_STATE_ALWAYS +enum class FlushStateMode { + NONE, + IF_NEEDED, + PERIODIC, + ALWAYS }; // See definition for documentation @@ -983,7 +983,7 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo } // After we've (potentially) uncached entries, ensure our coins cache is still within its size limits CValidationState stateDummy; - FlushStateToDisk(chainparams, stateDummy, FLUSH_STATE_PERIODIC); + FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC); return res; } @@ -1685,7 +1685,7 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { ThresholdState state = VersionBitsState(pindexPrev, params, static_cast(i), versionbitscache); - if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) { + if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) { nVersion |= VersionBitsMask(params, static_cast(i)); } } @@ -1741,7 +1741,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens } // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. - if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { + if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) { flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; } @@ -1927,7 +1927,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. int nLockTimeFlags = 0; - if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { + if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) { nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; } @@ -2097,15 +2097,15 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState & int64_t cacheSize = pcoinsTip->DynamicMemoryUsage(); int64_t nTotalSpace = nCoinCacheUsage + std::max(nMempoolSizeMax - nMempoolUsage, 0); // The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing). - bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024); + bool fCacheLarge = mode == FlushStateMode::PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024); // The cache is over the limit, we have to write now. - bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nTotalSpace; + bool fCacheCritical = mode == FlushStateMode::IF_NEEDED && cacheSize > nTotalSpace; // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. - bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; + bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. - bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; + bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; // Combine all conditions that result in a full cache flush. - fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; + fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; // Write blocks and block index to disk. if (fDoFullFlush || fPeriodicWrite) { // Depend on nMinDiskSpace to ensure we can write block index @@ -2151,7 +2151,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState & nLastFlush = nNow; } } - if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) { + if (fDoFullFlush || ((mode == FlushStateMode::ALWAYS || mode == FlushStateMode::PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) { // Update best block in wallet (so we can detect restored wallets). GetMainSignals().SetBestChain(chainActive.GetLocator()); nLastSetChain = nNow; @@ -2165,14 +2165,14 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState & void FlushStateToDisk() { CValidationState state; const CChainParams& chainparams = Params(); - FlushStateToDisk(chainparams, state, FLUSH_STATE_ALWAYS); + FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS); } void PruneAndFlush() { CValidationState state; fCheckForPruning = true; const CChainParams& chainparams = Params(); - FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); + FlushStateToDisk(chainparams, state, FlushStateMode::NONE); } static void DoWarning(const std::string& strWarning) @@ -2200,9 +2200,9 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { WarningBitsConditionChecker checker(bit); ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); - if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { + if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) { const std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); - if (state == THRESHOLD_ACTIVE) { + if (state == ThresholdState::ACTIVE) { DoWarning(strWarning); } else { warningMessages.push_back(strWarning); @@ -2268,7 +2268,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha } LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI); // Write the chain state to disk, if necessary. - if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED)) + if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED)) return false; if (disconnectpool) { @@ -2406,7 +2406,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3; LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal); // Write the chain state to disk, if necessary. - if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED)) + if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED)) return false; int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal); @@ -2683,7 +2683,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& CheckBlockIndex(chainparams.GetConsensus()); // Write changes periodically to disk, after relay. - if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_PERIODIC)) { + if (!FlushStateToDisk(chainparams, state, FlushStateMode::PERIODIC)) { return false; } @@ -3071,7 +3071,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params) { LOCK(cs_main); - return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE); + return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE); } // Compute at which vout of the block's coinbase transaction the witness @@ -3190,7 +3190,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c // Start enforcing BIP113 (Median Time Past) using versionbits logic. int nLockTimeFlags = 0; - if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { + if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) { nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; } @@ -3224,7 +3224,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c // {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are // multiple, the last one is used. bool fHaveWitness = false; - if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE) { + if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE) { int commitpos = GetWitnessCommitmentIndex(block); if (commitpos != -1) { bool malleated = false; @@ -3439,7 +3439,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr& pblock, CVali } if (fCheckForPruning) - FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files + FlushStateToDisk(chainparams, state, FlushStateMode::NONE); // we just allocated more disk space for block files CheckBlockIndex(chainparams.GetConsensus()); @@ -3592,7 +3592,7 @@ void PruneBlockFilesManual(int nManualPruneHeight) { CValidationState state; const CChainParams& chainparams = Params(); - FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE, nManualPruneHeight); + FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight); } /** @@ -4085,7 +4085,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params) return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight); } // Occasionally flush state to disk. - if (!FlushStateToDisk(params, state, FLUSH_STATE_PERIODIC)) + if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) return false; } @@ -4151,7 +4151,7 @@ bool RewindBlockIndex(const CChainParams& params) { // and skip it here, we're about to -reindex-chainstate anyway, so // it'll get called a bunch real soon. CValidationState state; - if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) { + if (!FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) { return false; } } diff --git a/src/versionbits.cpp b/src/versionbits.cpp index d2ee49db2..e3ec07817 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -29,7 +29,7 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* // Check if this deployment is always active. if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) { - return THRESHOLD_ACTIVE; + return ThresholdState::ACTIVE; } // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1. @@ -42,12 +42,12 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* while (cache.count(pindexPrev) == 0) { if (pindexPrev == nullptr) { // The genesis block is by definition defined. - cache[pindexPrev] = THRESHOLD_DEFINED; + cache[pindexPrev] = ThresholdState::DEFINED; break; } if (pindexPrev->GetMedianTimePast() < nTimeStart) { // Optimization: don't recompute down further, as we know every earlier block will be before the start time - cache[pindexPrev] = THRESHOLD_DEFINED; + cache[pindexPrev] = ThresholdState::DEFINED; break; } vToCompute.push_back(pindexPrev); @@ -65,17 +65,17 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* vToCompute.pop_back(); switch (state) { - case THRESHOLD_DEFINED: { + case ThresholdState::DEFINED: { if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { - stateNext = THRESHOLD_FAILED; + stateNext = ThresholdState::FAILED; } else if (pindexPrev->GetMedianTimePast() >= nTimeStart) { - stateNext = THRESHOLD_STARTED; + stateNext = ThresholdState::STARTED; } break; } - case THRESHOLD_STARTED: { + case ThresholdState::STARTED: { if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { - stateNext = THRESHOLD_FAILED; + stateNext = ThresholdState::FAILED; break; } // We need to count @@ -88,17 +88,17 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexCount = pindexCount->pprev; } if (count >= nThreshold) { - stateNext = THRESHOLD_LOCKED_IN; + stateNext = ThresholdState::LOCKED_IN; } break; } - case THRESHOLD_LOCKED_IN: { + case ThresholdState::LOCKED_IN: { // Always progresses into ACTIVE. - stateNext = THRESHOLD_ACTIVE; + stateNext = ThresholdState::ACTIVE; break; } - case THRESHOLD_FAILED: - case THRESHOLD_ACTIVE: { + case ThresholdState::FAILED: + case ThresholdState::ACTIVE: { // Nothing happens, these are terminal states. break; } @@ -149,7 +149,7 @@ int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* const ThresholdState initialState = GetStateFor(pindexPrev, params, cache); // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment." - if (initialState == THRESHOLD_DEFINED) { + if (initialState == ThresholdState::DEFINED) { return 0; } diff --git a/src/versionbits.h b/src/versionbits.h index 1600dc8c9..65cf308c7 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -17,12 +17,12 @@ static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL; /** Total bits available for versionbits */ static const int32_t VERSIONBITS_NUM_BITS = 29; -enum ThresholdState { - THRESHOLD_DEFINED, - THRESHOLD_STARTED, - THRESHOLD_LOCKED_IN, - THRESHOLD_ACTIVE, - THRESHOLD_FAILED, +enum class ThresholdState { + DEFINED, + STARTED, + LOCKED_IN, + ACTIVE, + FAILED, }; // A map that gives the state for blocks whose height is a multiple of Period(). diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index ebe7b48da..553cae4d0 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -235,13 +235,13 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, recoverFunc_type Db db(dbenv.get(), 0); int result = db.verify(strFile.c_str(), nullptr, nullptr, 0); if (result == 0) - return VERIFY_OK; + return VerifyResult::VERIFY_OK; else if (recoverFunc == nullptr) - return RECOVER_FAIL; + return VerifyResult::RECOVER_FAIL; // Try to recover: bool fRecovered = (*recoverFunc)(fs::path(strPath) / strFile, out_backup_filename); - return (fRecovered ? RECOVER_OK : RECOVER_FAIL); + return (fRecovered ? VerifyResult::RECOVER_OK : VerifyResult::RECOVER_FAIL); } bool CDB::Recover(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename) @@ -347,7 +347,7 @@ bool CDB::VerifyDatabaseFile(const fs::path& file_path, std::string& warningStr, { std::string backup_filename; CDBEnv::VerifyResult r = env->Verify(walletFile, recoverFunc, backup_filename); - if (r == CDBEnv::RECOVER_OK) + if (r == CDBEnv::VerifyResult::RECOVER_OK) { warningStr = strprintf(_("Warning: Wallet file corrupt, data salvaged!" " Original %s saved as %s in %s; if" @@ -355,7 +355,7 @@ bool CDB::VerifyDatabaseFile(const fs::path& file_path, std::string& warningStr, " restore from a backup."), walletFile, backup_filename, walletDir); } - if (r == CDBEnv::RECOVER_FAIL) + if (r == CDBEnv::VerifyResult::RECOVER_FAIL) { errorStr = strprintf(_("%s corrupt, salvage failed"), walletFile); return false; diff --git a/src/wallet/db.h b/src/wallet/db.h index b1ce45153..65bb8cc25 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -53,7 +53,7 @@ class CDBEnv * This must be called BEFORE strFile is opened. * Returns true if strFile is OK. */ - enum VerifyResult { VERIFY_OK, + enum class VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL }; typedef bool (*recoverFunc_type)(const fs::path& file_path, std::string& out_backup_filename); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 0edc8d8d6..0db1fc21d 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -409,7 +409,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) vHash.push_back(hash); std::vector vHashOut; - if (pwallet->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) { + if (pwallet->ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) { throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction."); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 457abec1b..e7fdc2429 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -113,9 +113,9 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) if (confirms <= 0) { LOCK(mempool.cs); RBFTransactionState rbfState = IsRBFOptIn(*wtx.tx, mempool); - if (rbfState == RBF_TRANSACTIONSTATE_UNKNOWN) + if (rbfState == RBFTransactionState::UNKNOWN) rbfStatus = "unknown"; - else if (rbfState == RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125) + else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) rbfStatus = "yes"; } entry.pushKV("bip125-replaceable", rbfStatus); diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp index 7b20bd7b0..8cb87c195 100644 --- a/src/wallet/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -18,7 +18,7 @@ GetResults(CWallet& wallet, std::map& results) std::list aes; results.clear(); - BOOST_CHECK(wallet.ReorderTransactions() == DB_LOAD_OK); + BOOST_CHECK(wallet.ReorderTransactions() == DBErrors::LOAD_OK); wallet.ListAccountCreditDebit("", aes); for (CAccountingEntry& ae : aes) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0c468878e..613bb4688 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -737,11 +737,11 @@ DBErrors CWallet::ReorderTransactions() if (pwtx) { if (!walletdb.WriteTx(*pwtx)) - return DB_LOAD_FAIL; + return DBErrors::LOAD_FAIL; } else if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) - return DB_LOAD_FAIL; + return DBErrors::LOAD_FAIL; } else { @@ -761,16 +761,16 @@ DBErrors CWallet::ReorderTransactions() if (pwtx) { if (!walletdb.WriteTx(*pwtx)) - return DB_LOAD_FAIL; + return DBErrors::LOAD_FAIL; } else if (!walletdb.WriteAccountingEntry(pacentry->nEntryNo, *pacentry)) - return DB_LOAD_FAIL; + return DBErrors::LOAD_FAIL; } } walletdb.WriteOrderPosNext(nOrderPosNext); - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) @@ -3134,7 +3134,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) fFirstRunRet = false; DBErrors nLoadWalletRet = CWalletDB(*dbw,"cr+").LoadWallet(this); - if (nLoadWalletRet == DB_NEED_REWRITE) + if (nLoadWalletRet == DBErrors::NEED_REWRITE) { if (dbw->Rewrite("\x04pool")) { @@ -3150,12 +3150,12 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) // This wallet is in its first run if all of these are empty fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty(); - if (nLoadWalletRet != DB_LOAD_OK) + if (nLoadWalletRet != DBErrors::LOAD_OK) return nLoadWalletRet; uiInterface.LoadWallet(this); - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } DBErrors CWallet::ZapSelectTx(std::vector& vHashIn, std::vector& vHashOut) @@ -3165,7 +3165,7 @@ DBErrors CWallet::ZapSelectTx(std::vector& vHashIn, std::vectorRewrite("\x04pool")) { @@ -3178,19 +3178,19 @@ DBErrors CWallet::ZapSelectTx(std::vector& vHashIn, std::vector& vWtx) { DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx); - if (nZapWalletTxRet == DB_NEED_REWRITE) + if (nZapWalletTxRet == DBErrors::NEED_REWRITE) { if (dbw->Rewrite("\x04pool")) { @@ -3204,10 +3204,10 @@ DBErrors CWallet::ZapWalletTx(std::vector& vWtx) } } - if (nZapWalletTxRet != DB_LOAD_OK) + if (nZapWalletTxRet != DBErrors::LOAD_OK) return nZapWalletTxRet; - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } @@ -3919,7 +3919,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& std::unique_ptr tempWallet = MakeUnique(name, CWalletDBWrapper::Create(path)); DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); - if (nZapWalletRet != DB_LOAD_OK) { + if (nZapWalletRet != DBErrors::LOAD_OK) { InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); return nullptr; } @@ -3931,23 +3931,23 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path& bool fFirstRun = true; CWallet *walletInstance = new CWallet(name, CWalletDBWrapper::Create(path)); DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); - if (nLoadWalletRet != DB_LOAD_OK) + if (nLoadWalletRet != DBErrors::LOAD_OK) { - if (nLoadWalletRet == DB_CORRUPT) { + if (nLoadWalletRet == DBErrors::CORRUPT) { InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); return nullptr; } - else if (nLoadWalletRet == DB_NONCRITICAL_ERROR) + else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR) { InitWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data" " or address book entries might be missing or incorrect."), walletFile)); } - else if (nLoadWalletRet == DB_TOO_NEW) { + else if (nLoadWalletRet == DBErrors::TOO_NEW) { InitError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME))); return nullptr; } - else if (nLoadWalletRet == DB_NEED_REWRITE) + else if (nLoadWalletRet == DBErrors::NEED_REWRITE) { InitError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME))); return nullptr; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 0b0880a2b..4925d96d9 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -522,7 +522,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) { CWalletScanState wss; bool fNoncriticalErrors = false; - DBErrors result = DB_LOAD_OK; + DBErrors result = DBErrors::LOAD_OK; LOCK(pwallet->cs_wallet); try { @@ -530,7 +530,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (batch.Read((std::string)"minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) - return DB_TOO_NEW; + return DBErrors::TOO_NEW; pwallet->LoadMinVersion(nMinVersion); } @@ -539,7 +539,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if (!pcursor) { LogPrintf("Error getting wallet database cursor\n"); - return DB_CORRUPT; + return DBErrors::CORRUPT; } while (true) @@ -553,7 +553,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) else if (ret != 0) { LogPrintf("Error reading next record from wallet database\n"); - return DB_CORRUPT; + return DBErrors::CORRUPT; } // Try to be tolerant of single corrupt records: @@ -563,7 +563,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) // losing keys is considered a catastrophic error, anything else // we assume the user can live with: if (IsKeyType(strType) || strType == "defaultkey") - result = DB_CORRUPT; + result = DBErrors::CORRUPT; else { // Leave other errors alone, if we try to fix them we might make things worse. @@ -582,15 +582,15 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) throw; } catch (...) { - result = DB_CORRUPT; + result = DBErrors::CORRUPT; } - if (fNoncriticalErrors && result == DB_LOAD_OK) - result = DB_NONCRITICAL_ERROR; + if (fNoncriticalErrors && result == DBErrors::LOAD_OK) + result = DBErrors::NONCRITICAL_ERROR; // Any wallet corruption at all: skip any rewriting or // upgrading, we don't want to make it worse. - if (result != DB_LOAD_OK) + if (result != DBErrors::LOAD_OK) return result; LogPrintf("nFileVersion = %d\n", wss.nFileVersion); @@ -607,7 +607,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000)) - return DB_NEED_REWRITE; + return DBErrors::NEED_REWRITE; if (wss.nFileVersion < CLIENT_VERSION) // Update WriteVersion(CLIENT_VERSION); @@ -626,14 +626,14 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) DBErrors CWalletDB::FindWalletTx(std::vector& vTxHash, std::vector& vWtx) { - DBErrors result = DB_LOAD_OK; + DBErrors result = DBErrors::LOAD_OK; try { int nMinVersion = 0; if (batch.Read((std::string)"minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) - return DB_TOO_NEW; + return DBErrors::TOO_NEW; } // Get cursor @@ -641,7 +641,7 @@ DBErrors CWalletDB::FindWalletTx(std::vector& vTxHash, std::vector& vTxHash, std::vector& vTxHash, std::vector& vTxHashIn, std::vector vTxHash; std::vector vWtx; DBErrors err = FindWalletTx(vTxHash, vWtx); - if (err != DB_LOAD_OK) { + if (err != DBErrors::LOAD_OK) { return err; } @@ -716,9 +716,9 @@ DBErrors CWalletDB::ZapSelectTx(std::vector& vTxHashIn, std::vector& vWtx) @@ -726,16 +726,16 @@ DBErrors CWalletDB::ZapWalletTx(std::vector& vWtx) // build list of wallet TXs std::vector vTxHash; DBErrors err = FindWalletTx(vTxHash, vWtx); - if (err != DB_LOAD_OK) + if (err != DBErrors::LOAD_OK) return err; // erase each wallet TX for (uint256& hash : vTxHash) { if (!EraseTx(hash)) - return DB_CORRUPT; + return DBErrors::CORRUPT; } - return DB_LOAD_OK; + return DBErrors::LOAD_OK; } void MaybeCompactWalletDB() diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 7d754c728..606b7dace 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -46,14 +46,14 @@ class uint160; class uint256; /** Error statuses for the wallet database */ -enum DBErrors +enum class DBErrors { - DB_LOAD_OK, - DB_CORRUPT, - DB_NONCRITICAL_ERROR, - DB_TOO_NEW, - DB_LOAD_FAIL, - DB_NEED_REWRITE + LOAD_OK, + CORRUPT, + NONCRITICAL_ERROR, + TOO_NEW, + LOAD_FAIL, + NEED_REWRITE }; /* simple HD chain data model */ From 386a6b62a8a1db9dd0f354cb95b7585f555c7e5d Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 9 Mar 2018 12:12:43 +0800 Subject: [PATCH 019/900] Allow to optional specify the directory for the blocks storage --- src/init.cpp | 9 +++++++-- src/qt/bitcoin.cpp | 2 +- src/txdb.cpp | 2 +- src/util.cpp | 33 +++++++++++++++++++++++++++++++++ src/util.h | 1 + src/validation.cpp | 12 ++++++------ src/validation.h | 2 +- 7 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f763c3a43..eb8beda8d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -333,6 +333,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-version", _("Print version 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) @@ -596,7 +597,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 && @@ -908,6 +909,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 if (gArgs.GetArg("-prune", 0)) { if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) @@ -1630,7 +1635,7 @@ bool AppInitMain() // ********************************************************* Step 10: 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/bitcoin.cpp b/src/qt/bitcoin.cpp index ab381bfb5..a47b4af44 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -617,7 +617,7 @@ int main(int argc, char *argv[]) if (!Intro::pickDataDirectory()) return EXIT_SUCCESS; - /// 6. Determine availability of data directory and parse bitcoin.conf + /// 6. Determine availability of data and blocks directory and parse bitcoin.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 293d43c7b..f6d60411b 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -147,7 +147,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) { +CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetBlocksDir() / "index", nCacheSize, fMemory, fWipe) { } bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) { diff --git a/src/util.cpp b/src/util.cpp index dcf7ed38b..18a020ccd 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -598,10 +598,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) { @@ -640,6 +671,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 9490a5678..0c31ac5e6 100644 --- a/src/util.h +++ b/src/util.h @@ -182,6 +182,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); void ClearDatadirCache(); fs::path GetConfigFile(const std::string& confPath); diff --git a/src/validation.cpp b/src/validation.cpp index a77362f5d..16bba4f7b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2056,7 +2056,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(); @@ -2895,7 +2895,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); @@ -2928,7 +2928,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); @@ -3604,9 +3604,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) @@ -3649,7 +3649,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 99cbfdf1e..ba7a018ec 100644 --- a/src/validation.h +++ b/src/validation.h @@ -254,7 +254,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=nullptr, CBlockHeader *first_invalid=nullptr); /** 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 */ From cba2800e8c4e73c2eddff76880b55d930c5010f6 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 28 Feb 2018 21:15:01 +0100 Subject: [PATCH 020/900] Increase signal-to-noise ratio in debug.log by adjusting log level when logging failed non-manual connect():s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this patch: ``` $ src/bitcoind -printtoconsole … 2018-02-28 18:42:51 UpdateTip: new best=0000000000005448b10a219683d34b770a28044e1cc421032dea1a79ff548948 height=1286903 version=0x20000000 log2_work=69.791313 tx=17408546 date='2018-02-28 18:42:46' progress=1.000000 cache=0.0MiB(173txo) 2018-02-28T18:37:52Z connect() 10.11.21.34:18333 failed after select(): Connection refused (111) 2018-02-28 18:43:22 connect() to 10.11.43.14:18333 failed after select(): Network is unreachable (101) 2018-02-28 18:44:49 UpdateTip: new best=000000000000029a521ff2803e1441b09413b876accff5084a4cccf7747d798b height=1286904 version=0x20000000 log2_work=69.791345 tx=17408559 date='2018-02-28 18:44:51' progress=1.000000 cache=0.1MiB(502txo) 2018-02-28 18:46:54 connect() to [2001:0:9d38:78ff:1234:1234:1234:1234]:18333 failed: Network is unreachable (101) 2018-02-28 18:48:56 connect() to [2001:0:9d38:6aff:1234:1234:1234:1234]:18333 failed: Network is unreachable (101) 2018-02-28 18:49:11 UpdateTip: new best=000000000000000206b79eb235e5dd907b6369de0e5d764330bf40ec0d460311 height=1286905 version=0x20000000 log2_work=69.791377 tx=17408577 date='2018-02-28 18:49:12' progress=1.000000 cache=1.0MiB(5245txo) ``` After this patch: ``` $ src/bitcoind -printtoconsole … 2018-02-28 18:42:51 UpdateTip: new best=0000000000005448b10a219683d34b770a28044e1cc421032dea1a79ff548948 height=1286903 version=0x20000000 log2_work=69.791313 tx=17408546 date='2018-02-28 18:42:46' progress=1.000000 cache=0.0MiB(173txo) 2018-02-28 18:44:49 UpdateTip: new best=000000000000029a521ff2803e1441b09413b876accff5084a4cccf7747d798b height=1286904 version=0x20000000 log2_work=69.791345 tx=17408559 date='2018-02-28 18:44:51' progress=1.000000 cache=0.1MiB(502txo) 2018-02-28 18:49:11 UpdateTip: new best=000000000000000206b79eb235e5dd907b6369de0e5d764330bf40ec0d460311 height=1286905 version=0x20000000 log2_work=69.791377 tx=17408577 date='2018-02-28 18:49:12' progress=1.000000 cache=1.0MiB(5245txo) ``` Please note that "manual connect():s" (invoked via `-connect`, `-proxy` or `addnode`) are still reported as usual: ``` $ src/bitcoind -printtoconsole -connect=10.11.12.13 … 2018-02-28 18:33:13 connect() to 10.11.12.13:18333 failed after select(): Connection refused (111) $ src/bitcoind -printtoconsole -proxy=10.11.12.13 … 2018-02-28 18:32:32 connect() to 10.11.12.13:9050 failed after select(): Connection refused (111) $ src/bitcoind -printtoconsole & $ src/bitcoin-cli addnode "10.11.12.13" onetry … 2018-02-28 18:34:40 connect() to 10.11.12.13:18333 failed after select(): Connection refused (111) ``` --- src/net.cpp | 6 +++--- src/net.h | 2 +- src/netbase.cpp | 20 ++++++++++++++++---- src/netbase.h | 2 +- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 33a60ac96..01db30f90 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -367,7 +367,7 @@ static CAddress GetBindAddress(SOCKET sock) return addr_bind; } -CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure) +CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection) { if (pszDest == nullptr) { if (IsLocal(addrConnect)) @@ -431,7 +431,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo if (hSocket == INVALID_SOCKET) { return nullptr; } - connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout); + connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout, manual_connection); } if (!proxyConnectionFailed) { // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to @@ -1991,7 +1991,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai } else if (FindNode(std::string(pszDest))) return; - CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure); + CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, manual_connection); if (!pnode) return; diff --git a/src/net.h b/src/net.h index 96f04d83e..b86e8a586 100644 --- a/src/net.h +++ b/src/net.h @@ -338,7 +338,7 @@ class CConnman CNode* FindNode(const CService& addr); bool AttemptToEvictConnection(); - CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure); + CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection); bool IsWhitelistedRange(const CNetAddr &addr); void DeleteNode(CNode* pnode); diff --git a/src/netbase.cpp b/src/netbase.cpp index 3ea3141d5..dd3211093 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -468,7 +469,17 @@ SOCKET CreateSocket(const CService &addrConnect) return hSocket; } -bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout) +template +static void LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args) { + std::string error_message = tfm::format(fmt, args...); + if (manual_connection) { + LogPrintf("%s\n", error_message); + } else { + LogPrint(BCLog::NET, "%s\n", error_message); + } +} + +bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); @@ -513,7 +524,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i } if (nRet != 0) { - LogPrintf("connect() to %s failed after select(): %s\n", addrConnect.ToString(), NetworkErrorString(nRet)); + LogConnectFailure(manual_connection, "connect() to %s failed after select(): %s", addrConnect.ToString(), NetworkErrorString(nRet)); return false; } } @@ -523,7 +534,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i else #endif { - LogPrintf("connect() to %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); + LogConnectFailure(manual_connection, "connect() to %s failed: %s", addrConnect.ToString(), NetworkErrorString(WSAGetLastError())); return false; } } @@ -581,7 +592,7 @@ bool IsProxy(const CNetAddr &addr) { bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool *outProxyConnectionFailed) { // first connect to proxy server - if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) { + if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout, true)) { if (outProxyConnectionFailed) *outProxyConnectionFailed = true; return false; @@ -601,6 +612,7 @@ bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int } return true; } + bool LookupSubNet(const char* pszName, CSubNet& ret) { std::string strSubnet(pszName); diff --git a/src/netbase.h b/src/netbase.h index c0921b644..50d4bc54f 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -52,7 +52,7 @@ bool Lookup(const char *pszName, std::vector& vAddr, int portDefault, CService LookupNumeric(const char *pszName, int portDefault = 0); bool LookupSubNet(const char *pszName, CSubNet& subnet); SOCKET CreateSocket(const CService &addrConnect); -bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout); +bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocketRet, int nTimeout, bool manual_connection); bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed); /** Return readable error string for a network error code */ std::string NetworkErrorString(int err); From 8674e74b47c1f6e86a367cfbc738fcc9812b616b Mon Sep 17 00:00:00 2001 From: murrayn Date: Wed, 7 Mar 2018 03:08:55 -0800 Subject: [PATCH 021/900] Provide relevant error message if datadir is not writable. --- src/init.cpp | 3 +++ src/test/util_tests.cpp | 16 ++++++++++++++++ src/util.cpp | 13 +++++++++++++ src/util.h | 1 + 4 files changed, 33 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index f763c3a43..6493ae72b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1165,6 +1165,9 @@ static bool LockDataDirectory(bool probeOnly) { // Make sure only a single Bitcoin process is using the data directory. fs::path datadir = GetDataDir(); + if (!DirIsWritable(datadir)) { + return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string())); + } if (!LockDirectory(datadir, ".lock", probeOnly)) { return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), _(PACKAGE_NAME))); } diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 58f033cd8..e750969b6 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -800,4 +800,20 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory) fs::remove_all(dirname); } +BOOST_AUTO_TEST_CASE(test_DirIsWritable) +{ + // Should be able to write to the system tmp dir. + fs::path tmpdirname = fs::temp_directory_path(); + BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true); + + // Should not be able to write to a non-existent dir. + tmpdirname = fs::temp_directory_path() / fs::unique_path(); + BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), false); + + fs::create_directory(tmpdirname); + // Should be able to write to it now. + BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true); + fs::remove(tmpdirname); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util.cpp b/src/util.cpp index 82c99a3c2..7ea797256 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -418,6 +418,19 @@ void ReleaseDirectoryLocks() dir_locks.clear(); } +bool DirIsWritable(const fs::path& directory) +{ + fs::path tmpFile = directory / fs::unique_path(); + + FILE* file = fsbridge::fopen(tmpFile, "a"); + if (!file) return false; + + fclose(file); + remove(tmpFile); + + return true; +} + /** Interpret string as boolean, for argument parsing */ static bool InterpretBool(const std::string& strValue) { diff --git a/src/util.h b/src/util.h index e4170d8aa..3e1937549 100644 --- a/src/util.h +++ b/src/util.h @@ -174,6 +174,7 @@ int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); bool RenameOver(fs::path src, fs::path dest); bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false); +bool DirIsWritable(const fs::path& directory); /** Release all directory locks. This is used for unit testing only, at runtime * the global destructor will take care of the locks. From 6ef99826b9ab2c9d95ed4b55403d22225bcf086a Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 15 Mar 2018 02:42:18 -0400 Subject: [PATCH 022/900] Actually disable BnB when there are preset inputs We don't want to use BnB when there are preset inputs because there is some weirdness with making that work with using the KnapsackSolver as the fallback. Currently we say that we haven't used bnb when there are preset inputs, but we don't actually disable BnB. This fixes that. --- src/wallet/wallet.cpp | 3 ++- src/wallet/wallet.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index bd5094085..db63a5a85 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2493,7 +2493,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil } } -bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const +bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const { std::vector vCoins(vAvailableCoins); @@ -2523,6 +2523,7 @@ bool CWallet::SelectCoins(const std::vector& vAvailableCoins, const CAm { // For now, don't use BnB if preset inputs are selected. TODO: Enable this later bnb_used = false; + coin_selection_params.use_bnb = false; std::map::const_iterator it = mapWallet.find(outpoint.hash); if (it != mapWallet.end()) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index dc0e8d07d..a88da71f9 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -674,7 +674,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface * if they are not ours */ bool SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, - const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const; + const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const; CWalletDB *pwalletdbEncryption; From 081bf54ee4a282eed72e7de409ad6b9ab97f2987 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 15 Mar 2018 11:25:50 -0400 Subject: [PATCH 023/900] Test that BnB is not used when there are preset inputs --- src/wallet/test/coinselector_tests.cpp | 16 +++++++++++++++- src/wallet/wallet.h | 17 ++++++++--------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index f05c81cd4..6c36e2e96 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -4,6 +4,7 @@ #include "wallet/wallet.h" #include "wallet/coinselection.h" +#include "wallet/coincontrol.h" #include "amount.h" #include "primitives/transaction.h" #include "random.h" @@ -27,7 +28,7 @@ std::vector> wtxn; typedef std::set CoinSet; static std::vector vCoins; -static const CWallet testWallet("dummy", CWalletDBWrapper::CreateDummy()); +static CWallet testWallet("dummy", CWalletDBWrapper::CreateDummy()); static CAmount balance = 0; CoinEligibilityFilter filter_standard(1, 6, 0); @@ -72,6 +73,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa } COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */); vCoins.push_back(output); + testWallet.AddToWallet(*wtx.get()); wtxn.emplace_back(std::move(wtx)); } @@ -222,6 +224,18 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(1); vCoins.at(0).nInputBytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail BOOST_CHECK(!testWallet.SelectCoinsMinConf( 1 * CENT, filter_standard, vCoins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used)); + + // Make sure that we aren't using BnB when there are preset inputs + empty_wallet(); + add_coin(5 * CENT); + add_coin(3 * CENT); + add_coin(2 * CENT); + CCoinControl coin_control; + coin_control.fAllowOtherInputs = true; + coin_control.Select(COutPoint(vCoins.at(0).tx->GetHash(), vCoins.at(0).i)); + BOOST_CHECK(testWallet.SelectCoins(vCoins, 10 * CENT, setCoinsRet, nValueRet, coin_control, coin_selection_params_bnb, bnb_used)); + BOOST_CHECK(!bnb_used); + BOOST_CHECK(!coin_selection_params_bnb.use_bnb); } BOOST_AUTO_TEST_CASE(knapsack_solver_test) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index a88da71f9..bb72eb168 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -667,15 +667,6 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface std::mutex mutexScanning; friend class WalletRescanReserver; - - /** - * Select a set of coins such that nValueRet >= nTargetValue and at least - * all coins from coinControl are selected; Never select unconfirmed coins - * if they are not ours - */ - bool SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, - const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const; - CWalletDB *pwalletdbEncryption; //! the current wallet version: clients below this version are not able to load the wallet @@ -768,6 +759,14 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface return *dbw; } + /** + * Select a set of coins such that nValueRet >= nTargetValue and at least + * all coins from coinControl are selected; Never select unconfirmed coins + * if they are not ours + */ + bool SelectCoins(const std::vector& vAvailableCoins, const CAmount& nTargetValue, std::set& setCoinsRet, CAmount& nValueRet, + const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const; + /** Get a name for this wallet for logging/debugging purposes. */ const std::string& GetName() const { return m_name; } From 577f11141c5155345c68809aac8511b018cc4050 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 16 Mar 2018 10:24:59 -0700 Subject: [PATCH 024/900] Make verify-commits.sh test that merges are clean --- contrib/verify-commits/verify-commits.sh | 32 ++++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh index 532b97a43..6415eea4d 100755 --- a/contrib/verify-commits/verify-commits.sh +++ b/contrib/verify-commits/verify-commits.sh @@ -35,6 +35,8 @@ NO_SHA1=1 PREV_COMMIT="" INITIAL_COMMIT="${CURRENT_COMMIT}" +BRANCH="$(git rev-parse --abbrev-ref HEAD)" + while true; do if [ "$CURRENT_COMMIT" = $VERIFIED_ROOT ]; then echo "There is a valid path from \"$INITIAL_COMMIT\" to $VERIFIED_ROOT where all commits are signed!" @@ -123,9 +125,29 @@ while true; do fi PARENTS=$(git show -s --format=format:%P "$CURRENT_COMMIT") - for PARENT in $PARENTS; do - PREV_COMMIT="$CURRENT_COMMIT" - CURRENT_COMMIT="$PARENT" - break - done + PARENT1=${PARENTS%% *} + PARENT2="" + if [ "x$PARENT1" != "x$PARENTS" ]; then + PARENTX=${PARENTS#* } + PARENT2=${PARENTX%% *} + if [ "x$PARENT2" != "x$PARENTX" ]; then + echo "Commit $CURRENT_COMMIT is an octopus merge" > /dev/stderr + exit 1 + fi + fi + if [ "x$PARENT2" != "x" ]; then + CURRENT_TREE="$(git show --format="%T" "$CURRENT_COMMIT")" + git checkout --force --quiet "$PARENT1" + git merge --no-ff --quiet "$PARENT2" >/dev/null + RECREATED_TREE="$(git show --format="%T" HEAD)" + if [ "$CURRENT_TREE" != "$RECREATED_TREE" ]; then + echo "Merge commit $CURRENT_COMMIT is not clean" > /dev/stderr + git diff "$CURRENT_COMMIT" + git checkout --force --quiet "$BRANCH" + exit 1 + fi + git checkout --force --quiet "$BRANCH" + fi + PREV_COMMIT="$CURRENT_COMMIT" + CURRENT_COMMIT="$PARENT1" done From f38e4fdb06406f9a1a2562836fab523eb75b5090 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 9 Mar 2018 12:43:55 +0800 Subject: [PATCH 025/900] QA: Add -blocksdir test --- test/functional/feature_blocksdir.py | 34 ++++++++++++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 35 insertions(+) create mode 100755 test/functional/feature_blocksdir.py diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py new file mode 100755 index 000000000..e9d7b9de5 --- /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(self.options.tmpdir+ "/blocksdir/regtest/blocks/blk00000.dat")) + assert(os.path.isdir(self.options.tmpdir+ "/blocksdir/regtest/blocks/index")) + +if __name__ == '__main__': + BlocksdirTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 082191098..14211cd40 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -133,6 +133,7 @@ 'p2p_unrequested_blocks.py', 'feature_logging.py', 'p2p_node_network_limited.py', + 'feature_blocksdir.py', 'feature_config_args.py', # Don't append tests at the end to avoid merge conflicts # Put them in a random line within the section that fits their approximate run-time From 0ec08a672dce3f619e46d0c7455e95a13dc5c4e2 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 7 Feb 2018 09:36:13 -0500 Subject: [PATCH 026/900] [Tests] Move assert_start_raises_init_error method to TestNode --- test/functional/feature_config_args.py | 4 +-- test/functional/feature_logging.py | 4 +-- test/functional/feature_uacomment.py | 4 +-- .../test_framework/test_framework.py | 21 -------------- test/functional/test_framework/test_node.py | 28 +++++++++++++++++++ test/functional/wallet_hd.py | 2 +- test/functional/wallet_multiwallet.py | 18 ++++++------ 7 files changed, 44 insertions(+), 37 deletions(-) diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index c6cec0596..eb62ffc6a 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -25,13 +25,13 @@ def run_test(self): # Check that using -datadir argument on non-existent directory fails self.nodes[0].datadir = new_data_dir - self.assert_start_raises_init_error(0, ['-datadir='+new_data_dir], 'Error: Specified data directory "' + new_data_dir + '" does not exist.') + self.nodes[0].assert_start_raises_init_error(['-datadir='+new_data_dir], 'Error: Specified data directory "' + new_data_dir + '" does not exist.') # Check that using non-existent datadir in conf file fails conf_file = os.path.join(default_data_dir, "bitcoin.conf") with open(conf_file, 'a', encoding='utf8') as f: f.write("datadir=" + new_data_dir + "\n") - self.assert_start_raises_init_error(0, ['-conf='+conf_file], 'Error reading configuration file: specified data directory "' + new_data_dir + '" does not exist.') + self.nodes[0].assert_start_raises_init_error(['-conf='+conf_file], 'Error reading configuration file: specified data directory "' + new_data_dir + '" does not exist.') # Create the directory and ensure the config file now works os.mkdir(new_data_dir) diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py index da4e7b039..65a03e50a 100755 --- a/test/functional/feature_logging.py +++ b/test/functional/feature_logging.py @@ -30,7 +30,7 @@ def run_test(self): invdir = os.path.join(self.nodes[0].datadir, "regtest", "foo") invalidname = os.path.join("foo", "foo.log") self.stop_node(0) - self.assert_start_raises_init_error(0, ["-debuglogfile=%s" % (invalidname)], + self.nodes[0].assert_start_raises_init_error(["-debuglogfile=%s" % (invalidname)], "Error: Could not open debug log file") assert not os.path.isfile(os.path.join(invdir, "foo.log")) @@ -44,7 +44,7 @@ def run_test(self): self.stop_node(0) invdir = os.path.join(self.options.tmpdir, "foo") invalidname = os.path.join(invdir, "foo.log") - self.assert_start_raises_init_error(0, ["-debuglogfile=%s" % invalidname], + self.nodes[0].assert_start_raises_init_error(["-debuglogfile=%s" % invalidname], "Error: Could not open debug log file") assert not os.path.isfile(os.path.join(invdir, "foo.log")) diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py index bc3791508..5725b85b2 100755 --- a/test/functional/feature_uacomment.py +++ b/test/functional/feature_uacomment.py @@ -24,12 +24,12 @@ def run_test(self): self.log.info("test -uacomment max length") self.stop_node(0) expected = "exceeds maximum length (256). Reduce the number or size of uacomments." - self.assert_start_raises_init_error(0, ["-uacomment=" + 'a' * 256], expected) + self.nodes[0].assert_start_raises_init_error(["-uacomment=" + 'a' * 256], expected) self.log.info("test -uacomment unsafe characters") for unsafe_char in ['/', ':', '(', ')']: expected = "User Agent comment (" + unsafe_char + ") contains unsafe characters" - self.assert_start_raises_init_error(0, ["-uacomment=" + unsafe_char], expected) + self.nodes[0].assert_start_raises_init_error(["-uacomment=" + unsafe_char], expected) if __name__ == '__main__': UacommentTest().main() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 8efac9c47..aeb335edb 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -281,27 +281,6 @@ def restart_node(self, i, extra_args=None): self.stop_node(i) self.start_node(i, extra_args) - def assert_start_raises_init_error(self, i, extra_args=None, expected_msg=None, *args, **kwargs): - with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: - try: - self.start_node(i, extra_args, stderr=log_stderr, *args, **kwargs) - self.stop_node(i) - except Exception as e: - assert 'bitcoind exited' in str(e) # node must have shutdown - self.nodes[i].running = False - self.nodes[i].process = None - if expected_msg is not None: - log_stderr.seek(0) - stderr = log_stderr.read().decode('utf-8') - if expected_msg not in stderr: - raise AssertionError("Expected error \"" + expected_msg + "\" not found in:\n" + stderr) - else: - if expected_msg is None: - assert_msg = "bitcoind should have exited with an error" - else: - assert_msg = "bitcoind should have exited with expected error " + expected_msg - raise AssertionError(assert_msg) - def wait_for_node_exit(self, i, timeout): self.nodes[i].process.wait(timeout) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 86e44e4c9..dbdaf6720 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -12,6 +12,7 @@ import os import re import subprocess +import tempfile import time from .authproxy import JSONRPCException @@ -165,6 +166,33 @@ def is_node_stopped(self): def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): wait_until(self.is_node_stopped, timeout=timeout) + def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, *args, **kwargs): + """Attempt to start the node and expect it to raise an error. + + Will throw if bitcoind starts without an error. + Will throw if an expected_msg is provided and it does not appear in bitcoind's stdout.""" + with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: + try: + self.start(extra_args, stderr=log_stderr, *args, **kwargs) + self.wait_for_rpc_connection() + self.stop_node() + self.wait_util_stopped() + except Exception as e: + assert 'bitcoind exited' in str(e) # node must have shutdown + self.running = False + self.process = None + if expected_msg is not None: + log_stderr.seek(0) + stderr = log_stderr.read().decode('utf-8') + if expected_msg not in stderr: + raise AssertionError("Expected error \"" + expected_msg + "\" not found in:\n" + stderr) + else: + if expected_msg is None: + assert_msg = "bitcoind should have exited with an error" + else: + assert_msg = "bitcoind should have exited with expected error " + expected_msg + raise AssertionError(assert_msg) + def node_encrypt_wallet(self, passphrase): """"Encrypts the wallet. diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 91f77dd5b..f37b4bf52 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -23,7 +23,7 @@ def run_test (self): # Make sure can't switch off usehd after wallet creation self.stop_node(1) - self.assert_start_raises_init_error(1, ['-usehd=0'], 'already existing HD wallet') + self.nodes[1].assert_start_raises_init_error(['-usehd=0'], 'already existing HD wallet') self.start_node(1) connect_nodes_bi(self.nodes, 0, 1) diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 378c06ee5..3a255238d 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -62,27 +62,27 @@ def run_test(self): # should not initialize if wallet path can't be created self.assert_start_raises_init_error(0, ['-wallet=wallet.dat/bad'], 'Not a directory') - self.assert_start_raises_init_error(0, ['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" does not exist') - self.assert_start_raises_init_error(0, ['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" is a relative path', cwd=data_dir()) - self.assert_start_raises_init_error(0, ['-walletdir=debug.log'], 'Error: Specified -walletdir "debug.log" is not a directory', cwd=data_dir()) + self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" does not exist') + self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" is a relative path', cwd=data_dir()) + self.nodes[0].assert_start_raises_init_error(['-walletdir=debug.log'], 'Error: Specified -walletdir "debug.log" is not a directory', cwd=data_dir()) # should not initialize if there are duplicate wallets - self.assert_start_raises_init_error(0, ['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') + self.nodes[0].assert_start_raises_init_error(['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') # should not initialize if one wallet is a copy of another shutil.copyfile(wallet_dir('w8'), wallet_dir('w8_copy')) - self.assert_start_raises_init_error(0, ['-wallet=w8', '-wallet=w8_copy'], 'duplicates fileid') + self.nodes[0].assert_start_raises_init_error(['-wallet=w8', '-wallet=w8_copy'], 'duplicates fileid') # should not initialize if wallet file is a symlink os.symlink('w8', wallet_dir('w8_symlink')) - self.assert_start_raises_init_error(0, ['-wallet=w8_symlink'], 'Invalid -wallet path') + self.nodes[0].assert_start_raises_init_error(['-wallet=w8_symlink'], 'Invalid -wallet path') # should not initialize if the specified walletdir does not exist - self.assert_start_raises_init_error(0, ['-walletdir=bad'], 'Error: Specified -walletdir "bad" does not exist') + self.nodes[0].assert_start_raises_init_error(['-walletdir=bad'], 'Error: Specified -walletdir "bad" does not exist') # should not initialize if the specified walletdir is not a directory not_a_dir = wallet_dir('notadir') open(not_a_dir, 'a').close() - self.assert_start_raises_init_error(0, ['-walletdir=' + not_a_dir], 'Error: Specified -walletdir "' + not_a_dir + '" is not a directory') + self.nodes[0].assert_start_raises_init_error(['-walletdir=' + not_a_dir], 'Error: Specified -walletdir "' + not_a_dir + '" is not a directory') # if wallets/ doesn't exist, datadir should be the default wallet dir wallet_dir2 = data_dir('walletdir') @@ -103,7 +103,7 @@ def run_test(self): competing_wallet_dir = os.path.join(self.options.tmpdir, 'competing_walletdir') os.mkdir(competing_wallet_dir) self.restart_node(0, ['-walletdir='+competing_wallet_dir]) - self.assert_start_raises_init_error(1, ['-walletdir='+competing_wallet_dir], 'Error initializing wallet database environment') + self.nodes[1].assert_start_raises_init_error(['-walletdir='+competing_wallet_dir], 'Error initializing wallet database environment') self.restart_node(0, extra_args) From 58122736b53390a2013630e95ff760800af160e7 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 7 Feb 2018 10:38:25 -0500 Subject: [PATCH 027/900] [Tests] Require exact match in assert_start_raises_init_eror() --- test/functional/feature_config_args.py | 5 +++-- test/functional/feature_logging.py | 7 +++---- test/functional/feature_uacomment.py | 8 ++++++-- test/functional/test_framework/test_node.py | 10 +++++++--- test/functional/wallet_hd.py | 2 +- test/functional/wallet_multiwallet.py | 21 +++++++++++++++------ 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index eb62ffc6a..0c3654705 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -5,6 +5,7 @@ """Test various command line arguments and configuration file parameters.""" import os +import re from test_framework.test_framework import BitcoinTestFramework from test_framework.util import get_datadir_path @@ -25,13 +26,13 @@ def run_test(self): # Check that using -datadir argument on non-existent directory fails self.nodes[0].datadir = new_data_dir - self.nodes[0].assert_start_raises_init_error(['-datadir='+new_data_dir], 'Error: Specified data directory "' + new_data_dir + '" does not exist.') + self.nodes[0].assert_start_raises_init_error(['-datadir=' + new_data_dir], 'Error: Specified data directory "' + re.escape(new_data_dir) + '" does not exist.') # Check that using non-existent datadir in conf file fails conf_file = os.path.join(default_data_dir, "bitcoin.conf") with open(conf_file, 'a', encoding='utf8') as f: f.write("datadir=" + new_data_dir + "\n") - self.nodes[0].assert_start_raises_init_error(['-conf='+conf_file], 'Error reading configuration file: specified data directory "' + new_data_dir + '" does not exist.') + self.nodes[0].assert_start_raises_init_error(['-conf=' + conf_file], 'Error reading configuration file: specified data directory "' + re.escape(new_data_dir) + '" does not exist.') # Create the directory and ensure the config file now works os.mkdir(new_data_dir) diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py index 65a03e50a..a4ebc7cca 100755 --- a/test/functional/feature_logging.py +++ b/test/functional/feature_logging.py @@ -30,8 +30,8 @@ def run_test(self): invdir = os.path.join(self.nodes[0].datadir, "regtest", "foo") invalidname = os.path.join("foo", "foo.log") self.stop_node(0) - self.nodes[0].assert_start_raises_init_error(["-debuglogfile=%s" % (invalidname)], - "Error: Could not open debug log file") + exp_stderr = "Error: Could not open debug log file \S+$" + self.nodes[0].assert_start_raises_init_error(["-debuglogfile=%s" % (invalidname)], exp_stderr) assert not os.path.isfile(os.path.join(invdir, "foo.log")) # check that invalid log (relative) works after path exists @@ -44,8 +44,7 @@ def run_test(self): self.stop_node(0) invdir = os.path.join(self.options.tmpdir, "foo") invalidname = os.path.join(invdir, "foo.log") - self.nodes[0].assert_start_raises_init_error(["-debuglogfile=%s" % invalidname], - "Error: Could not open debug log file") + self.nodes[0].assert_start_raises_init_error(["-debuglogfile=%s" % invalidname], exp_stderr) assert not os.path.isfile(os.path.join(invdir, "foo.log")) # check that invalid log (absolute) works after path exists diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py index 5725b85b2..c73bdcfbb 100755 --- a/test/functional/feature_uacomment.py +++ b/test/functional/feature_uacomment.py @@ -4,9 +4,12 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the -uacomment option.""" +import re + from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal + class UacommentTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 @@ -23,13 +26,14 @@ def run_test(self): self.log.info("test -uacomment max length") self.stop_node(0) - expected = "exceeds maximum length (256). Reduce the number or size of uacomments." + expected = "Error: Total length of network version string \([0-9]+\) exceeds maximum length \(256\). Reduce the number or size of uacomments." self.nodes[0].assert_start_raises_init_error(["-uacomment=" + 'a' * 256], expected) self.log.info("test -uacomment unsafe characters") for unsafe_char in ['/', ':', '(', ')']: - expected = "User Agent comment (" + unsafe_char + ") contains unsafe characters" + expected = "Error: User Agent comment \(" + re.escape(unsafe_char) + "\) contains unsafe characters." self.nodes[0].assert_start_raises_init_error(["-uacomment=" + unsafe_char], expected) + if __name__ == '__main__': UacommentTest().main() diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index dbdaf6720..8d8806910 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -169,8 +169,11 @@ def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, *args, **kwargs): """Attempt to start the node and expect it to raise an error. + extra_args: extra arguments to pass through to bitcoind + expected_msg: regex that stderr should match when bitcoind fails + Will throw if bitcoind starts without an error. - Will throw if an expected_msg is provided and it does not appear in bitcoind's stdout.""" + Will throw if an expected_msg is provided and it does not match bitcoind's stdout.""" with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: try: self.start(extra_args, stderr=log_stderr, *args, **kwargs) @@ -181,11 +184,12 @@ def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, *ar assert 'bitcoind exited' in str(e) # node must have shutdown self.running = False self.process = None + # Check stderr for expected message if expected_msg is not None: log_stderr.seek(0) stderr = log_stderr.read().decode('utf-8') - if expected_msg not in stderr: - raise AssertionError("Expected error \"" + expected_msg + "\" not found in:\n" + stderr) + if re.fullmatch(expected_msg + '\n', stderr) is None: + raise AssertionError('Expected message "{}" does not match stderr:\n"{}"'.format(expected_msg, stderr)) else: if expected_msg is None: assert_msg = "bitcoind should have exited with an error" diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index f37b4bf52..2f6e2852a 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -23,7 +23,7 @@ def run_test (self): # Make sure can't switch off usehd after wallet creation self.stop_node(1) - self.nodes[1].assert_start_raises_init_error(['-usehd=0'], 'already existing HD wallet') + self.nodes[1].assert_start_raises_init_error(['-usehd=0'], "Error: Error loading : You can't disable HD on an already existing HD wallet") self.start_node(1) connect_nodes_bi(self.nodes, 0, 1) diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 3a255238d..cc72f09c8 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -60,22 +60,30 @@ def run_test(self): assert_equal(os.path.isfile(wallet_dir(wallet_name)), True) # should not initialize if wallet path can't be created - self.assert_start_raises_init_error(0, ['-wallet=wallet.dat/bad'], 'Not a directory') + exp_stderr = "\n\n\*+\n" + \ + "EXCEPTION: .*\n" + \ + "boost::filesystem::create_directory: Not a directory:.*\n" + \ + "bitcoin in .*\n" + self.nodes[0].assert_start_raises_init_error(['-wallet=wallet.dat/bad'], exp_stderr) self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" does not exist') self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" is a relative path', cwd=data_dir()) self.nodes[0].assert_start_raises_init_error(['-walletdir=debug.log'], 'Error: Specified -walletdir "debug.log" is not a directory', cwd=data_dir()) # should not initialize if there are duplicate wallets - self.nodes[0].assert_start_raises_init_error(['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') + self.nodes[0].assert_start_raises_init_error(['-wallet=w1', '-wallet=w1'], 'Error: Error loading wallet w1. Duplicate -wallet filename specified.') # should not initialize if one wallet is a copy of another shutil.copyfile(wallet_dir('w8'), wallet_dir('w8_copy')) - self.nodes[0].assert_start_raises_init_error(['-wallet=w8', '-wallet=w8_copy'], 'duplicates fileid') + exp_stderr = "\n\n\*+\n" + \ + "EXCEPTION: .*\n" + \ + "CDB: Can't open database w8_copy \(duplicates fileid \w+ from w8\)\s*\n" + \ + "bitcoin in .*\n" + self.nodes[0].assert_start_raises_init_error(['-wallet=w8', '-wallet=w8_copy'], exp_stderr) # should not initialize if wallet file is a symlink os.symlink('w8', wallet_dir('w8_symlink')) - self.nodes[0].assert_start_raises_init_error(['-wallet=w8_symlink'], 'Invalid -wallet path') + self.nodes[0].assert_start_raises_init_error(['-wallet=w8_symlink'], 'Error: Invalid -wallet path \'w8_symlink\'\. .*') # should not initialize if the specified walletdir does not exist self.nodes[0].assert_start_raises_init_error(['-walletdir=bad'], 'Error: Specified -walletdir "bad" does not exist') @@ -102,8 +110,9 @@ def run_test(self): competing_wallet_dir = os.path.join(self.options.tmpdir, 'competing_walletdir') os.mkdir(competing_wallet_dir) - self.restart_node(0, ['-walletdir='+competing_wallet_dir]) - self.nodes[1].assert_start_raises_init_error(['-walletdir='+competing_wallet_dir], 'Error initializing wallet database environment') + self.restart_node(0, ['-walletdir=' + competing_wallet_dir]) + exp_stderr = "Error: Error initializing wallet database environment \"\S+competing_walletdir\"!" + self.nodes[1].assert_start_raises_init_error(['-walletdir=' + competing_wallet_dir], exp_stderr) self.restart_node(0, extra_args) From 6f7f5bc0026df12b64935b4e9db32cfc7b6e8829 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 29 Nov 2017 16:45:24 -0500 Subject: [PATCH 028/900] [tests] fix flake8 nits in feature_csv_activation.py --- test/functional/feature_csv_activation.py | 186 +++++++++++----------- 1 file changed, 96 insertions(+), 90 deletions(-) diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 8b5e5681e..0b353e78b 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -42,21 +42,30 @@ bip112txs_vary_OP_CSV_9 - 16 txs with nSequence = 9 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP bip112tx_special - test negative argument to OP_CSV """ +from decimal import Decimal +from io import BytesIO +import time -from test_framework.test_framework import ComparisonTestFramework -from test_framework.util import * -from test_framework.mininode import ToHex, CTransaction, network_thread_start from test_framework.blocktools import create_coinbase, create_block from test_framework.comptool import TestInstance, TestManager -from test_framework.script import * -from io import BytesIO -import time +from test_framework.mininode import ToHex, CTransaction, network_thread_start +from test_framework.script import ( + CScript, + OP_CHECKSEQUENCEVERIFY, + OP_DROP, +) +from test_framework.test_framework import ComparisonTestFramework +from test_framework.util import ( + assert_equal, + get_bip9_status, + hex_str_to_bytes, +) base_relative_locktime = 10 -seq_disable_flag = 1<<31 -seq_random_high_bit = 1<<25 -seq_type_flag = 1<<22 -seq_random_low_bit = 1<<18 +seq_disable_flag = 1 << 31 +seq_random_high_bit = 1 << 25 +seq_type_flag = 1 << 22 +seq_random_low_bit = 1 << 18 # b31,b25,b22,b18 represent the 31st, 25th, 22nd and 18th bits respectively in the nSequence field # relative_locktimes[b31][b25][b22][b18] is a base_relative_locktime with the indicated bits set if their indices are 1 @@ -108,8 +117,8 @@ def send_generic_input_tx(self, node, coinbases): return node.sendrawtransaction(ToHex(self.sign_transaction(node, self.create_transaction(node, node.getblock(coinbases.pop())['tx'][0], self.nodeaddress, amount)))) def create_transaction(self, node, txid, to_address, amount): - inputs = [{ "txid" : txid, "vout" : 0}] - outputs = { to_address : amount } + inputs = [{"txid": txid, "vout": 0}] + outputs = {to_address: amount} rawtx = node.createrawtransaction(inputs, outputs) tx = CTransaction() f = BytesIO(hex_str_to_bytes(rawtx)) @@ -124,7 +133,7 @@ def sign_transaction(self, node, unsignedtx): tx.deserialize(f) return tx - def generate_blocks(self, number, version, test_blocks = []): + def generate_blocks(self, number, version, test_blocks=[]): for i in range(number): block = self.create_test_block([], version) test_blocks.append([block, True]) @@ -133,7 +142,7 @@ def generate_blocks(self, number, version, test_blocks = []): self.tipheight += 1 return test_blocks - def create_test_block(self, txs, version = 536870912): + def create_test_block(self, txs, version=536870912): block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600) block.nVersion = version block.vtx.extend(txs) @@ -142,7 +151,7 @@ def create_test_block(self, txs, version = 536870912): block.solve() return block - def create_bip68txs(self, bip68inputs, txversion, locktime_delta = 0): + def create_bip68txs(self, bip68inputs, txversion, locktime_delta=0): txs = [] assert(len(bip68inputs) >= 16) i = 0 @@ -153,7 +162,7 @@ def create_bip68txs(self, bip68inputs, txversion, locktime_delta = 0): for b22 in range(2): b18txs = [] for b18 in range(2): - tx = self.create_transaction(self.nodes[0], bip68inputs[i], self.nodeaddress, Decimal("49.98")) + tx = self.create_transaction(self.nodes[0], bip68inputs[i], self.nodeaddress, Decimal("49.98")) i += 1 tx.nVersion = txversion tx.vin[0].nSequence = relative_locktimes[b31][b25][b22][b18] + locktime_delta @@ -170,7 +179,7 @@ def create_bip112special(self, input, txversion): signtx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig))) return signtx - def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta = 0): + def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta=0): txs = [] assert(len(bip112inputs) >= 16) i = 0 @@ -181,11 +190,11 @@ def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta = for b22 in range(2): b18txs = [] for b18 in range(2): - tx = self.create_transaction(self.nodes[0], bip112inputs[i], self.nodeaddress, Decimal("49.98")) + tx = self.create_transaction(self.nodes[0], bip112inputs[i], self.nodeaddress, Decimal("49.98")) i += 1 - if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed + if (varyOP_CSV): # if varying OP_CSV, nSequence is fixed tx.vin[0].nSequence = base_relative_locktime + locktime_delta - else: # vary nSequence instead, OP_CSV is fixed + else: # vary nSequence instead, OP_CSV is fixed tx.vin[0].nSequence = relative_locktimes[b31][b25][b22][b18] + locktime_delta tx.nVersion = txversion signtx = self.sign_transaction(self.nodes[0], tx) @@ -200,46 +209,47 @@ def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta = return txs def get_tests(self): - long_past_time = int(time.time()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future - self.nodes[0].setmocktime(long_past_time - 100) # enough so that the generated blocks will still all be before long_past_time - self.coinbase_blocks = self.nodes[0].generate(1 + 16 + 2*32 + 1) # 82 blocks generated for inputs - self.nodes[0].setmocktime(0) # set time back to present so yielded blocks aren't in the future as we advance last_block_time - self.tipheight = 82 # height of the next block to build + long_past_time = int(time.time()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future + self.nodes[0].setmocktime(long_past_time - 100) # enough so that the generated blocks will still all be before long_past_time + self.coinbase_blocks = self.nodes[0].generate(1 + 16 + 2 * 32 + 1) # 82 blocks generated for inputs + self.nodes[0].setmocktime(0) # set time back to present so yielded blocks aren't in the future as we advance last_block_time + self.tipheight = 82 # height of the next block to build self.last_block_time = long_past_time - self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0) + self.tip = int(self.nodes[0].getbestblockhash(), 16) self.nodeaddress = self.nodes[0].getnewaddress() assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined') test_blocks = self.generate_blocks(61, 4) - yield TestInstance(test_blocks, sync_every_block=False) # 1 + yield TestInstance(test_blocks, sync_every_block=False) # Advanced from DEFINED to STARTED, height = 143 assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') # Fail to achieve LOCKED_IN 100 out of 144 signal bit 0 # using a variety of bits to simulate multiple parallel softforks - test_blocks = self.generate_blocks(50, 536870913) # 0x20000001 (signalling ready) - test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not) - test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) - test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not) - yield TestInstance(test_blocks, sync_every_block=False) # 2 + test_blocks = self.generate_blocks(50, 536870913) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) # Failed to advance past STARTED, height = 287 assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') # 108 out of 144 signal bit 0 to achieve lock-in # using a variety of bits to simulate multiple parallel softforks - test_blocks = self.generate_blocks(58, 536870913) # 0x20000001 (signalling ready) - test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not) - test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) - test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not) - yield TestInstance(test_blocks, sync_every_block=False) # 3 + test_blocks = self.generate_blocks(58, 536870913) # 0x20000001 (signalling ready) + test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not) + test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) + test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not) + yield TestInstance(test_blocks, sync_every_block=False) # Advanced from STARTED to LOCKED_IN, height = 431 assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') # 140 more version 4 blocks test_blocks = self.generate_blocks(140, 4) - yield TestInstance(test_blocks, sync_every_block=False) # 4 + yield TestInstance(test_blocks, sync_every_block=False) - ### Inputs at height = 572 + # Inputs at height = 572 + # # Put inputs for all tests in the chain at height 572 (tip now = 571) (time increases by 600s per block) # Note we reuse inputs for v1 and v2 txs so must test these separately # 16 normal inputs @@ -266,16 +276,16 @@ def get_tests(self): bip113input = self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks) self.nodes[0].setmocktime(self.last_block_time + 600) - inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 572 + inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 572 self.nodes[0].setmocktime(0) - self.tip = int("0x" + inputblockhash, 0) + self.tip = int(inputblockhash, 16) self.tipheight += 1 self.last_block_time += 600 - assert_equal(len(self.nodes[0].getblock(inputblockhash,True)["tx"]), 82+1) + assert_equal(len(self.nodes[0].getblock(inputblockhash, True)["tx"]), 82 + 1) # 2 more version 4 blocks test_blocks = self.generate_blocks(2, 4) - yield TestInstance(test_blocks, sync_every_block=False) # 5 + yield TestInstance(test_blocks, sync_every_block=False) # Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575) assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') @@ -318,7 +328,7 @@ def get_tests(self): ### Version 1 txs ### success_txs = [] # add BIP113 tx and -1 CSV tx - bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) success_txs.append(bip113signed1) success_txs.append(bip112tx_special_v1) @@ -330,13 +340,13 @@ def get_tests(self): # try BIP 112 with seq=9 txs success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v1)) success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v1)) - yield TestInstance([[self.create_test_block(success_txs), True]]) # 6 + yield TestInstance([[self.create_test_block(success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) ### Version 2 txs ### success_txs = [] # add BIP113 tx and -1 CSV tx - bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) success_txs.append(bip113signed2) success_txs.append(bip112tx_special_v2) @@ -348,46 +358,44 @@ def get_tests(self): # try BIP 112 with seq=9 txs success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v2)) - yield TestInstance([[self.create_test_block(success_txs), True]]) # 7 + yield TestInstance([[self.create_test_block(success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - # 1 more version 4 block to get us to height 575 so the fork should now be active for the next block test_blocks = self.generate_blocks(1, 4) - yield TestInstance(test_blocks, sync_every_block=False) # 8 + yield TestInstance(test_blocks, sync_every_block=False) assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active') - ################################# ### After Soft Forks Activate ### ################################# ### BIP 113 ### # BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules - bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) - bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) for bip113tx in [bip113signed1, bip113signed2]: - yield TestInstance([[self.create_test_block([bip113tx]), False]]) # 9,10 + yield TestInstance([[self.create_test_block([bip113tx]), False]]) # BIP 113 tests should now pass if the locktime is < MTP - bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block + bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) - bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block + bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block bip113signed2 = self.sign_transaction(self.nodes[0], bip113tx_v2) for bip113tx in [bip113signed1, bip113signed2]: - yield TestInstance([[self.create_test_block([bip113tx]), True]]) # 11,12 + yield TestInstance([[self.create_test_block([bip113tx]), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) # Next block height = 580 after 4 blocks of random version test_blocks = self.generate_blocks(4, 1234) - yield TestInstance(test_blocks, sync_every_block=False) # 13 + yield TestInstance(test_blocks, sync_every_block=False) ### BIP 68 ### ### Version 1 txs ### # All still pass success_txs = [] success_txs.extend(all_rlt_txs(bip68txs_v1)) - yield TestInstance([[self.create_test_block(success_txs), True]]) # 14 + yield TestInstance([[self.create_test_block(success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) ### Version 2 txs ### @@ -397,7 +405,7 @@ def get_tests(self): for b22 in range(2): for b18 in range(2): bip68success_txs.append(bip68txs_v2[1][b25][b22][b18]) - yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 15 + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) # All txs without flag fail as we are at delta height = 8 < 10 and delta time = 8 * 600 < 10 * 512 bip68timetxs = [] @@ -405,39 +413,38 @@ def get_tests(self): for b18 in range(2): bip68timetxs.append(bip68txs_v2[0][b25][1][b18]) for tx in bip68timetxs: - yield TestInstance([[self.create_test_block([tx]), False]]) # 16 - 19 + yield TestInstance([[self.create_test_block([tx]), False]]) bip68heighttxs = [] for b25 in range(2): for b18 in range(2): bip68heighttxs.append(bip68txs_v2[0][b25][0][b18]) for tx in bip68heighttxs: - yield TestInstance([[self.create_test_block([tx]), False]]) # 20 - 23 + yield TestInstance([[self.create_test_block([tx]), False]]) # Advance one block to 581 test_blocks = self.generate_blocks(1, 1234) - yield TestInstance(test_blocks, sync_every_block=False) # 24 + yield TestInstance(test_blocks, sync_every_block=False) # Height txs should fail and time txs should now pass 9 * 600 > 10 * 512 bip68success_txs.extend(bip68timetxs) - yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 25 + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) for tx in bip68heighttxs: - yield TestInstance([[self.create_test_block([tx]), False]]) # 26 - 29 + yield TestInstance([[self.create_test_block([tx]), False]]) # Advance one block to 582 test_blocks = self.generate_blocks(1, 1234) - yield TestInstance(test_blocks, sync_every_block=False) # 30 + yield TestInstance(test_blocks, sync_every_block=False) # All BIP 68 txs should pass bip68success_txs.extend(bip68heighttxs) - yield TestInstance([[self.create_test_block(bip68success_txs), True]]) # 31 + yield TestInstance([[self.create_test_block(bip68success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - ### BIP 112 ### ### Version 1 txs ### # -1 OP_CSV tx should fail - yield TestInstance([[self.create_test_block([bip112tx_special_v1]), False]]) #32 + yield TestInstance([[self.create_test_block([bip112tx_special_v1]), False]]) # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass success_txs = [] for b25 in range(2): @@ -445,7 +452,7 @@ def get_tests(self): for b18 in range(2): success_txs.append(bip112txs_vary_OP_CSV_v1[1][b25][b22][b18]) success_txs.append(bip112txs_vary_OP_CSV_9_v1[1][b25][b22][b18]) - yield TestInstance([[self.create_test_block(success_txs), True]]) # 33 + yield TestInstance([[self.create_test_block(success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) # If SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV, version 1 txs should now fail @@ -459,60 +466,61 @@ def get_tests(self): fail_txs.append(bip112txs_vary_OP_CSV_9_v1[0][b25][b22][b18]) for tx in fail_txs: - yield TestInstance([[self.create_test_block([tx]), False]]) # 34 - 81 + yield TestInstance([[self.create_test_block([tx]), False]]) ### Version 2 txs ### # -1 OP_CSV tx should fail - yield TestInstance([[self.create_test_block([bip112tx_special_v2]), False]]) #82 + yield TestInstance([[self.create_test_block([bip112tx_special_v2]), False]]) # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 2 txs should pass (all sequence locks are met) success_txs = [] for b25 in range(2): for b22 in range(2): for b18 in range(2): - success_txs.append(bip112txs_vary_OP_CSV_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV - success_txs.append(bip112txs_vary_OP_CSV_9_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV_9 + success_txs.append(bip112txs_vary_OP_CSV_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV + success_txs.append(bip112txs_vary_OP_CSV_9_v2[1][b25][b22][b18]) # 8/16 of vary_OP_CSV_9 - yield TestInstance([[self.create_test_block(success_txs), True]]) # 83 + yield TestInstance([[self.create_test_block(success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - ## SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV for all remaining txs ## + # SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV for all remaining txs ## + # All txs with nSequence 9 should fail either due to earlier mismatch or failing the CSV check fail_txs = [] - fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) # 16/16 of vary_nSequence_9 + fail_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2)) # 16/16 of vary_nSequence_9 for b25 in range(2): for b22 in range(2): for b18 in range(2): - fail_txs.append(bip112txs_vary_OP_CSV_9_v2[0][b25][b22][b18]) # 16/16 of vary_OP_CSV_9 + fail_txs.append(bip112txs_vary_OP_CSV_9_v2[0][b25][b22][b18]) # 16/16 of vary_OP_CSV_9 for tx in fail_txs: - yield TestInstance([[self.create_test_block([tx]), False]]) # 84 - 107 + yield TestInstance([[self.create_test_block([tx]), False]]) # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in nSequence, tx should fail fail_txs = [] for b25 in range(2): for b22 in range(2): for b18 in range(2): - fail_txs.append(bip112txs_vary_nSequence_v2[1][b25][b22][b18]) # 8/16 of vary_nSequence + fail_txs.append(bip112txs_vary_nSequence_v2[1][b25][b22][b18]) # 8/16 of vary_nSequence for tx in fail_txs: - yield TestInstance([[self.create_test_block([tx]), False]]) # 108-115 + yield TestInstance([[self.create_test_block([tx]), False]]) # If sequencelock types mismatch, tx should fail fail_txs = [] for b25 in range(2): for b18 in range(2): - fail_txs.append(bip112txs_vary_nSequence_v2[0][b25][1][b18]) # 12/16 of vary_nSequence - fail_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][1][b18]) # 12/16 of vary_OP_CSV + fail_txs.append(bip112txs_vary_nSequence_v2[0][b25][1][b18]) # 12/16 of vary_nSequence + fail_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][1][b18]) # 12/16 of vary_OP_CSV for tx in fail_txs: - yield TestInstance([[self.create_test_block([tx]), False]]) # 116-123 + yield TestInstance([[self.create_test_block([tx]), False]]) # Remaining txs should pass, just test masking works properly success_txs = [] for b25 in range(2): for b18 in range(2): - success_txs.append(bip112txs_vary_nSequence_v2[0][b25][0][b18]) # 16/16 of vary_nSequence - success_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][0][b18]) # 16/16 of vary_OP_CSV - yield TestInstance([[self.create_test_block(success_txs), True]]) # 124 + success_txs.append(bip112txs_vary_nSequence_v2[0][b25][0][b18]) # 16/16 of vary_nSequence + success_txs.append(bip112txs_vary_OP_CSV_v2[0][b25][0][b18]) # 16/16 of vary_OP_CSV + yield TestInstance([[self.create_test_block(success_txs), True]]) # 124 self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) # Additional test, of checking that comparison of two time types works properly @@ -523,12 +531,10 @@ def get_tests(self): tx.vin[0].nSequence = base_relative_locktime | seq_type_flag signtx = self.sign_transaction(self.nodes[0], tx) time_txs.append(signtx) - yield TestInstance([[self.create_test_block(time_txs), True]]) # 125 + yield TestInstance([[self.create_test_block(time_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - ### Missing aspects of test - ## Testing empty stack fails - + # TODO: Test empty stack fails if __name__ == '__main__': BIP68_112_113Test().main() From 2e511d54243e360c013079bc8f676934ef450ae3 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 29 Nov 2017 17:38:51 -0500 Subject: [PATCH 029/900] [tests] improve logging in feature_csv_activation.py --- test/functional/feature_csv_activation.py | 63 ++++++++++++++--------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 0b353e78b..359161708 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -209,6 +209,7 @@ def create_bip112txs(self, bip112inputs, varyOP_CSV, txversion, locktime_delta=0 return txs def get_tests(self): + self.log.info("Generate blocks in the past for coinbase outputs.") long_past_time = int(time.time()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future self.nodes[0].setmocktime(long_past_time - 100) # enough so that the generated blocks will still all be before long_past_time self.coinbase_blocks = self.nodes[0].generate(1 + 16 + 2 * 32 + 1) # 82 blocks generated for inputs @@ -218,22 +219,27 @@ def get_tests(self): self.tip = int(self.nodes[0].getbestblockhash(), 16) self.nodeaddress = self.nodes[0].getnewaddress() + self.log.info("Test that the csv softfork is DEFINED") assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined') test_blocks = self.generate_blocks(61, 4) yield TestInstance(test_blocks, sync_every_block=False) - # Advanced from DEFINED to STARTED, height = 143 + + self.log.info("Advance from DEFINED to STARTED, height = 143") assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') - # Fail to achieve LOCKED_IN 100 out of 144 signal bit 0 - # using a variety of bits to simulate multiple parallel softforks + self.log.info("Fail to achieve LOCKED_IN") + # 100 out of 144 signal bit 0. Use a variety of bits to simulate multiple parallel softforks + test_blocks = self.generate_blocks(50, 536870913) # 0x20000001 (signalling ready) test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not) test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not) yield TestInstance(test_blocks, sync_every_block=False) - # Failed to advance past STARTED, height = 287 + + self.log.info("Failed to advance past STARTED, height = 287") assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') + self.log.info("Generate blocks to achieve LOCK-IN") # 108 out of 144 signal bit 0 to achieve lock-in # using a variety of bits to simulate multiple parallel softforks test_blocks = self.generate_blocks(58, 536870913) # 0x20000001 (signalling ready) @@ -241,10 +247,11 @@ def get_tests(self): test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready) test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not) yield TestInstance(test_blocks, sync_every_block=False) - # Advanced from STARTED to LOCKED_IN, height = 431 + + self.log.info("Advanced from STARTED to LOCKED_IN, height = 431") assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') - # 140 more version 4 blocks + # Generate 140 more version 4 blocks test_blocks = self.generate_blocks(140, 4) yield TestInstance(test_blocks, sync_every_block=False) @@ -256,6 +263,7 @@ def get_tests(self): bip68inputs = [] for i in range(16): bip68inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) + # 2 sets of 16 inputs with 10 OP_CSV OP_DROP (actually will be prepended to spending scriptSig) bip112basicinputs = [] for j in range(2): @@ -263,6 +271,7 @@ def get_tests(self): for i in range(16): inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) bip112basicinputs.append(inputs) + # 2 sets of 16 varied inputs with (relative_lock_time) OP_CSV OP_DROP (actually will be prepended to spending scriptSig) bip112diverseinputs = [] for j in range(2): @@ -270,8 +279,10 @@ def get_tests(self): for i in range(16): inputs.append(self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks)) bip112diverseinputs.append(inputs) + # 1 special input with -1 OP_CSV OP_DROP (actually will be prepended to spending scriptSig) bip112specialinput = self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks) + # 1 normal input bip113input = self.send_generic_input_tx(self.nodes[0], self.coinbase_blocks) @@ -286,7 +297,8 @@ def get_tests(self): # 2 more version 4 blocks test_blocks = self.generate_blocks(2, 4) yield TestInstance(test_blocks, sync_every_block=False) - # Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575) + + self.log.info("Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575)") assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') # Test both version 1 and version 2 transactions for all tests @@ -319,13 +331,11 @@ def get_tests(self): bip112tx_special_v1 = self.create_bip112special(bip112specialinput, 1) bip112tx_special_v2 = self.create_bip112special(bip112specialinput, 2) + self.log.info("TESTING") + + self.log.info("Pre-Soft Fork Tests. All txs should pass.") + self.log.info("Test version 1 txs") - ### TESTING ### - ################################## - ### Before Soft Forks Activate ### - ################################## - # All txs should pass - ### Version 1 txs ### success_txs = [] # add BIP113 tx and -1 CSV tx bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block @@ -343,7 +353,8 @@ def get_tests(self): yield TestInstance([[self.create_test_block(success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - ### Version 2 txs ### + self.log.info("Test version 2 txs") + success_txs = [] # add BIP113 tx and -1 CSV tx bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block @@ -366,10 +377,9 @@ def get_tests(self): yield TestInstance(test_blocks, sync_every_block=False) assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active') - ################################# - ### After Soft Forks Activate ### - ################################# - ### BIP 113 ### + self.log.info("Post-Soft Fork Tests.") + + self.log.info("BIP 113 tests") # BIP 113 tests should now fail regardless of version number if nLockTime isn't satisfied by new rules bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block bip113signed1 = self.sign_transaction(self.nodes[0], bip113tx_v1) @@ -390,15 +400,16 @@ def get_tests(self): test_blocks = self.generate_blocks(4, 1234) yield TestInstance(test_blocks, sync_every_block=False) - ### BIP 68 ### - ### Version 1 txs ### - # All still pass + self.log.info("BIP 68 tests") + self.log.info("Test version 1 txs - all should still pass") + success_txs = [] success_txs.extend(all_rlt_txs(bip68txs_v1)) yield TestInstance([[self.create_test_block(success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - ### Version 2 txs ### + self.log.info("Test version 2 txs") + bip68success_txs = [] # All txs with SEQUENCE_LOCKTIME_DISABLE_FLAG set pass for b25 in range(2): @@ -441,8 +452,9 @@ def get_tests(self): yield TestInstance([[self.create_test_block(bip68success_txs), True]]) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - ### BIP 112 ### - ### Version 1 txs ### + self.log.info("BIP 112 tests") + self.log.info("Test version 1 txs") + # -1 OP_CSV tx should fail yield TestInstance([[self.create_test_block([bip112tx_special_v1]), False]]) # If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass @@ -468,7 +480,8 @@ def get_tests(self): for tx in fail_txs: yield TestInstance([[self.create_test_block([tx]), False]]) - ### Version 2 txs ### + self.log.info("Version 2 txs") + # -1 OP_CSV tx should fail yield TestInstance([[self.create_test_block([bip112tx_special_v2]), False]]) From d843db7733135e2a93eaff21a03d9a025fceabd6 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 19 Mar 2018 12:13:08 +0700 Subject: [PATCH 030/900] Qt: remove "new" button during receive-mode in addressbook --- src/qt/addressbookpage.cpp | 11 +++++++---- src/qt/editaddressdialog.cpp | 7 +------ src/qt/editaddressdialog.h | 1 - 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 78dc9f81d..f2ddbf259 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -104,10 +104,12 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, case SendingTab: ui->labelExplanation->setText(tr("These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.")); ui->deleteAddress->setVisible(true); + ui->newAddress->setVisible(true); break; case ReceivingTab: ui->labelExplanation->setText(tr("These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.")); ui->deleteAddress->setVisible(false); + ui->newAddress->setVisible(false); break; } @@ -211,10 +213,11 @@ void AddressBookPage::on_newAddress_clicked() if(!model) return; - EditAddressDialog dlg( - tab == SendingTab ? - EditAddressDialog::NewSendingAddress : - EditAddressDialog::NewReceivingAddress, this); + if (tab == ReceivingTab) { + return; + } + + EditAddressDialog dlg(EditAddressDialog::NewSendingAddress, this); dlg.setModel(model); if(dlg.exec()) { diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index a945fc6aa..b7f66b887 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -26,10 +26,6 @@ EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) : switch(mode) { - case NewReceivingAddress: - setWindowTitle(tr("New receiving address")); - ui->addressEdit->setEnabled(false); - break; case NewSendingAddress: setWindowTitle(tr("New sending address")); break; @@ -74,10 +70,9 @@ bool EditAddressDialog::saveCurrentRow() switch(mode) { - case NewReceivingAddress: case NewSendingAddress: address = model->addRow( - mode == NewSendingAddress ? AddressTableModel::Send : AddressTableModel::Receive, + AddressTableModel::Send, ui->labelEdit->text(), ui->addressEdit->text(), g_address_type); diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index ddb67ece7..41c5d1708 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -25,7 +25,6 @@ class EditAddressDialog : public QDialog public: enum Mode { - NewReceivingAddress, NewSendingAddress, EditReceivingAddress, EditSendingAddress From 7b4a296a71d1b7f2555f5f63512ec964671464c0 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sun, 18 Mar 2018 20:43:21 +0100 Subject: [PATCH 031/900] tests: Add note about test suite naming convention --- doc/developer-notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/developer-notes.md b/doc/developer-notes.md index a5468c3be..2724fe194 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -34,6 +34,8 @@ code. - Constant names are all uppercase, and use `_` to separate words. - Class names, function names and method names are UpperCamelCase (PascalCase). Do not prefix class names with `C`. + - Test suite naming convention: The Boost test suite in file + `src/test/foo_tests.cpp` should be named `foo_tests`. - **Miscellaneous** - `++i` is preferred over `i++`. From 5fd864fe8a3b7c6abcfec97980ccc8f57ffdd8ca Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sun, 18 Mar 2018 18:52:30 +0100 Subject: [PATCH 032/900] tests: Rename test suits not following the test suite naming convention The name of the fixture test suite in `src/test/foo_tests.cpp` should be `foo_tests`. --- src/test/blockchain_tests.cpp | 2 +- src/test/prevector_tests.cpp | 2 +- src/wallet/crypter.h | 4 ++-- src/wallet/test/coinselector_tests.cpp | 2 +- src/wallet/test/crypto_tests.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp index 55fdd2c07..32b408838 100644 --- a/src/test/blockchain_tests.cpp +++ b/src/test/blockchain_tests.cpp @@ -54,7 +54,7 @@ void TestDifficulty(uint32_t nbits, double expected_difficulty) RejectDifficultyMismatch(difficulty, expected_difficulty); } -BOOST_FIXTURE_TEST_SUITE(blockchain_difficulty_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(blockchain_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(get_difficulty_for_very_low_target) { diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index 01c3a6ced..fe6f10d84 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -13,7 +13,7 @@ #include -BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(prevector_tests, TestingSetup) template class prevector_tester { diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index f3ae7144b..fdeb4cfee 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -67,7 +67,7 @@ class CMasterKey typedef std::vector > CKeyingMaterial; -namespace wallet_crypto +namespace crypto_tests { class TestCrypter; } @@ -75,7 +75,7 @@ namespace wallet_crypto /** Encryption/decryption context with key information */ class CCrypter { -friend class wallet_crypto::TestCrypter; // for test access to chKey/chIV +friend class crypto_tests::TestCrypter; // for test access to chKey/chIV private: std::vector> vchKey; std::vector> vchIV; diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index f05c81cd4..df47bc0bc 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -13,7 +13,7 @@ #include #include -BOOST_FIXTURE_TEST_SUITE(coin_selection_tests, WalletTestingSetup) +BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup) // how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles #define RUN_TESTS 100 diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp index 89b2c4e79..d8c0cdf0f 100644 --- a/src/wallet/test/crypto_tests.cpp +++ b/src/wallet/test/crypto_tests.cpp @@ -10,7 +10,7 @@ #include -BOOST_FIXTURE_TEST_SUITE(wallet_crypto, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup) class TestCrypter { From db983beba6fec910722bacc0d67c7ae98ba566fa Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sun, 18 Mar 2018 19:17:34 +0100 Subject: [PATCH 033/900] tests: Add lint-tests.sh which checks the test suite naming convention --- contrib/devtools/lint-tests.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100755 contrib/devtools/lint-tests.sh diff --git a/contrib/devtools/lint-tests.sh b/contrib/devtools/lint-tests.sh new file mode 100755 index 000000000..dd1a3ebdc --- /dev/null +++ b/contrib/devtools/lint-tests.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# +# 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. +# +# Check the test suite naming convention + +NAMING_INCONSISTENCIES=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\(' -- \ + "src/test/**.cpp" "src/wallet/test/**.cpp" | \ + grep -vE '/(.*?)\.cpp:BOOST_FIXTURE_TEST_SUITE\(\1, .*\)$') +if [[ ${NAMING_INCONSISTENCIES} != "" ]]; then + echo "The test suite in file src/test/foo_tests.cpp should be named" + echo "\"foo_tests\". Please make sure the following test suites follow" + echo "that convention:" + echo + echo "${NAMING_INCONSISTENCIES}" + exit 1 +fi From 5cd01d235a6a8fb86ae693cded78b5535cdc94b3 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 22 Nov 2017 12:57:58 -0500 Subject: [PATCH 034/900] [tests] Fix flake8 warnings in feature_block.py --- test/functional/feature_block.py | 209 ++++++++++++++++--------------- 1 file changed, 109 insertions(+), 100 deletions(-) diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index fe9bbda14..59c336e11 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -2,15 +2,48 @@ # Copyright (c) 2015-2017 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 block processing. - -This reimplements tests from the bitcoinj/FullBlockTestGenerator used -by the pull-tester. - -We use the testing framework in which we expect a particular answer from -each test. -""" +"""Test block processing.""" +import copy +import struct +import time +from test_framework.blocktools import create_block, create_coinbase, create_transaction, get_legacy_sigopcount_block +from test_framework.comptool import RejectResult, TestInstance, TestManager +from test_framework.key import CECKey +from test_framework.messages import ( + CBlock, + CBlockHeader, + COIN, + COutPoint, + CTransaction, + CTxIn, + CTxOut, + MAX_BLOCK_BASE_SIZE, + uint256_from_compact, + uint256_from_str, +) +from test_framework.mininode import network_thread_start +from test_framework.script import ( + CScript, + MAX_SCRIPT_ELEMENT_SIZE, + OP_2DUP, + OP_CHECKMULTISIG, + OP_CHECKMULTISIGVERIFY, + OP_CHECKSIG, + OP_CHECKSIGVERIFY, + OP_ELSE, + OP_ENDIF, + OP_EQUAL, + OP_FALSE, + OP_HASH160, + OP_IF, + OP_INVALIDOPCODE, + OP_RETURN, + OP_TRUE, + SIGHASH_ALL, + SignatureHash, + hash160, +) from test_framework.test_framework import ComparisonTestFramework from test_framework.util import * from test_framework.comptool import TestManager, TestInstance, RejectResult @@ -18,11 +51,10 @@ import time from test_framework.key import CECKey from test_framework.script import * -from test_framework.mininode import network_thread_start import struct class PreviousSpendableOutput(): - def __init__(self, tx = CTransaction(), n = -1): + def __init__(self, tx=CTransaction(), n=-1): self.tx = tx self.n = n # the output we're spending @@ -76,7 +108,7 @@ def run_test(self): self.test.run() def add_transactions_to_block(self, block, tx_list): - [ tx.rehash() for tx in tx_list ] + [tx.rehash() for tx in tx_list] block.vtx.extend(tx_list) # this is a little handier to use than the version in blocktools.py @@ -101,9 +133,9 @@ def create_and_sign_transaction(self, spend_tx, n, value, script=CScript([OP_TRU return tx def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True): - if self.tip == None: + if self.tip is None: base_block_hash = self.genesis_hash - block_time = int(time.time())+1 + block_time = int(time.time()) + 1 else: base_block_hash = self.tip.sha256 block_time = self.tip.nTime + 1 @@ -112,10 +144,10 @@ def next_block(self, number, spend=None, additional_coinbase_value=0, script=CSc coinbase = create_coinbase(height, self.coinbase_pubkey) coinbase.vout[0].nValue += additional_coinbase_value coinbase.rehash() - if spend == None: + if spend is None: block = create_block(base_block_hash, coinbase, block_time) else: - coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 # all but one satoshi to fees + coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 # all but one satoshi to fees coinbase.rehash() block = create_block(base_block_hash, coinbase, block_time) tx = create_transaction(spend.tx, spend.n, b"", 1, script) # spend 1 satoshi @@ -148,7 +180,7 @@ def accepted(): return TestInstance([[self.tip, True]]) # returns a test case that asserts that the current tip was rejected - def rejected(reject = None): + def rejected(reject=None): if reject is None: return TestInstance([[self.tip, False]]) else: @@ -181,14 +213,12 @@ def update_block(block_number, new_transactions): # these must be updated if consensus changes MAX_BLOCK_SIGOPS = 20000 - # Create a new block block(0) save_spendable_output() yield accepted() - - # Now we need that block to mature so we can spend the coinbase. + # Now we need that block to mature so we can spend the coinbase. test = TestInstance(sync_every_block=False) for i in range(99): block(5000 + i) @@ -223,7 +253,6 @@ def update_block(block_number, new_transactions): txout_b3 = PreviousSpendableOutput(b3.vtx[1], 0) yield rejected() - # Now we add another block to make the alternative chain longer. # # genesis -> b1 (0) -> b2 (1) @@ -231,7 +260,6 @@ def update_block(block_number, new_transactions): block(4, spend=out[2]) yield accepted() - # ... and back to the first chain. # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b3 (1) -> b4 (2) @@ -273,7 +301,6 @@ def update_block(block_number, new_transactions): block(11, spend=out[4], additional_coinbase_value=1) yield rejected(RejectResult(16, b'bad-cb-amount')) - # Try again, but with a valid fork first # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b14 (5) @@ -293,7 +320,7 @@ def update_block(block_number, new_transactions): block(14, spend=out[5], additional_coinbase_value=1) yield rejected() - yield TestInstance([[b12, True, b13.sha256]]) # New tip should be b13. + yield TestInstance([[b12, True, b13.sha256]]) # New tip should be b13. # Add a block with MAX_BLOCK_SIGOPS and one with one more sigop # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) @@ -307,13 +334,11 @@ def update_block(block_number, new_transactions): yield accepted() save_spendable_output() - # Test that a block with too many checksigs is rejected too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS)) block(16, spend=out[6], script=too_many_checksigs) yield rejected(RejectResult(16, b'bad-blk-sigops')) - # Attempt to spend a transaction created on a different fork # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1]) @@ -376,10 +401,10 @@ def update_block(block_number, new_transactions): tip(15) b24 = block(24, spend=out[6]) script_length = MAX_BLOCK_BASE_SIZE - len(b24.serialize()) - 69 - script_output = CScript([b'\x00' * (script_length+1)]) + script_output = CScript([b'\x00' * (script_length + 1)]) tx.vout = [CTxOut(0, script_output)] b24 = update_block(24, [tx]) - assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE+1) + assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1) yield rejected(RejectResult(16, b'bad-blk-length')) block(25, spend=out[7]) @@ -433,7 +458,7 @@ def update_block(block_number, new_transactions): # # MULTISIG: each op code counts as 20 sigops. To create the edge case, pack another 19 sigops at the end. - lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS-1) // 20) + [OP_CHECKSIG] * 19) + lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19) b31 = block(31, spend=out[8], script=lots_of_multisigs) assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS) yield accepted() @@ -445,10 +470,9 @@ def update_block(block_number, new_transactions): assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1) yield rejected(RejectResult(16, b'bad-blk-sigops')) - # CHECKMULTISIGVERIFY tip(31) - lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS-1) // 20) + [OP_CHECKSIG] * 19) + lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19) block(33, spend=out[9], script=lots_of_multisigs) yield accepted() save_spendable_output() @@ -457,7 +481,6 @@ def update_block(block_number, new_transactions): block(34, spend=out[10], script=too_many_multisigs) yield rejected(RejectResult(16, b'bad-blk-sigops')) - # CHECKSIGVERIFY tip(33) lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS - 1)) @@ -469,7 +492,6 @@ def update_block(block_number, new_transactions): block(36, spend=out[11], script=too_many_checksigs) yield rejected(RejectResult(16, b'bad-blk-sigops')) - # Check spending of a transaction in a block which failed to connect # # b6 (3) @@ -508,7 +530,7 @@ def update_block(block_number, new_transactions): b39_sigops_per_output = 6 # Build the redeem script, hash it, use hash to create the p2sh script - redeem_script = CScript([self.coinbase_pubkey] + [OP_2DUP, OP_CHECKSIGVERIFY]*5 + [OP_CHECKSIG]) + redeem_script = CScript([self.coinbase_pubkey] + [OP_2DUP, OP_CHECKSIGVERIFY] * 5 + [OP_CHECKSIG]) redeem_script_hash = hash160(redeem_script) p2sh_script = CScript([OP_HASH160, redeem_script_hash, OP_EQUAL]) @@ -525,7 +547,7 @@ def update_block(block_number, new_transactions): # Until block is full, add tx's with 1 satoshi to p2sh_script, the rest to OP_TRUE tx_new = None tx_last = tx - total_size=len(b39.serialize()) + total_size = len(b39.serialize()) while(total_size < MAX_BLOCK_BASE_SIZE): tx_new = create_tx(tx_last, 1, 1, p2sh_script) tx_new.vout.append(CTxOut(tx_last.vout[1].nValue - 1, CScript([OP_TRUE]))) @@ -533,7 +555,7 @@ def update_block(block_number, new_transactions): total_size += len(tx_new.serialize()) if total_size >= MAX_BLOCK_BASE_SIZE: break - b39.vtx.append(tx_new) # add tx to block + b39.vtx.append(tx_new) # add tx to block tx_last = tx_new b39_outputs += 1 @@ -541,7 +563,6 @@ def update_block(block_number, new_transactions): yield accepted() save_spendable_output() - # Test sigops in P2SH redeem scripts # # b40 creates 3333 tx's spending the 6-sigop P2SH outputs from b39 for a total of 19998 sigops. @@ -557,7 +578,7 @@ def update_block(block_number, new_transactions): lastOutpoint = COutPoint(b40.vtx[1].sha256, 0) new_txs = [] - for i in range(1, numTxes+1): + for i in range(1, numTxes + 1): tx = CTransaction() tx.vout.append(CTxOut(1, CScript([OP_TRUE]))) tx.vin.append(CTxIn(lastOutpoint, b'')) @@ -608,7 +629,6 @@ def update_block(block_number, new_transactions): yield accepted() save_spendable_output() - # Test a number of really invalid scenarios # # -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b44 (14) @@ -640,7 +660,7 @@ def update_block(block_number, new_transactions): b45.hashMerkleRoot = b45.calc_merkle_root() b45.calc_sha256() b45.solve() - self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256]+1 + self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1 self.tip = b45 self.blocks[45] = b45 yield rejected(RejectResult(16, b'bad-cb-missing')) @@ -648,24 +668,23 @@ def update_block(block_number, new_transactions): # A block with no txns tip(44) b46 = CBlock() - b46.nTime = b44.nTime+1 + b46.nTime = b44.nTime + 1 b46.hashPrevBlock = b44.sha256 b46.nBits = 0x207fffff b46.vtx = [] b46.hashMerkleRoot = 0 b46.solve() - self.block_heights[b46.sha256] = self.block_heights[b44.sha256]+1 + self.block_heights[b46.sha256] = self.block_heights[b44.sha256] + 1 self.tip = b46 assert 46 not in self.blocks self.blocks[46] = b46 - s = ser_uint256(b46.hashMerkleRoot) yield rejected(RejectResult(16, b'bad-blk-length')) # A block with invalid work tip(44) b47 = block(47, solve=False) target = uint256_from_compact(b47.nBits) - while b47.sha256 < target: #changed > to < + while b47.sha256 < target: # changed > to < b47.nNonce += 1 b47.rehash() yield rejected(RejectResult(16, b'high-hash')) @@ -693,9 +712,9 @@ def update_block(block_number, new_transactions): # A block with two coinbase txns tip(44) - b51 = block(51) + block(51) cb2 = create_coinbase(51, self.coinbase_pubkey) - b51 = update_block(51, [cb2]) + update_block(51, [cb2]) yield rejected(RejectResult(16, b'bad-cb-multiple')) # A block w/ duplicate txns @@ -712,7 +731,7 @@ def update_block(block_number, new_transactions): # tip(43) block(53, spend=out[14]) - yield rejected() # rejected since b44 is at same height + yield rejected() # rejected since b44 is at same height save_spendable_output() # invalid timestamp (b35 is 5 blocks back, so its time is MedianTimePast) @@ -729,7 +748,6 @@ def update_block(block_number, new_transactions): yield accepted() save_spendable_output() - # Test CVE-2012-2459 # # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57p2 (16) @@ -737,7 +755,7 @@ def update_block(block_number, new_transactions): # \-> b56p2 (16) # \-> b56 (16) # - # Merkle tree malleability (CVE-2012-2459): repeating sequences of transactions in a block without + # Merkle tree malleability (CVE-2012-2459): repeating sequences of transactions in a block without # affecting the merkle root of a block, while still invalidating it. # See: src/consensus/merkle.h # @@ -768,7 +786,7 @@ def update_block(block_number, new_transactions): tip(55) b56 = copy.deepcopy(b57) self.blocks[56] = b56 - assert_equal(len(b56.vtx),3) + assert_equal(len(b56.vtx), 3) b56 = update_block(56, [tx1]) assert_equal(b56.hash, b57.hash) yield rejected(RejectResult(16, b'bad-txns-duplicate')) @@ -788,7 +806,7 @@ def update_block(block_number, new_transactions): b56p2 = copy.deepcopy(b57p2) self.blocks["b56p2"] = b56p2 assert_equal(b56p2.hash, b57p2.hash) - assert_equal(len(b56p2.vtx),6) + assert_equal(len(b56p2.vtx), 6) b56p2 = update_block("b56p2", [tx3, tx4]) yield rejected(RejectResult(16, b'bad-txns-duplicate')) @@ -796,7 +814,7 @@ def update_block(block_number, new_transactions): yield accepted() tip(57) - yield rejected() #rejected because 57p2 seen first + yield rejected() # rejected because 57p2 seen first save_spendable_output() # Test a few invalid tx types @@ -807,20 +825,20 @@ def update_block(block_number, new_transactions): # tx with prevout.n out of range tip(57) - b58 = block(58, spend=out[17]) + block(58, spend=out[17]) tx = CTransaction() assert(len(out[17].tx.vout) < 42) tx.vin.append(CTxIn(COutPoint(out[17].tx.sha256, 42), CScript([OP_TRUE]), 0xffffffff)) tx.vout.append(CTxOut(0, b"")) tx.calc_sha256() - b58 = update_block(58, [tx]) + update_block(58, [tx]) yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # tx with output value > input value out of range tip(57) - b59 = block(59) - tx = create_and_sign_tx(out[17].tx, out[17].n, 51*COIN) - b59 = update_block(59, [tx]) + block(59) + tx = create_and_sign_tx(out[17].tx, out[17].n, 51 * COIN) + update_block(59, [tx]) yield rejected(RejectResult(16, b'bad-txns-in-belowout')) # reset to good chain @@ -840,31 +858,29 @@ def update_block(block_number, new_transactions): # tip(60) b61 = block(61, spend=out[18]) - b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig #equalize the coinbases + b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig # equalize the coinbases b61.vtx[0].rehash() b61 = update_block(61, []) assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize()) yield rejected(RejectResult(16, b'bad-txns-BIP30')) - # Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests) # # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) # \-> b62 (18) # tip(60) - b62 = block(62) + block(62) tx = CTransaction() - tx.nLockTime = 0xffffffff #this locktime is non-final + tx.nLockTime = 0xffffffff # this locktime is non-final assert(out[18].n < len(out[18].tx.vout)) - tx.vin.append(CTxIn(COutPoint(out[18].tx.sha256, out[18].n))) # don't set nSequence + tx.vin.append(CTxIn(COutPoint(out[18].tx.sha256, out[18].n))) # don't set nSequence tx.vout.append(CTxOut(0, CScript([OP_TRUE]))) assert(tx.vin[0].nSequence < 0xffffffff) tx.calc_sha256() - b62 = update_block(62, [tx]) + update_block(62, [tx]) yield rejected(RejectResult(16, b'bad-txns-nonfinal')) - # Test a non-final coinbase is also rejected # # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) @@ -878,7 +894,6 @@ def update_block(block_number, new_transactions): b63 = update_block(63, []) yield rejected(RejectResult(16, b'bad-txns-nonfinal')) - # This checks that a block with a bloated VARINT between the block_header and the array of tx such that # the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint, # does not cause a subsequent, identical block with canonical encoding to be rejected. The test does not @@ -976,13 +991,13 @@ def update_block(block_number, new_transactions): # tip(65) block(68, additional_coinbase_value=10) - tx = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue-9) + tx = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 9) update_block(68, [tx]) yield rejected(RejectResult(16, b'bad-cb-amount')) tip(65) b69 = block(69, additional_coinbase_value=10) - tx = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue-10) + tx = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 10) update_block(69, [tx]) yield accepted() save_spendable_output() @@ -1002,7 +1017,6 @@ def update_block(block_number, new_transactions): update_block(70, [tx]) yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) - # Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks) # # -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21) @@ -1031,7 +1045,6 @@ def update_block(block_number, new_transactions): yield accepted() save_spendable_output() - # Test some invalid scripts and MAX_BLOCK_SIGOPS # # -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21) @@ -1053,17 +1066,17 @@ def update_block(block_number, new_transactions): b73 = block(73) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 1 a = bytearray([OP_CHECKSIG] * size) - a[MAX_BLOCK_SIGOPS - 1] = int("4e",16) # OP_PUSHDATA4 + a[MAX_BLOCK_SIGOPS - 1] = int("4e", 16) # OP_PUSHDATA4 element_size = MAX_SCRIPT_ELEMENT_SIZE + 1 a[MAX_BLOCK_SIGOPS] = element_size % 256 - a[MAX_BLOCK_SIGOPS+1] = element_size // 256 - a[MAX_BLOCK_SIGOPS+2] = 0 - a[MAX_BLOCK_SIGOPS+3] = 0 + a[MAX_BLOCK_SIGOPS + 1] = element_size // 256 + a[MAX_BLOCK_SIGOPS + 2] = 0 + a[MAX_BLOCK_SIGOPS + 3] = 0 tx = create_and_sign_tx(out[22].tx, 0, 1, CScript(a)) b73 = update_block(73, [tx]) - assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS+1) + assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1) yield rejected(RejectResult(16, b'bad-blk-sigops')) # b74/75 - if we push an invalid script element, all prevous sigops are counted, @@ -1079,40 +1092,40 @@ def update_block(block_number, new_transactions): # # tip(72) - b74 = block(74) - size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 # total = 20,561 + block(74) + size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 # total = 20,561 a = bytearray([OP_CHECKSIG] * size) a[MAX_BLOCK_SIGOPS] = 0x4e - a[MAX_BLOCK_SIGOPS+1] = 0xfe - a[MAX_BLOCK_SIGOPS+2] = 0xff - a[MAX_BLOCK_SIGOPS+3] = 0xff - a[MAX_BLOCK_SIGOPS+4] = 0xff + a[MAX_BLOCK_SIGOPS + 1] = 0xfe + a[MAX_BLOCK_SIGOPS + 2] = 0xff + a[MAX_BLOCK_SIGOPS + 3] = 0xff + a[MAX_BLOCK_SIGOPS + 4] = 0xff tx = create_and_sign_tx(out[22].tx, 0, 1, CScript(a)) - b74 = update_block(74, [tx]) + update_block(74, [tx]) yield rejected(RejectResult(16, b'bad-blk-sigops')) tip(72) - b75 = block(75) + block(75) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 a = bytearray([OP_CHECKSIG] * size) - a[MAX_BLOCK_SIGOPS-1] = 0x4e + a[MAX_BLOCK_SIGOPS - 1] = 0x4e a[MAX_BLOCK_SIGOPS] = 0xff - a[MAX_BLOCK_SIGOPS+1] = 0xff - a[MAX_BLOCK_SIGOPS+2] = 0xff - a[MAX_BLOCK_SIGOPS+3] = 0xff + a[MAX_BLOCK_SIGOPS + 1] = 0xff + a[MAX_BLOCK_SIGOPS + 2] = 0xff + a[MAX_BLOCK_SIGOPS + 3] = 0xff tx = create_and_sign_tx(out[22].tx, 0, 1, CScript(a)) - b75 = update_block(75, [tx]) + update_block(75, [tx]) yield accepted() save_spendable_output() # Check that if we push an element filled with CHECKSIGs, they are not counted tip(75) - b76 = block(76) + block(76) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 a = bytearray([OP_CHECKSIG] * size) - a[MAX_BLOCK_SIGOPS-1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs + a[MAX_BLOCK_SIGOPS - 1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs tx = create_and_sign_tx(out[23].tx, 0, 1, CScript(a)) - b76 = update_block(76, [tx]) + update_block(76, [tx]) yield accepted() save_spendable_output() @@ -1136,18 +1149,18 @@ def update_block(block_number, new_transactions): # tip(76) block(77) - tx77 = create_and_sign_tx(out[24].tx, out[24].n, 10*COIN) + tx77 = create_and_sign_tx(out[24].tx, out[24].n, 10 * COIN) update_block(77, [tx77]) yield accepted() save_spendable_output() block(78) - tx78 = create_tx(tx77, 0, 9*COIN) + tx78 = create_tx(tx77, 0, 9 * COIN) update_block(78, [tx78]) yield accepted() block(79) - tx79 = create_tx(tx78, 0, 8*COIN) + tx79 = create_tx(tx78, 0, 8 * COIN) update_block(79, [tx79]) yield accepted() @@ -1160,7 +1173,7 @@ def update_block(block_number, new_transactions): save_spendable_output() block(81, spend=out[26]) - yield rejected() # other chain is same length + yield rejected() # other chain is same length save_spendable_output() block(82, spend=out[27]) @@ -1173,7 +1186,6 @@ def update_block(block_number, new_transactions): assert(tx78.hash in mempool) assert(tx79.hash in mempool) - # Test invalid opcodes in dead execution paths. # # -> b81 (26) -> b82 (27) -> b83 (28) @@ -1191,7 +1203,6 @@ def update_block(block_number, new_transactions): yield accepted() save_spendable_output() - # Reorg on/off blocks that have OP_RETURN in them (and try to spend them) # # -> b81 (26) -> b82 (27) -> b83 (28) -> b84 (29) -> b87 (30) -> b88 (31) @@ -1215,7 +1226,7 @@ def update_block(block_number, new_transactions): tx4.vout.append(CTxOut(0, CScript([OP_RETURN]))) tx5 = create_tx(tx1, 4, 0, CScript([OP_RETURN])) - update_block(84, [tx1,tx2,tx3,tx4,tx5]) + update_block(84, [tx1, tx2, tx3, tx4, tx5]) yield accepted() save_spendable_output() @@ -1241,7 +1252,6 @@ def update_block(block_number, new_transactions): update_block("89a", [tx]) yield rejected() - # Test re-org of a week's worth of blocks (1088 blocks) # This test takes a minute or two and can be accomplished in memory # @@ -1249,7 +1259,7 @@ def update_block(block_number, new_transactions): tip(88) LARGE_REORG_SIZE = 1088 test1 = TestInstance(sync_every_block=False) - spend=out[32] + spend = out[32] for i in range(89, LARGE_REORG_SIZE + 89): b = block(i, spend) tx = CTransaction() @@ -1270,7 +1280,7 @@ def update_block(block_number, new_transactions): tip(88) test2 = TestInstance(sync_every_block=False) for i in range(89, LARGE_REORG_SIZE + 89): - block("alt"+str(i)) + block("alt" + str(i)) test2.blocks_and_transactions.append([self.tip, False]) yield test2 @@ -1288,6 +1298,5 @@ def update_block(block_number, new_transactions): chain1_tip += 2 - if __name__ == '__main__': FullBlockTest().main() From 3898c4f3d7afa0abf876831bf479c3b8f1514070 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 22 Nov 2017 13:47:03 -0500 Subject: [PATCH 035/900] [tests] Tidy up feature_block.py - move all helper methods to the end - remove block, create_tx and create_and_sign_tx shortcuts - remove --runbarelyexpensive option, since it defaults to True and it's unlikely that anyone ever runs the test with this option set to false. --- test/functional/feature_block.py | 1005 +++++++++++++++--------------- 1 file changed, 497 insertions(+), 508 deletions(-) diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 59c336e11..e026e85a3 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -53,6 +53,8 @@ from test_framework.script import * import struct +MAX_BLOCK_SIGOPS = 20000 + class PreviousSpendableOutput(): def __init__(self, tx=CTransaction(), n=-1): self.tx = tx @@ -97,150 +99,45 @@ def set_test_params(self): self.tip = None self.blocks = {} - def add_options(self, parser): - super().add_options(parser) - parser.add_option("--runbarelyexpensive", dest="runbarelyexpensive", default=True) - def run_test(self): self.test = TestManager(self, self.options.tmpdir) self.test.add_all_connections(self.nodes) network_thread_start() self.test.run() - def add_transactions_to_block(self, block, tx_list): - [tx.rehash() for tx in tx_list] - block.vtx.extend(tx_list) - - # this is a little handier to use than the version in blocktools.py - def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE])): - tx = create_transaction(spend_tx, n, b"", value, script) - return tx - - # sign a transaction, using the key we know about - # this signs input 0 in tx, which is assumed to be spending output n in spend_tx - def sign_tx(self, tx, spend_tx, n): - scriptPubKey = bytearray(spend_tx.vout[n].scriptPubKey) - if (scriptPubKey[0] == OP_TRUE): # an anyone-can-spend - tx.vin[0].scriptSig = CScript() - return - (sighash, err) = SignatureHash(spend_tx.vout[n].scriptPubKey, tx, 0, SIGHASH_ALL) - tx.vin[0].scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))]) - - def create_and_sign_transaction(self, spend_tx, n, value, script=CScript([OP_TRUE])): - tx = self.create_tx(spend_tx, n, value, script) - self.sign_tx(tx, spend_tx, n) - tx.rehash() - return tx - - def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True): - if self.tip is None: - base_block_hash = self.genesis_hash - block_time = int(time.time()) + 1 - else: - base_block_hash = self.tip.sha256 - block_time = self.tip.nTime + 1 - # First create the coinbase - height = self.block_heights[base_block_hash] + 1 - coinbase = create_coinbase(height, self.coinbase_pubkey) - coinbase.vout[0].nValue += additional_coinbase_value - coinbase.rehash() - if spend is None: - block = create_block(base_block_hash, coinbase, block_time) - else: - coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 # all but one satoshi to fees - coinbase.rehash() - block = create_block(base_block_hash, coinbase, block_time) - tx = create_transaction(spend.tx, spend.n, b"", 1, script) # spend 1 satoshi - self.sign_tx(tx, spend.tx, spend.n) - self.add_transactions_to_block(block, [tx]) - block.hashMerkleRoot = block.calc_merkle_root() - if solve: - block.solve() - self.tip = block - self.block_heights[block.sha256] = height - assert number not in self.blocks - self.blocks[number] = block - return block - def get_tests(self): self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16) self.block_heights[self.genesis_hash] = 0 - spendable_outputs = [] - - # save the current tip so it can be spent by a later block - def save_spendable_output(): - spendable_outputs.append(self.tip) - - # get an output that we previously marked as spendable - def get_spendable_output(): - return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0) - - # returns a test case that asserts that the current tip was accepted - def accepted(): - return TestInstance([[self.tip, True]]) - - # returns a test case that asserts that the current tip was rejected - def rejected(reject=None): - if reject is None: - return TestInstance([[self.tip, False]]) - else: - return TestInstance([[self.tip, reject]]) - - # move the tip back to a previous block - def tip(number): - self.tip = self.blocks[number] - - # adds transactions to the block and updates state - def update_block(block_number, new_transactions): - block = self.blocks[block_number] - self.add_transactions_to_block(block, new_transactions) - old_sha256 = block.sha256 - block.hashMerkleRoot = block.calc_merkle_root() - block.solve() - # Update the internal state just like in next_block - self.tip = block - if block.sha256 != old_sha256: - self.block_heights[block.sha256] = self.block_heights[old_sha256] - del self.block_heights[old_sha256] - self.blocks[block_number] = block - return block - - # shorthand for functions - block = self.next_block - create_tx = self.create_tx - create_and_sign_tx = self.create_and_sign_transaction - - # these must be updated if consensus changes - MAX_BLOCK_SIGOPS = 20000 + self.spendable_outputs = [] # Create a new block - block(0) - save_spendable_output() - yield accepted() + self.next_block(0) + self.save_spendable_output() + yield self.accepted() # Now we need that block to mature so we can spend the coinbase. test = TestInstance(sync_every_block=False) for i in range(99): - block(5000 + i) + self.next_block(5000 + i) test.blocks_and_transactions.append([self.tip, True]) - save_spendable_output() + self.save_spendable_output() yield test # collect spendable outputs now to avoid cluttering the code later on out = [] for i in range(33): - out.append(get_spendable_output()) + out.append(self.get_spendable_output()) # Start by building a couple of blocks on top (which output is spent is # in parentheses): # genesis -> b1 (0) -> b2 (1) - block(1, spend=out[0]) - save_spendable_output() - yield accepted() + self.next_block(1, spend=out[0]) + self.save_spendable_output() + yield self.accepted() - block(2, spend=out[1]) - yield accepted() - save_spendable_output() + self.next_block(2, spend=out[1]) + yield self.accepted() + self.save_spendable_output() # so fork like this: # @@ -248,77 +145,77 @@ def update_block(block_number, new_transactions): # \-> b3 (1) # # Nothing should happen at this point. We saw b2 first so it takes priority. - tip(1) - b3 = block(3, spend=out[1]) + self.move_tip(1) + b3 = self.next_block(3, spend=out[1]) txout_b3 = PreviousSpendableOutput(b3.vtx[1], 0) - yield rejected() + yield self.rejected() # Now we add another block to make the alternative chain longer. # # genesis -> b1 (0) -> b2 (1) # \-> b3 (1) -> b4 (2) - block(4, spend=out[2]) - yield accepted() + self.next_block(4, spend=out[2]) + yield self.accepted() # ... and back to the first chain. # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b3 (1) -> b4 (2) - tip(2) - block(5, spend=out[2]) - save_spendable_output() - yield rejected() + self.move_tip(2) + self.next_block(5, spend=out[2]) + self.save_spendable_output() + yield self.rejected() - block(6, spend=out[3]) - yield accepted() + self.next_block(6, spend=out[3]) + yield self.accepted() # Try to create a fork that double-spends # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b7 (2) -> b8 (4) # \-> b3 (1) -> b4 (2) - tip(5) - block(7, spend=out[2]) - yield rejected() + self.move_tip(5) + self.next_block(7, spend=out[2]) + yield self.rejected() - block(8, spend=out[4]) - yield rejected() + self.next_block(8, spend=out[4]) + yield self.rejected() # Try to create a block that has too much fee # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b9 (4) # \-> b3 (1) -> b4 (2) - tip(6) - block(9, spend=out[4], additional_coinbase_value=1) - yield rejected(RejectResult(16, b'bad-cb-amount')) + self.move_tip(6) + self.next_block(9, spend=out[4], additional_coinbase_value=1) + yield self.rejected(RejectResult(16, b'bad-cb-amount')) # Create a fork that ends in a block with too much fee (the one that causes the reorg) # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b10 (3) -> b11 (4) # \-> b3 (1) -> b4 (2) - tip(5) - block(10, spend=out[3]) - yield rejected() + self.move_tip(5) + self.next_block(10, spend=out[3]) + yield self.rejected() - block(11, spend=out[4], additional_coinbase_value=1) - yield rejected(RejectResult(16, b'bad-cb-amount')) + self.next_block(11, spend=out[4], additional_coinbase_value=1) + yield self.rejected(RejectResult(16, b'bad-cb-amount')) # Try again, but with a valid fork first # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b14 (5) # (b12 added last) # \-> b3 (1) -> b4 (2) - tip(5) - b12 = block(12, spend=out[3]) - save_spendable_output() - b13 = block(13, spend=out[4]) + self.move_tip(5) + b12 = self.next_block(12, spend=out[3]) + self.save_spendable_output() + b13 = self.next_block(13, spend=out[4]) # Deliver the block header for b12, and the block b13. # b13 should be accepted but the tip won't advance until b12 is delivered. yield TestInstance([[CBlockHeader(b12), None], [b13, False]]) - save_spendable_output() + self.save_spendable_output() # b14 is invalid, but the node won't know that until it tries to connect # Tip still can't advance because b12 is missing - block(14, spend=out[5], additional_coinbase_value=1) - yield rejected() + self.next_block(14, spend=out[5], additional_coinbase_value=1) + yield self.rejected() yield TestInstance([[b12, True, b13.sha256]]) # New tip should be b13. @@ -329,125 +226,125 @@ def update_block(block_number, new_transactions): # Test that a block with a lot of checksigs is okay lots_of_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS - 1)) - tip(13) - block(15, spend=out[5], script=lots_of_checksigs) - yield accepted() - save_spendable_output() + self.move_tip(13) + self.next_block(15, spend=out[5], script=lots_of_checksigs) + yield self.accepted() + self.save_spendable_output() # Test that a block with too many checksigs is rejected too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS)) - block(16, spend=out[6], script=too_many_checksigs) - yield rejected(RejectResult(16, b'bad-blk-sigops')) + self.next_block(16, spend=out[6], script=too_many_checksigs) + yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # Attempt to spend a transaction created on a different fork # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1]) # \-> b3 (1) -> b4 (2) - tip(15) - block(17, spend=txout_b3) - yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + self.move_tip(15) + self.next_block(17, spend=txout_b3) + yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # Attempt to spend a transaction created on a different fork (on a fork this time) # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) # \-> b18 (b3.vtx[1]) -> b19 (6) # \-> b3 (1) -> b4 (2) - tip(13) - block(18, spend=txout_b3) - yield rejected() + self.move_tip(13) + self.next_block(18, spend=txout_b3) + yield self.rejected() - block(19, spend=out[6]) - yield rejected() + self.next_block(19, spend=out[6]) + yield self.rejected() # Attempt to spend a coinbase at depth too low # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7) # \-> b3 (1) -> b4 (2) - tip(15) - block(20, spend=out[7]) - yield rejected(RejectResult(16, b'bad-txns-premature-spend-of-coinbase')) + self.move_tip(15) + self.next_block(20, spend=out[7]) + yield self.rejected(RejectResult(16, b'bad-txns-premature-spend-of-coinbase')) # Attempt to spend a coinbase at depth too low (on a fork this time) # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) # \-> b21 (6) -> b22 (5) # \-> b3 (1) -> b4 (2) - tip(13) - block(21, spend=out[6]) - yield rejected() + self.move_tip(13) + self.next_block(21, spend=out[6]) + yield self.rejected() - block(22, spend=out[5]) - yield rejected() + self.next_block(22, spend=out[5]) + yield self.rejected() # Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) # \-> b24 (6) -> b25 (7) # \-> b3 (1) -> b4 (2) - tip(15) - b23 = block(23, spend=out[6]) + self.move_tip(15) + b23 = self.next_block(23, spend=out[6]) tx = CTransaction() script_length = MAX_BLOCK_BASE_SIZE - len(b23.serialize()) - 69 script_output = CScript([b'\x00' * script_length]) tx.vout.append(CTxOut(0, script_output)) tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 0))) - b23 = update_block(23, [tx]) + b23 = self.update_block(23, [tx]) # Make sure the math above worked out to produce a max-sized block assert_equal(len(b23.serialize()), MAX_BLOCK_BASE_SIZE) - yield accepted() - save_spendable_output() + yield self.accepted() + self.save_spendable_output() # Make the next block one byte bigger and check that it fails - tip(15) - b24 = block(24, spend=out[6]) + self.move_tip(15) + b24 = self.next_block(24, spend=out[6]) script_length = MAX_BLOCK_BASE_SIZE - len(b24.serialize()) - 69 script_output = CScript([b'\x00' * (script_length + 1)]) tx.vout = [CTxOut(0, script_output)] - b24 = update_block(24, [tx]) + b24 = self.update_block(24, [tx]) assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1) - yield rejected(RejectResult(16, b'bad-blk-length')) + yield self.rejected(RejectResult(16, b'bad-blk-length')) - block(25, spend=out[7]) - yield rejected() + self.next_block(25, spend=out[7]) + yield self.rejected() # Create blocks with a coinbase input script size out of range # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) # \-> ... (6) -> ... (7) # \-> b3 (1) -> b4 (2) - tip(15) - b26 = block(26, spend=out[6]) + self.move_tip(15) + b26 = self.next_block(26, spend=out[6]) b26.vtx[0].vin[0].scriptSig = b'\x00' b26.vtx[0].rehash() # update_block causes the merkle root to get updated, even with no new # transactions, and updates the required state. - b26 = update_block(26, []) - yield rejected(RejectResult(16, b'bad-cb-length')) + b26 = self.update_block(26, []) + yield self.rejected(RejectResult(16, b'bad-cb-length')) # Extend the b26 chain to make sure bitcoind isn't accepting b26 - block(27, spend=out[7]) - yield rejected(False) + self.next_block(27, spend=out[7]) + yield self.rejected(False) # Now try a too-large-coinbase script - tip(15) - b28 = block(28, spend=out[6]) + self.move_tip(15) + b28 = self.next_block(28, spend=out[6]) b28.vtx[0].vin[0].scriptSig = b'\x00' * 101 b28.vtx[0].rehash() - b28 = update_block(28, []) - yield rejected(RejectResult(16, b'bad-cb-length')) + b28 = self.update_block(28, []) + yield self.rejected(RejectResult(16, b'bad-cb-length')) # Extend the b28 chain to make sure bitcoind isn't accepting b28 - block(29, spend=out[7]) - yield rejected(False) + self.next_block(29, spend=out[7]) + yield self.rejected(False) # b30 has a max-sized coinbase scriptSig. - tip(23) - b30 = block(30) + self.move_tip(23) + b30 = self.next_block(30) b30.vtx[0].vin[0].scriptSig = b'\x00' * 100 b30.vtx[0].rehash() - b30 = update_block(30, []) - yield accepted() - save_spendable_output() + b30 = self.update_block(30, []) + yield self.accepted() + self.save_spendable_output() # b31 - b35 - check sigops of OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY / OP_CHECKSIGVERIFY # @@ -459,38 +356,38 @@ def update_block(block_number, new_transactions): # MULTISIG: each op code counts as 20 sigops. To create the edge case, pack another 19 sigops at the end. lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19) - b31 = block(31, spend=out[8], script=lots_of_multisigs) + b31 = self.next_block(31, spend=out[8], script=lots_of_multisigs) assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS) - yield accepted() - save_spendable_output() + yield self.accepted() + self.save_spendable_output() # this goes over the limit because the coinbase has one sigop too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20)) - b32 = block(32, spend=out[9], script=too_many_multisigs) + b32 = self.next_block(32, spend=out[9], script=too_many_multisigs) assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1) - yield rejected(RejectResult(16, b'bad-blk-sigops')) + yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # CHECKMULTISIGVERIFY - tip(31) + self.move_tip(31) lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19) - block(33, spend=out[9], script=lots_of_multisigs) - yield accepted() - save_spendable_output() + self.next_block(33, spend=out[9], script=lots_of_multisigs) + yield self.accepted() + self.save_spendable_output() too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20)) - block(34, spend=out[10], script=too_many_multisigs) - yield rejected(RejectResult(16, b'bad-blk-sigops')) + self.next_block(34, spend=out[10], script=too_many_multisigs) + yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # CHECKSIGVERIFY - tip(33) + self.move_tip(33) lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS - 1)) - b35 = block(35, spend=out[10], script=lots_of_checksigs) - yield accepted() - save_spendable_output() + b35 = self.next_block(35, spend=out[10], script=lots_of_checksigs) + yield self.accepted() + self.save_spendable_output() too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS)) - block(36, spend=out[11], script=too_many_checksigs) - yield rejected(RejectResult(16, b'bad-blk-sigops')) + self.next_block(36, spend=out[11], script=too_many_checksigs) + yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # Check spending of a transaction in a block which failed to connect # @@ -501,17 +398,17 @@ def update_block(block_number, new_transactions): # # save 37's spendable output, but then double-spend out11 to invalidate the block - tip(35) - b37 = block(37, spend=out[11]) + self.move_tip(35) + b37 = self.next_block(37, spend=out[11]) txout_b37 = PreviousSpendableOutput(b37.vtx[1], 0) - tx = create_and_sign_tx(out[11].tx, out[11].n, 0) - b37 = update_block(37, [tx]) - yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + tx = self.create_and_sign_transaction(out[11].tx, out[11].n, 0) + b37 = self.update_block(37, [tx]) + yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid - tip(35) - block(38, spend=txout_b37) - yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + self.move_tip(35) + self.next_block(38, spend=txout_b37) + yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # Check P2SH SigOp counting # @@ -524,8 +421,8 @@ def update_block(block_number, new_transactions): # redeem_script = COINBASE_PUBKEY, (OP_2DUP+OP_CHECKSIGVERIFY) * 5, OP_CHECKSIG # p2sh_script = OP_HASH160, ripemd160(sha256(script)), OP_EQUAL # - tip(35) - b39 = block(39) + self.move_tip(35) + b39 = self.next_block(39) b39_outputs = 0 b39_sigops_per_output = 6 @@ -537,11 +434,11 @@ def update_block(block_number, new_transactions): # Create a transaction that spends one satoshi to the p2sh_script, the rest to OP_TRUE # This must be signed because it is spending a coinbase spend = out[11] - tx = create_tx(spend.tx, spend.n, 1, p2sh_script) + tx = self.create_tx(spend.tx, spend.n, 1, p2sh_script) tx.vout.append(CTxOut(spend.tx.vout[spend.n].nValue - 1, CScript([OP_TRUE]))) self.sign_tx(tx, spend.tx, spend.n) tx.rehash() - b39 = update_block(39, [tx]) + b39 = self.update_block(39, [tx]) b39_outputs += 1 # Until block is full, add tx's with 1 satoshi to p2sh_script, the rest to OP_TRUE @@ -549,7 +446,7 @@ def update_block(block_number, new_transactions): tx_last = tx total_size = len(b39.serialize()) while(total_size < MAX_BLOCK_BASE_SIZE): - tx_new = create_tx(tx_last, 1, 1, p2sh_script) + tx_new = self.create_tx(tx_last, 1, 1, p2sh_script) tx_new.vout.append(CTxOut(tx_last.vout[1].nValue - 1, CScript([OP_TRUE]))) tx_new.rehash() total_size += len(tx_new.serialize()) @@ -559,9 +456,9 @@ def update_block(block_number, new_transactions): tx_last = tx_new b39_outputs += 1 - b39 = update_block(39, []) - yield accepted() - save_spendable_output() + b39 = self.update_block(39, []) + yield self.accepted() + self.save_spendable_output() # Test sigops in P2SH redeem scripts # @@ -570,8 +467,8 @@ def update_block(block_number, new_transactions): # # b41 does the same, less one, so it has the maximum sigops permitted. # - tip(39) - b40 = block(40, spend=out[12]) + self.move_tip(39) + b40 = self.next_block(40, spend=out[12]) sigops = get_legacy_sigopcount_block(b40) numTxes = (MAX_BLOCK_SIGOPS - sigops) // b39_sigops_per_output assert_equal(numTxes <= b39_outputs, True) @@ -600,34 +497,34 @@ def update_block(block_number, new_transactions): tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b40_sigops_to_fill))) tx.rehash() new_txs.append(tx) - update_block(40, new_txs) - yield rejected(RejectResult(16, b'bad-blk-sigops')) + self.update_block(40, new_txs) + yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # same as b40, but one less sigop - tip(39) - block(41, spend=None) - update_block(41, b40.vtx[1:-1]) + self.move_tip(39) + self.next_block(41, spend=None) + self.update_block(41, b40.vtx[1:-1]) b41_sigops_to_fill = b40_sigops_to_fill - 1 tx = CTransaction() tx.vin.append(CTxIn(lastOutpoint, b'')) tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b41_sigops_to_fill))) tx.rehash() - update_block(41, [tx]) - yield accepted() + self.update_block(41, [tx]) + yield self.accepted() # Fork off of b39 to create a constant base again # # b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) # \-> b41 (12) # - tip(39) - block(42, spend=out[12]) - yield rejected() - save_spendable_output() + self.move_tip(39) + self.next_block(42, spend=out[12]) + yield self.rejected() + self.save_spendable_output() - block(43, spend=out[13]) - yield accepted() - save_spendable_output() + self.next_block(43, spend=out[13]) + yield self.accepted() + self.save_spendable_output() # Test a number of really invalid scenarios # @@ -648,10 +545,10 @@ def update_block(block_number, new_transactions): self.tip = b44 self.block_heights[b44.sha256] = height self.blocks[44] = b44 - yield accepted() + yield self.accepted() # A block with a non-coinbase as the first tx - non_coinbase = create_tx(out[15].tx, out[15].n, 1) + non_coinbase = self.create_tx(out[15].tx, out[15].n, 1) b45 = CBlock() b45.nTime = self.tip.nTime + 1 b45.hashPrevBlock = self.tip.sha256 @@ -663,10 +560,10 @@ def update_block(block_number, new_transactions): self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1 self.tip = b45 self.blocks[45] = b45 - yield rejected(RejectResult(16, b'bad-cb-missing')) + yield self.rejected(RejectResult(16, b'bad-cb-missing')) # A block with no txns - tip(44) + self.move_tip(44) b46 = CBlock() b46.nTime = b44.nTime + 1 b46.hashPrevBlock = b44.sha256 @@ -678,75 +575,75 @@ def update_block(block_number, new_transactions): self.tip = b46 assert 46 not in self.blocks self.blocks[46] = b46 - yield rejected(RejectResult(16, b'bad-blk-length')) + yield self.rejected(RejectResult(16, b'bad-blk-length')) # A block with invalid work - tip(44) - b47 = block(47, solve=False) + self.move_tip(44) + b47 = self.next_block(47, solve=False) target = uint256_from_compact(b47.nBits) while b47.sha256 < target: # changed > to < b47.nNonce += 1 b47.rehash() - yield rejected(RejectResult(16, b'high-hash')) + yield self.rejected(RejectResult(16, b'high-hash')) # A block with timestamp > 2 hrs in the future - tip(44) - b48 = block(48, solve=False) + self.move_tip(44) + b48 = self.next_block(48, solve=False) b48.nTime = int(time.time()) + 60 * 60 * 3 b48.solve() - yield rejected(RejectResult(16, b'time-too-new')) + yield self.rejected(RejectResult(16, b'time-too-new')) # A block with an invalid merkle hash - tip(44) - b49 = block(49) + self.move_tip(44) + b49 = self.next_block(49) b49.hashMerkleRoot += 1 b49.solve() - yield rejected(RejectResult(16, b'bad-txnmrklroot')) + yield self.rejected(RejectResult(16, b'bad-txnmrklroot')) # A block with an incorrect POW limit - tip(44) - b50 = block(50) + self.move_tip(44) + b50 = self.next_block(50) b50.nBits = b50.nBits - 1 b50.solve() - yield rejected(RejectResult(16, b'bad-diffbits')) + yield self.rejected(RejectResult(16, b'bad-diffbits')) # A block with two coinbase txns - tip(44) - block(51) + self.move_tip(44) + self.next_block(51) cb2 = create_coinbase(51, self.coinbase_pubkey) - update_block(51, [cb2]) - yield rejected(RejectResult(16, b'bad-cb-multiple')) + self.update_block(51, [cb2]) + yield self.rejected(RejectResult(16, b'bad-cb-multiple')) # A block w/ duplicate txns # Note: txns have to be in the right position in the merkle tree to trigger this error - tip(44) - b52 = block(52, spend=out[15]) - tx = create_tx(b52.vtx[1], 0, 1) - b52 = update_block(52, [tx, tx]) - yield rejected(RejectResult(16, b'bad-txns-duplicate')) + self.move_tip(44) + b52 = self.next_block(52, spend=out[15]) + tx = self.create_tx(b52.vtx[1], 0, 1) + b52 = self.update_block(52, [tx, tx]) + yield self.rejected(RejectResult(16, b'bad-txns-duplicate')) # Test block timestamps # -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) # \-> b54 (15) # - tip(43) - block(53, spend=out[14]) - yield rejected() # rejected since b44 is at same height - save_spendable_output() + self.move_tip(43) + self.next_block(53, spend=out[14]) + yield self.rejected() # rejected since b44 is at same height + self.save_spendable_output() # invalid timestamp (b35 is 5 blocks back, so its time is MedianTimePast) - b54 = block(54, spend=out[15]) + b54 = self.next_block(54, spend=out[15]) b54.nTime = b35.nTime - 1 b54.solve() - yield rejected(RejectResult(16, b'time-too-old')) + yield self.rejected(RejectResult(16, b'time-too-old')) # valid timestamp - tip(53) - b55 = block(55, spend=out[15]) + self.move_tip(53) + b55 = self.next_block(55, spend=out[15]) b55.nTime = b35.nTime - update_block(55, []) - yield accepted() - save_spendable_output() + self.update_block(55, []) + yield self.accepted() + self.save_spendable_output() # Test CVE-2012-2459 # @@ -776,46 +673,46 @@ def update_block(block_number, new_transactions): # that the error was caught early, avoiding a DOS vulnerability.) # b57 - a good block with 2 txs, don't submit until end - tip(55) - b57 = block(57) - tx = create_and_sign_tx(out[16].tx, out[16].n, 1) - tx1 = create_tx(tx, 0, 1) - b57 = update_block(57, [tx, tx1]) + self.move_tip(55) + b57 = self.next_block(57) + tx = self.create_and_sign_transaction(out[16].tx, out[16].n, 1) + tx1 = self.create_tx(tx, 0, 1) + b57 = self.update_block(57, [tx, tx1]) # b56 - copy b57, add a duplicate tx - tip(55) + self.move_tip(55) b56 = copy.deepcopy(b57) self.blocks[56] = b56 assert_equal(len(b56.vtx), 3) - b56 = update_block(56, [tx1]) + b56 = self.update_block(56, [tx1]) assert_equal(b56.hash, b57.hash) - yield rejected(RejectResult(16, b'bad-txns-duplicate')) + yield self.rejected(RejectResult(16, b'bad-txns-duplicate')) # b57p2 - a good block with 6 tx'es, don't submit until end - tip(55) - b57p2 = block("57p2") - tx = create_and_sign_tx(out[16].tx, out[16].n, 1) - tx1 = create_tx(tx, 0, 1) - tx2 = create_tx(tx1, 0, 1) - tx3 = create_tx(tx2, 0, 1) - tx4 = create_tx(tx3, 0, 1) - b57p2 = update_block("57p2", [tx, tx1, tx2, tx3, tx4]) + self.move_tip(55) + b57p2 = self.next_block("57p2") + tx = self.create_and_sign_transaction(out[16].tx, out[16].n, 1) + tx1 = self.create_tx(tx, 0, 1) + tx2 = self.create_tx(tx1, 0, 1) + tx3 = self.create_tx(tx2, 0, 1) + tx4 = self.create_tx(tx3, 0, 1) + b57p2 = self.update_block("57p2", [tx, tx1, tx2, tx3, tx4]) # b56p2 - copy b57p2, duplicate two non-consecutive tx's - tip(55) + self.move_tip(55) b56p2 = copy.deepcopy(b57p2) self.blocks["b56p2"] = b56p2 assert_equal(b56p2.hash, b57p2.hash) assert_equal(len(b56p2.vtx), 6) - b56p2 = update_block("b56p2", [tx3, tx4]) - yield rejected(RejectResult(16, b'bad-txns-duplicate')) + b56p2 = self.update_block("b56p2", [tx3, tx4]) + yield self.rejected(RejectResult(16, b'bad-txns-duplicate')) - tip("57p2") - yield accepted() + self.move_tip("57p2") + yield self.accepted() - tip(57) - yield rejected() # rejected because 57p2 seen first - save_spendable_output() + self.move_tip(57) + yield self.rejected() # rejected because 57p2 seen first + self.save_spendable_output() # Test a few invalid tx types # @@ -824,28 +721,28 @@ def update_block(block_number, new_transactions): # # tx with prevout.n out of range - tip(57) - block(58, spend=out[17]) + self.move_tip(57) + self.next_block(58, spend=out[17]) tx = CTransaction() assert(len(out[17].tx.vout) < 42) tx.vin.append(CTxIn(COutPoint(out[17].tx.sha256, 42), CScript([OP_TRUE]), 0xffffffff)) tx.vout.append(CTxOut(0, b"")) tx.calc_sha256() - update_block(58, [tx]) - yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + self.update_block(58, [tx]) + yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # tx with output value > input value out of range - tip(57) - block(59) - tx = create_and_sign_tx(out[17].tx, out[17].n, 51 * COIN) - update_block(59, [tx]) - yield rejected(RejectResult(16, b'bad-txns-in-belowout')) + self.move_tip(57) + self.next_block(59) + tx = self.create_and_sign_transaction(out[17].tx, out[17].n, 51 * COIN) + self.update_block(59, [tx]) + yield self.rejected(RejectResult(16, b'bad-txns-in-belowout')) # reset to good chain - tip(57) - b60 = block(60, spend=out[17]) - yield accepted() - save_spendable_output() + self.move_tip(57) + b60 = self.next_block(60, spend=out[17]) + yield self.accepted() + self.save_spendable_output() # Test BIP30 # @@ -856,21 +753,21 @@ def update_block(block_number, new_transactions): # not-fully-spent transaction in the same chain. To test, make identical coinbases; # the second one should be rejected. # - tip(60) - b61 = block(61, spend=out[18]) + self.move_tip(60) + b61 = self.next_block(61, spend=out[18]) b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig # equalize the coinbases b61.vtx[0].rehash() - b61 = update_block(61, []) + b61 = self.update_block(61, []) assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize()) - yield rejected(RejectResult(16, b'bad-txns-BIP30')) + yield self.rejected(RejectResult(16, b'bad-txns-BIP30')) # Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests) # # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) # \-> b62 (18) # - tip(60) - block(62) + self.move_tip(60) + self.next_block(62) tx = CTransaction() tx.nLockTime = 0xffffffff # this locktime is non-final assert(out[18].n < len(out[18].tx.vout)) @@ -878,21 +775,21 @@ def update_block(block_number, new_transactions): tx.vout.append(CTxOut(0, CScript([OP_TRUE]))) assert(tx.vin[0].nSequence < 0xffffffff) tx.calc_sha256() - update_block(62, [tx]) - yield rejected(RejectResult(16, b'bad-txns-nonfinal')) + self.update_block(62, [tx]) + yield self.rejected(RejectResult(16, b'bad-txns-nonfinal')) # Test a non-final coinbase is also rejected # # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) # \-> b63 (-) # - tip(60) - b63 = block(63) + self.move_tip(60) + b63 = self.next_block(63) b63.vtx[0].nLockTime = 0xffffffff b63.vtx[0].vin[0].nSequence = 0xDEADBEEF b63.vtx[0].rehash() - b63 = update_block(63, []) - yield rejected(RejectResult(16, b'bad-txns-nonfinal')) + b63 = self.update_block(63, []) + yield self.rejected(RejectResult(16, b'bad-txns-nonfinal')) # This checks that a block with a bloated VARINT between the block_header and the array of tx such that # the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint, @@ -908,8 +805,8 @@ def update_block(block_number, new_transactions): # b64a is a bloated block (non-canonical varint) # b64 is a good block (same as b64 but w/ canonical varint) # - tip(60) - regular_block = block("64a", spend=out[18]) + self.move_tip(60) + regular_block = self.next_block("64a", spend=out[18]) # make it a "broken_block," with non-canonical serialization b64a = CBrokenBlock(regular_block) @@ -923,45 +820,45 @@ def update_block(block_number, new_transactions): script_output = CScript([b'\x00' * script_length]) tx.vout.append(CTxOut(0, script_output)) tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0))) - b64a = update_block("64a", [tx]) + b64a = self.update_block("64a", [tx]) assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8) yield TestInstance([[self.tip, None]]) # comptool workaround: to make sure b64 is delivered, manually erase b64a from blockstore self.test.block_store.erase(b64a.sha256) - tip(60) + self.move_tip(60) b64 = CBlock(b64a) b64.vtx = copy.deepcopy(b64a.vtx) assert_equal(b64.hash, b64a.hash) assert_equal(len(b64.serialize()), MAX_BLOCK_BASE_SIZE) self.blocks[64] = b64 - update_block(64, []) - yield accepted() - save_spendable_output() + self.update_block(64, []) + yield self.accepted() + self.save_spendable_output() # Spend an output created in the block itself # # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) # - tip(64) - block(65) - tx1 = create_and_sign_tx(out[19].tx, out[19].n, out[19].tx.vout[0].nValue) - tx2 = create_and_sign_tx(tx1, 0, 0) - update_block(65, [tx1, tx2]) - yield accepted() - save_spendable_output() + self.move_tip(64) + self.next_block(65) + tx1 = self.create_and_sign_transaction(out[19].tx, out[19].n, out[19].tx.vout[0].nValue) + tx2 = self.create_and_sign_transaction(tx1, 0, 0) + self.update_block(65, [tx1, tx2]) + yield self.accepted() + self.save_spendable_output() # Attempt to spend an output created later in the same block # # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) # \-> b66 (20) - tip(65) - block(66) - tx1 = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue) - tx2 = create_and_sign_tx(tx1, 0, 1) - update_block(66, [tx2, tx1]) - yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + self.move_tip(65) + self.next_block(66) + tx1 = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue) + tx2 = self.create_and_sign_transaction(tx1, 0, 1) + self.update_block(66, [tx2, tx1]) + yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # Attempt to double-spend a transaction created in a block # @@ -969,13 +866,13 @@ def update_block(block_number, new_transactions): # \-> b67 (20) # # - tip(65) - block(67) - tx1 = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue) - tx2 = create_and_sign_tx(tx1, 0, 1) - tx3 = create_and_sign_tx(tx1, 0, 2) - update_block(67, [tx1, tx2, tx3]) - yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + self.move_tip(65) + self.next_block(67) + tx1 = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue) + tx2 = self.create_and_sign_transaction(tx1, 0, 1) + tx3 = self.create_and_sign_transaction(tx1, 0, 2) + self.update_block(67, [tx1, tx2, tx3]) + yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # More tests of block subsidy # @@ -989,33 +886,33 @@ def update_block(block_number, new_transactions): # b69 - coinbase with extra 10 satoshis, and a tx that gives a 10 satoshi fee # this succeeds # - tip(65) - block(68, additional_coinbase_value=10) - tx = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 9) - update_block(68, [tx]) - yield rejected(RejectResult(16, b'bad-cb-amount')) + self.move_tip(65) + self.next_block(68, additional_coinbase_value=10) + tx = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 9) + self.update_block(68, [tx]) + yield self.rejected(RejectResult(16, b'bad-cb-amount')) - tip(65) - b69 = block(69, additional_coinbase_value=10) - tx = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 10) - update_block(69, [tx]) - yield accepted() - save_spendable_output() + self.move_tip(65) + b69 = self.next_block(69, additional_coinbase_value=10) + tx = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 10) + self.update_block(69, [tx]) + yield self.accepted() + self.save_spendable_output() # Test spending the outpoint of a non-existent transaction # # -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) # \-> b70 (21) # - tip(69) - block(70, spend=out[21]) + self.move_tip(69) + self.next_block(70, spend=out[21]) bogus_tx = CTransaction() bogus_tx.sha256 = uint256_from_str(b"23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c") tx = CTransaction() tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff)) tx.vout.append(CTxOut(1, b"")) - update_block(70, [tx]) - yield rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) + self.update_block(70, [tx]) + yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks) # @@ -1025,11 +922,11 @@ def update_block(block_number, new_transactions): # b72 is a good block. # b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b71. # - tip(69) - b72 = block(72) - tx1 = create_and_sign_tx(out[21].tx, out[21].n, 2) - tx2 = create_and_sign_tx(tx1, 0, 1) - b72 = update_block(72, [tx1, tx2]) # now tip is 72 + self.move_tip(69) + b72 = self.next_block(72) + tx1 = self.create_and_sign_transaction(out[21].tx, out[21].n, 2) + tx2 = self.create_and_sign_transaction(tx1, 0, 1) + b72 = self.update_block(72, [tx1, tx2]) # now tip is 72 b71 = copy.deepcopy(b72) b71.vtx.append(tx2) # add duplicate tx2 self.block_heights[b71.sha256] = self.block_heights[b69.sha256] + 1 # b71 builds off b69 @@ -1039,11 +936,11 @@ def update_block(block_number, new_transactions): assert_equal(len(b72.vtx), 3) assert_equal(b72.sha256, b71.sha256) - tip(71) - yield rejected(RejectResult(16, b'bad-txns-duplicate')) - tip(72) - yield accepted() - save_spendable_output() + self.move_tip(71) + yield self.rejected(RejectResult(16, b'bad-txns-duplicate')) + self.move_tip(72) + yield self.accepted() + self.save_spendable_output() # Test some invalid scripts and MAX_BLOCK_SIGOPS # @@ -1062,8 +959,8 @@ def update_block(block_number, new_transactions): # bytearray[20,004-20,525]: unread data (script_element) # bytearray[20,526] : OP_CHECKSIG (this puts us over the limit) # - tip(72) - b73 = block(73) + self.move_tip(72) + b73 = self.next_block(73) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 1 a = bytearray([OP_CHECKSIG] * size) a[MAX_BLOCK_SIGOPS - 1] = int("4e", 16) # OP_PUSHDATA4 @@ -1074,10 +971,10 @@ def update_block(block_number, new_transactions): a[MAX_BLOCK_SIGOPS + 2] = 0 a[MAX_BLOCK_SIGOPS + 3] = 0 - tx = create_and_sign_tx(out[22].tx, 0, 1, CScript(a)) - b73 = update_block(73, [tx]) + tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a)) + b73 = self.update_block(73, [tx]) assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1) - yield rejected(RejectResult(16, b'bad-blk-sigops')) + yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # b74/75 - if we push an invalid script element, all prevous sigops are counted, # but sigops after the element are not counted. @@ -1091,8 +988,8 @@ def update_block(block_number, new_transactions): # b75 succeeds because we put MAX_BLOCK_SIGOPS before the element # # - tip(72) - block(74) + self.move_tip(72) + self.next_block(74) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 # total = 20,561 a = bytearray([OP_CHECKSIG] * size) a[MAX_BLOCK_SIGOPS] = 0x4e @@ -1100,12 +997,12 @@ def update_block(block_number, new_transactions): a[MAX_BLOCK_SIGOPS + 2] = 0xff a[MAX_BLOCK_SIGOPS + 3] = 0xff a[MAX_BLOCK_SIGOPS + 4] = 0xff - tx = create_and_sign_tx(out[22].tx, 0, 1, CScript(a)) - update_block(74, [tx]) - yield rejected(RejectResult(16, b'bad-blk-sigops')) + tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a)) + self.update_block(74, [tx]) + yield self.rejected(RejectResult(16, b'bad-blk-sigops')) - tip(72) - block(75) + self.move_tip(72) + self.next_block(75) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 a = bytearray([OP_CHECKSIG] * size) a[MAX_BLOCK_SIGOPS - 1] = 0x4e @@ -1113,21 +1010,21 @@ def update_block(block_number, new_transactions): a[MAX_BLOCK_SIGOPS + 1] = 0xff a[MAX_BLOCK_SIGOPS + 2] = 0xff a[MAX_BLOCK_SIGOPS + 3] = 0xff - tx = create_and_sign_tx(out[22].tx, 0, 1, CScript(a)) - update_block(75, [tx]) - yield accepted() - save_spendable_output() + tx = self.create_and_sign_transaction(out[22].tx, 0, 1, CScript(a)) + self.update_block(75, [tx]) + yield self.accepted() + self.save_spendable_output() # Check that if we push an element filled with CHECKSIGs, they are not counted - tip(75) - block(76) + self.move_tip(75) + self.next_block(76) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 a = bytearray([OP_CHECKSIG] * size) a[MAX_BLOCK_SIGOPS - 1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs - tx = create_and_sign_tx(out[23].tx, 0, 1, CScript(a)) - update_block(76, [tx]) - yield accepted() - save_spendable_output() + tx = self.create_and_sign_transaction(out[23].tx, 0, 1, CScript(a)) + self.update_block(76, [tx]) + yield self.accepted() + self.save_spendable_output() # Test transaction resurrection # @@ -1147,38 +1044,38 @@ def update_block(block_number, new_transactions): # spend to OP_TRUE. If the standard-ness rules change, this test would need to be # updated. (Perhaps to spend to a P2SH OP_TRUE script) # - tip(76) - block(77) - tx77 = create_and_sign_tx(out[24].tx, out[24].n, 10 * COIN) - update_block(77, [tx77]) - yield accepted() - save_spendable_output() + self.move_tip(76) + self.next_block(77) + tx77 = self.create_and_sign_transaction(out[24].tx, out[24].n, 10 * COIN) + self.update_block(77, [tx77]) + yield self.accepted() + self.save_spendable_output() - block(78) - tx78 = create_tx(tx77, 0, 9 * COIN) - update_block(78, [tx78]) - yield accepted() + self.next_block(78) + tx78 = self.create_tx(tx77, 0, 9 * COIN) + self.update_block(78, [tx78]) + yield self.accepted() - block(79) - tx79 = create_tx(tx78, 0, 8 * COIN) - update_block(79, [tx79]) - yield accepted() + self.next_block(79) + tx79 = self.create_tx(tx78, 0, 8 * COIN) + self.update_block(79, [tx79]) + yield self.accepted() # mempool should be empty assert_equal(len(self.nodes[0].getrawmempool()), 0) - tip(77) - block(80, spend=out[25]) - yield rejected() - save_spendable_output() + self.move_tip(77) + self.next_block(80, spend=out[25]) + yield self.rejected() + self.save_spendable_output() - block(81, spend=out[26]) - yield rejected() # other chain is same length - save_spendable_output() + self.next_block(81, spend=out[26]) + yield self.rejected() # other chain is same length + self.save_spendable_output() - block(82, spend=out[27]) - yield accepted() # now this chain is longer, triggers re-org - save_spendable_output() + self.next_block(82, spend=out[27]) + yield self.accepted() # now this chain is longer, triggers re-org + self.save_spendable_output() # now check that tx78 and tx79 have been put back into the peer's mempool mempool = self.nodes[0].getrawmempool() @@ -1190,18 +1087,18 @@ def update_block(block_number, new_transactions): # # -> b81 (26) -> b82 (27) -> b83 (28) # - block(83) + self.next_block(83) op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF] script = CScript(op_codes) - tx1 = create_and_sign_tx(out[28].tx, out[28].n, out[28].tx.vout[0].nValue, script) + tx1 = self.create_and_sign_transaction(out[28].tx, out[28].n, out[28].tx.vout[0].nValue, script) - tx2 = create_and_sign_tx(tx1, 0, 0, CScript([OP_TRUE])) + tx2 = self.create_and_sign_transaction(tx1, 0, 0, CScript([OP_TRUE])) tx2.vin[0].scriptSig = CScript([OP_FALSE]) tx2.rehash() - update_block(83, [tx1, tx2]) - yield accepted() - save_spendable_output() + self.update_block(83, [tx1, tx2]) + yield self.accepted() + self.save_spendable_output() # Reorg on/off blocks that have OP_RETURN in them (and try to spend them) # @@ -1209,8 +1106,8 @@ def update_block(block_number, new_transactions): # \-> b85 (29) -> b86 (30) \-> b89a (32) # # - block(84) - tx1 = create_tx(out[29].tx, out[29].n, 0, CScript([OP_RETURN])) + self.next_block(84) + tx1 = self.create_tx(out[29].tx, out[29].n, 0, CScript([OP_RETURN])) tx1.vout.append(CTxOut(0, CScript([OP_TRUE]))) tx1.vout.append(CTxOut(0, CScript([OP_TRUE]))) tx1.vout.append(CTxOut(0, CScript([OP_TRUE]))) @@ -1218,84 +1115,176 @@ def update_block(block_number, new_transactions): tx1.calc_sha256() self.sign_tx(tx1, out[29].tx, out[29].n) tx1.rehash() - tx2 = create_tx(tx1, 1, 0, CScript([OP_RETURN])) + tx2 = self.create_tx(tx1, 1, 0, CScript([OP_RETURN])) tx2.vout.append(CTxOut(0, CScript([OP_RETURN]))) - tx3 = create_tx(tx1, 2, 0, CScript([OP_RETURN])) + tx3 = self.create_tx(tx1, 2, 0, CScript([OP_RETURN])) tx3.vout.append(CTxOut(0, CScript([OP_TRUE]))) - tx4 = create_tx(tx1, 3, 0, CScript([OP_TRUE])) + tx4 = self.create_tx(tx1, 3, 0, CScript([OP_TRUE])) tx4.vout.append(CTxOut(0, CScript([OP_RETURN]))) - tx5 = create_tx(tx1, 4, 0, CScript([OP_RETURN])) + tx5 = self.create_tx(tx1, 4, 0, CScript([OP_RETURN])) - update_block(84, [tx1, tx2, tx3, tx4, tx5]) - yield accepted() - save_spendable_output() + self.update_block(84, [tx1, tx2, tx3, tx4, tx5]) + yield self.accepted() + self.save_spendable_output() - tip(83) - block(85, spend=out[29]) - yield rejected() + self.move_tip(83) + self.next_block(85, spend=out[29]) + yield self.rejected() - block(86, spend=out[30]) - yield accepted() + self.next_block(86, spend=out[30]) + yield self.accepted() - tip(84) - block(87, spend=out[30]) - yield rejected() - save_spendable_output() + self.move_tip(84) + self.next_block(87, spend=out[30]) + yield self.rejected() + self.save_spendable_output() - block(88, spend=out[31]) - yield accepted() - save_spendable_output() + self.next_block(88, spend=out[31]) + yield self.accepted() + self.save_spendable_output() # trying to spend the OP_RETURN output is rejected - block("89a", spend=out[32]) - tx = create_tx(tx1, 0, 0, CScript([OP_TRUE])) - update_block("89a", [tx]) - yield rejected() - - # Test re-org of a week's worth of blocks (1088 blocks) - # This test takes a minute or two and can be accomplished in memory - # - if self.options.runbarelyexpensive: - tip(88) - LARGE_REORG_SIZE = 1088 - test1 = TestInstance(sync_every_block=False) - spend = out[32] - for i in range(89, LARGE_REORG_SIZE + 89): - b = block(i, spend) - tx = CTransaction() - script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69 - script_output = CScript([b'\x00' * script_length]) - tx.vout.append(CTxOut(0, script_output)) - tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0))) - b = update_block(i, [tx]) - assert_equal(len(b.serialize()), MAX_BLOCK_BASE_SIZE) - test1.blocks_and_transactions.append([self.tip, True]) - save_spendable_output() - spend = get_spendable_output() - - yield test1 - chain1_tip = i - - # now create alt chain of same length - tip(88) - test2 = TestInstance(sync_every_block=False) - for i in range(89, LARGE_REORG_SIZE + 89): - block("alt" + str(i)) - test2.blocks_and_transactions.append([self.tip, False]) - yield test2 - - # extend alt chain to trigger re-org - block("alt" + str(chain1_tip + 1)) - yield accepted() - - # ... and re-org back to the first chain - tip(chain1_tip) - block(chain1_tip + 1) - yield rejected() - block(chain1_tip + 2) - yield accepted() - - chain1_tip += 2 + self.next_block("89a", spend=out[32]) + tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE])) + self.update_block("89a", [tx]) + yield self.rejected() + + self.move_tip(88) + LARGE_REORG_SIZE = 1088 + test1 = TestInstance(sync_every_block=False) + spend = out[32] + for i in range(89, LARGE_REORG_SIZE + 89): + b = self.next_block(i, spend) + tx = CTransaction() + script_length = MAX_BLOCK_BASE_SIZE - len(b.serialize()) - 69 + script_output = CScript([b'\x00' * script_length]) + tx.vout.append(CTxOut(0, script_output)) + tx.vin.append(CTxIn(COutPoint(b.vtx[1].sha256, 0))) + b = self.update_block(i, [tx]) + assert_equal(len(b.serialize()), MAX_BLOCK_BASE_SIZE) + test1.blocks_and_transactions.append([self.tip, True]) + self.save_spendable_output() + spend = self.get_spendable_output() + + yield test1 + chain1_tip = i + + # now create alt chain of same length + self.move_tip(88) + test2 = TestInstance(sync_every_block=False) + for i in range(89, LARGE_REORG_SIZE + 89): + self.next_block("alt" + str(i)) + test2.blocks_and_transactions.append([self.tip, False]) + yield test2 + + # extend alt chain to trigger re-org + self.next_block("alt" + str(chain1_tip + 1)) + yield self.accepted() + + # ... and re-org back to the first chain + self.move_tip(chain1_tip) + self.next_block(chain1_tip + 1) + yield self.rejected() + self.next_block(chain1_tip + 2) + yield self.accepted() + + chain1_tip += 2 + + # Helper methods + ################ + + def add_transactions_to_block(self, block, tx_list): + [tx.rehash() for tx in tx_list] + block.vtx.extend(tx_list) + + # this is a little handier to use than the version in blocktools.py + def create_tx(self, spend_tx, n, value, script=CScript([OP_TRUE])): + tx = create_transaction(spend_tx, n, b"", value, script) + return tx + + # sign a transaction, using the key we know about + # this signs input 0 in tx, which is assumed to be spending output n in spend_tx + def sign_tx(self, tx, spend_tx, n): + scriptPubKey = bytearray(spend_tx.vout[n].scriptPubKey) + if (scriptPubKey[0] == OP_TRUE): # an anyone-can-spend + tx.vin[0].scriptSig = CScript() + return + (sighash, err) = SignatureHash(spend_tx.vout[n].scriptPubKey, tx, 0, SIGHASH_ALL) + tx.vin[0].scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))]) + + def create_and_sign_transaction(self, spend_tx, n, value, script=CScript([OP_TRUE])): + tx = self.create_tx(spend_tx, n, value, script) + self.sign_tx(tx, spend_tx, n) + tx.rehash() + return tx + + def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True): + if self.tip is None: + base_block_hash = self.genesis_hash + block_time = int(time.time()) + 1 + else: + base_block_hash = self.tip.sha256 + block_time = self.tip.nTime + 1 + # First create the coinbase + height = self.block_heights[base_block_hash] + 1 + coinbase = create_coinbase(height, self.coinbase_pubkey) + coinbase.vout[0].nValue += additional_coinbase_value + coinbase.rehash() + if spend is None: + block = create_block(base_block_hash, coinbase, block_time) + else: + coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 # all but one satoshi to fees + coinbase.rehash() + block = create_block(base_block_hash, coinbase, block_time) + tx = create_transaction(spend.tx, spend.n, b"", 1, script) # spend 1 satoshi + self.sign_tx(tx, spend.tx, spend.n) + self.add_transactions_to_block(block, [tx]) + block.hashMerkleRoot = block.calc_merkle_root() + if solve: + block.solve() + self.tip = block + self.block_heights[block.sha256] = height + assert number not in self.blocks + self.blocks[number] = block + return block + + # save the current tip so it can be spent by a later block + def save_spendable_output(self): + self.spendable_outputs.append(self.tip) + + # get an output that we previously marked as spendable + def get_spendable_output(self): + return PreviousSpendableOutput(self.spendable_outputs.pop(0).vtx[0], 0) + + # returns a test case that asserts that the current tip was accepted + def accepted(self): + return TestInstance([[self.tip, True]]) + + # returns a test case that asserts that the current tip was rejected + def rejected(self, reject=None): + if reject is None: + return TestInstance([[self.tip, False]]) + else: + return TestInstance([[self.tip, reject]]) + + # move the tip back to a previous block + def move_tip(self, number): + self.tip = self.blocks[number] + + # adds transactions to the block and updates state + def update_block(self, block_number, new_transactions): + block = self.blocks[block_number] + self.add_transactions_to_block(block, new_transactions) + old_sha256 = block.sha256 + block.hashMerkleRoot = block.calc_merkle_root() + block.solve() + # Update the internal state just like in next_block + self.tip = block + if block.sha256 != old_sha256: + self.block_heights[block.sha256] = self.block_heights[old_sha256] + del self.block_heights[old_sha256] + self.blocks[block_number] = block + return block if __name__ == '__main__': From fc02c12ae915ac040f64860048912d1624b921fb Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 22 Nov 2017 14:07:26 -0500 Subject: [PATCH 036/900] [tests] Add logging to feature_block.py --- test/functional/feature_block.py | 77 ++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index e026e85a3..ad6b9eb21 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -145,6 +145,7 @@ def get_tests(self): # \-> b3 (1) # # Nothing should happen at this point. We saw b2 first so it takes priority. + self.log.info("Don't reorg to a chain of the same length") self.move_tip(1) b3 = self.next_block(3, spend=out[1]) txout_b3 = PreviousSpendableOutput(b3.vtx[1], 0) @@ -154,6 +155,7 @@ def get_tests(self): # # genesis -> b1 (0) -> b2 (1) # \-> b3 (1) -> b4 (2) + self.log.info("Reorg to a longer chain") self.next_block(4, spend=out[2]) yield self.accepted() @@ -165,6 +167,7 @@ def get_tests(self): self.save_spendable_output() yield self.rejected() + self.log.info("Reorg back to the original chain") self.next_block(6, spend=out[3]) yield self.accepted() @@ -172,6 +175,7 @@ def get_tests(self): # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b7 (2) -> b8 (4) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a chain with a double spend, even if it is longer") self.move_tip(5) self.next_block(7, spend=out[2]) yield self.rejected() @@ -183,6 +187,7 @@ def get_tests(self): # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b9 (4) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a block where the miner creates too much coinbase reward") self.move_tip(6) self.next_block(9, spend=out[4], additional_coinbase_value=1) yield self.rejected(RejectResult(16, b'bad-cb-amount')) @@ -191,6 +196,7 @@ def get_tests(self): # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b10 (3) -> b11 (4) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer") self.move_tip(5) self.next_block(10, spend=out[3]) yield self.rejected() @@ -203,6 +209,7 @@ def get_tests(self): # \-> b12 (3) -> b13 (4) -> b14 (5) # (b12 added last) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer (on a forked chain)") self.move_tip(5) b12 = self.next_block(12, spend=out[3]) self.save_spendable_output() @@ -223,15 +230,14 @@ def get_tests(self): # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6) # \-> b3 (1) -> b4 (2) - - # Test that a block with a lot of checksigs is okay + self.log.info("Accept a block with lots of checksigs") lots_of_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS - 1)) self.move_tip(13) self.next_block(15, spend=out[5], script=lots_of_checksigs) yield self.accepted() self.save_spendable_output() - # Test that a block with too many checksigs is rejected + self.log.info("Reject a block with too many checksigs") too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS)) self.next_block(16, spend=out[6], script=too_many_checksigs) yield self.rejected(RejectResult(16, b'bad-blk-sigops')) @@ -240,6 +246,7 @@ def get_tests(self): # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1]) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a block with a spend from a re-org'ed out tx") self.move_tip(15) self.next_block(17, spend=txout_b3) yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) @@ -249,6 +256,7 @@ def get_tests(self): # \-> b12 (3) -> b13 (4) -> b15 (5) # \-> b18 (b3.vtx[1]) -> b19 (6) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a block with a spend from a re-org'ed out tx (on a forked chain)") self.move_tip(13) self.next_block(18, spend=txout_b3) yield self.rejected() @@ -260,6 +268,7 @@ def get_tests(self): # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) # \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a block spending an immature coinbase.") self.move_tip(15) self.next_block(20, spend=out[7]) yield self.rejected(RejectResult(16, b'bad-txns-premature-spend-of-coinbase')) @@ -269,6 +278,7 @@ def get_tests(self): # \-> b12 (3) -> b13 (4) -> b15 (5) # \-> b21 (6) -> b22 (5) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a block spending an immature coinbase (on a forked chain)") self.move_tip(13) self.next_block(21, spend=out[6]) yield self.rejected() @@ -281,6 +291,7 @@ def get_tests(self): # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) # \-> b24 (6) -> b25 (7) # \-> b3 (1) -> b4 (2) + self.log.info("Accept a block of size MAX_BLOCK_BASE_SIZE") self.move_tip(15) b23 = self.next_block(23, spend=out[6]) tx = CTransaction() @@ -294,7 +305,7 @@ def get_tests(self): yield self.accepted() self.save_spendable_output() - # Make the next block one byte bigger and check that it fails + self.log.info("Reject a block of size MAX_BLOCK_BASE_SIZE + 1") self.move_tip(15) b24 = self.next_block(24, spend=out[6]) script_length = MAX_BLOCK_BASE_SIZE - len(b24.serialize()) - 69 @@ -312,6 +323,7 @@ def get_tests(self): # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) # \-> ... (6) -> ... (7) # \-> b3 (1) -> b4 (2) + self.log.info("Reject a block with coinbase input script size out of range") self.move_tip(15) b26 = self.next_block(26, spend=out[6]) b26.vtx[0].vin[0].scriptSig = b'\x00' @@ -355,6 +367,7 @@ def get_tests(self): # # MULTISIG: each op code counts as 20 sigops. To create the edge case, pack another 19 sigops at the end. + self.log.info("Accept a block with the max number of OP_CHECKMULTISIG sigops") lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19) b31 = self.next_block(31, spend=out[8], script=lots_of_multisigs) assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS) @@ -362,29 +375,34 @@ def get_tests(self): self.save_spendable_output() # this goes over the limit because the coinbase has one sigop + self.log.info("Reject a block with too many OP_CHECKMULTISIG sigops") too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20)) b32 = self.next_block(32, spend=out[9], script=too_many_multisigs) assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1) yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # CHECKMULTISIGVERIFY + self.log.info("Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops") self.move_tip(31) lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19) self.next_block(33, spend=out[9], script=lots_of_multisigs) yield self.accepted() self.save_spendable_output() + self.log.info("Reject a block with too many OP_CHECKMULTISIGVERIFY sigops") too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20)) self.next_block(34, spend=out[10], script=too_many_multisigs) yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # CHECKSIGVERIFY + self.log.info("Accept a block with the max number of OP_CHECKSIGVERIFY sigops") self.move_tip(33) lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS - 1)) b35 = self.next_block(35, spend=out[10], script=lots_of_checksigs) yield self.accepted() self.save_spendable_output() + self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops") too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS)) self.next_block(36, spend=out[11], script=too_many_checksigs) yield self.rejected(RejectResult(16, b'bad-blk-sigops')) @@ -398,6 +416,7 @@ def get_tests(self): # # save 37's spendable output, but then double-spend out11 to invalidate the block + self.log.info("Reject a block spending transaction from a block which failed to connect") self.move_tip(35) b37 = self.next_block(37, spend=out[11]) txout_b37 = PreviousSpendableOutput(b37.vtx[1], 0) @@ -421,6 +440,7 @@ def get_tests(self): # redeem_script = COINBASE_PUBKEY, (OP_2DUP+OP_CHECKSIGVERIFY) * 5, OP_CHECKSIG # p2sh_script = OP_HASH160, ripemd160(sha256(script)), OP_EQUAL # + self.log.info("Check P2SH SIGOPS are correctly counted") self.move_tip(35) b39 = self.next_block(39) b39_outputs = 0 @@ -467,6 +487,7 @@ def get_tests(self): # # b41 does the same, less one, so it has the maximum sigops permitted. # + self.log.info("Reject a block with too many P2SH sigops") self.move_tip(39) b40 = self.next_block(40, spend=out[12]) sigops = get_legacy_sigopcount_block(b40) @@ -501,6 +522,7 @@ def get_tests(self): yield self.rejected(RejectResult(16, b'bad-blk-sigops')) # same as b40, but one less sigop + self.log.info("Accept a block with the max number of P2SH sigops") self.move_tip(39) self.next_block(41, spend=None) self.update_block(41, b40.vtx[1:-1]) @@ -533,6 +555,7 @@ def get_tests(self): # The next few blocks are going to be created "by hand" since they'll do funky things, such as having # the first transaction be non-coinbase, etc. The purpose of b44 is to make sure this works. + self.log.info("Build block 44 manually") height = self.block_heights[self.tip.sha256] + 1 coinbase = create_coinbase(height, self.coinbase_pubkey) b44 = CBlock() @@ -547,7 +570,7 @@ def get_tests(self): self.blocks[44] = b44 yield self.accepted() - # A block with a non-coinbase as the first tx + self.log.info("Reject a block with a non-coinbase as the first tx") non_coinbase = self.create_tx(out[15].tx, out[15].n, 1) b45 = CBlock() b45.nTime = self.tip.nTime + 1 @@ -562,7 +585,7 @@ def get_tests(self): self.blocks[45] = b45 yield self.rejected(RejectResult(16, b'bad-cb-missing')) - # A block with no txns + self.log.info("Reject a block with no transactions") self.move_tip(44) b46 = CBlock() b46.nTime = b44.nTime + 1 @@ -577,7 +600,7 @@ def get_tests(self): self.blocks[46] = b46 yield self.rejected(RejectResult(16, b'bad-blk-length')) - # A block with invalid work + self.log.info("Reject a block with invalid work") self.move_tip(44) b47 = self.next_block(47, solve=False) target = uint256_from_compact(b47.nBits) @@ -586,35 +609,35 @@ def get_tests(self): b47.rehash() yield self.rejected(RejectResult(16, b'high-hash')) - # A block with timestamp > 2 hrs in the future + self.log.info("Reject a block with a timestamp >2 hours in the future") self.move_tip(44) b48 = self.next_block(48, solve=False) b48.nTime = int(time.time()) + 60 * 60 * 3 b48.solve() yield self.rejected(RejectResult(16, b'time-too-new')) - # A block with an invalid merkle hash + self.log.info("Reject a block with invalid merkle hash") self.move_tip(44) b49 = self.next_block(49) b49.hashMerkleRoot += 1 b49.solve() yield self.rejected(RejectResult(16, b'bad-txnmrklroot')) - # A block with an incorrect POW limit + self.log.info("Reject a block with incorrect POW limit") self.move_tip(44) b50 = self.next_block(50) b50.nBits = b50.nBits - 1 b50.solve() yield self.rejected(RejectResult(16, b'bad-diffbits')) - # A block with two coinbase txns + self.log.info("Reject a block with two coinbase transactions") self.move_tip(44) self.next_block(51) cb2 = create_coinbase(51, self.coinbase_pubkey) self.update_block(51, [cb2]) yield self.rejected(RejectResult(16, b'bad-cb-multiple')) - # A block w/ duplicate txns + self.log.info("Reject a block with duplicate transactions") # Note: txns have to be in the right position in the merkle tree to trigger this error self.move_tip(44) b52 = self.next_block(52, spend=out[15]) @@ -631,7 +654,7 @@ def get_tests(self): yield self.rejected() # rejected since b44 is at same height self.save_spendable_output() - # invalid timestamp (b35 is 5 blocks back, so its time is MedianTimePast) + self.log.info("Reject a block with timestamp before MedianTimePast") b54 = self.next_block(54, spend=out[15]) b54.nTime = b35.nTime - 1 b54.solve() @@ -680,6 +703,7 @@ def get_tests(self): b57 = self.update_block(57, [tx, tx1]) # b56 - copy b57, add a duplicate tx + self.log.info("Reject a block with a duplicate transaction in the Merkle Tree (but with a valid Merkle Root)") self.move_tip(55) b56 = copy.deepcopy(b57) self.blocks[56] = b56 @@ -699,6 +723,7 @@ def get_tests(self): b57p2 = self.update_block("57p2", [tx, tx1, tx2, tx3, tx4]) # b56p2 - copy b57p2, duplicate two non-consecutive tx's + self.log.info("Reject a block with two duplicate transactions in the Merkle Tree (but with a valid Merkle Root)") self.move_tip(55) b56p2 = copy.deepcopy(b57p2) self.blocks["b56p2"] = b56p2 @@ -721,6 +746,7 @@ def get_tests(self): # # tx with prevout.n out of range + self.log.info("Reject a block with a transaction with prevout.n out of range") self.move_tip(57) self.next_block(58, spend=out[17]) tx = CTransaction() @@ -732,6 +758,7 @@ def get_tests(self): yield self.rejected(RejectResult(16, b'bad-txns-inputs-missingorspent')) # tx with output value > input value out of range + self.log.info("Reject a block with a transaction with outputs > inputs") self.move_tip(57) self.next_block(59) tx = self.create_and_sign_transaction(out[17].tx, out[17].n, 51 * COIN) @@ -753,6 +780,7 @@ def get_tests(self): # not-fully-spent transaction in the same chain. To test, make identical coinbases; # the second one should be rejected. # + self.log.info("Reject a block with a transaction with a duplicate hash of a previous transaction (BIP30)") self.move_tip(60) b61 = self.next_block(61, spend=out[18]) b61.vtx[0].vin[0].scriptSig = b60.vtx[0].vin[0].scriptSig # equalize the coinbases @@ -766,6 +794,7 @@ def get_tests(self): # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) # \-> b62 (18) # + self.log.info("Reject a block with a transaction with a nonfinal locktime") self.move_tip(60) self.next_block(62) tx = CTransaction() @@ -783,6 +812,7 @@ def get_tests(self): # -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) # \-> b63 (-) # + self.log.info("Reject a block with a coinbase transaction with a nonfinal locktime") self.move_tip(60) b63 = self.next_block(63) b63.vtx[0].nLockTime = 0xffffffff @@ -805,6 +835,7 @@ def get_tests(self): # b64a is a bloated block (non-canonical varint) # b64 is a good block (same as b64 but w/ canonical varint) # + self.log.info("Accept a valid block even if a bloated version of the block has previously been sent") self.move_tip(60) regular_block = self.next_block("64a", spend=out[18]) @@ -841,6 +872,7 @@ def get_tests(self): # # -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) # + self.log.info("Accept a block with a transaction spending an output created in the same block") self.move_tip(64) self.next_block(65) tx1 = self.create_and_sign_transaction(out[19].tx, out[19].n, out[19].tx.vout[0].nValue) @@ -853,6 +885,7 @@ def get_tests(self): # # -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) # \-> b66 (20) + self.log.info("Reject a block with a transaction spending an output created later in the same block") self.move_tip(65) self.next_block(66) tx1 = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue) @@ -866,6 +899,7 @@ def get_tests(self): # \-> b67 (20) # # + self.log.info("Reject a block with a transaction double spending a transaction creted in the same block") self.move_tip(65) self.next_block(67) tx1 = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue) @@ -886,12 +920,14 @@ def get_tests(self): # b69 - coinbase with extra 10 satoshis, and a tx that gives a 10 satoshi fee # this succeeds # + self.log.info("Reject a block trying to claim too much subsidy in the coinbase transaction") self.move_tip(65) self.next_block(68, additional_coinbase_value=10) tx = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 9) self.update_block(68, [tx]) yield self.rejected(RejectResult(16, b'bad-cb-amount')) + self.log.info("Accept a block claiming the correct subsidy in the coinbase transaction") self.move_tip(65) b69 = self.next_block(69, additional_coinbase_value=10) tx = self.create_and_sign_transaction(out[20].tx, out[20].n, out[20].tx.vout[0].nValue - 10) @@ -904,6 +940,7 @@ def get_tests(self): # -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) # \-> b70 (21) # + self.log.info("Reject a block containing a transaction spending from a non-existent input") self.move_tip(69) self.next_block(70, spend=out[21]) bogus_tx = CTransaction() @@ -921,7 +958,7 @@ def get_tests(self): # # b72 is a good block. # b71 is a copy of 72, but re-adds one of its transactions. However, it has the same hash as b71. - # + self.log.info("Reject a block containing a duplicate transaction but with the same Merkle root (Merkle tree malleability") self.move_tip(69) b72 = self.next_block(72) tx1 = self.create_and_sign_transaction(out[21].tx, out[21].n, 2) @@ -958,7 +995,7 @@ def get_tests(self): # bytearray[20,000-20,003]: 521 (max_script_element_size+1, in little-endian format) # bytearray[20,004-20,525]: unread data (script_element) # bytearray[20,526] : OP_CHECKSIG (this puts us over the limit) - # + self.log.info("Reject a block containing too many sigops after a large script element") self.move_tip(72) b73 = self.next_block(73) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 1 @@ -986,8 +1023,7 @@ def get_tests(self): # # b74 fails because we put MAX_BLOCK_SIGOPS+1 before the element # b75 succeeds because we put MAX_BLOCK_SIGOPS before the element - # - # + self.log.info("Check sigops are counted correctly after an invalid script element") self.move_tip(72) self.next_block(74) size = MAX_BLOCK_SIGOPS - 1 + MAX_SCRIPT_ELEMENT_SIZE + 42 # total = 20,561 @@ -1043,7 +1079,7 @@ def get_tests(self): # To get around this issue, we construct transactions which are not signed and which # spend to OP_TRUE. If the standard-ness rules change, this test would need to be # updated. (Perhaps to spend to a P2SH OP_TRUE script) - # + self.log.info("Test transaction resurrection during a re-org") self.move_tip(76) self.next_block(77) tx77 = self.create_and_sign_transaction(out[24].tx, out[24].n, 10 * COIN) @@ -1087,6 +1123,7 @@ def get_tests(self): # # -> b81 (26) -> b82 (27) -> b83 (28) # + self.log.info("Accept a block with invalid opcodes in dead execution paths") self.next_block(83) op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF] script = CScript(op_codes) @@ -1105,7 +1142,7 @@ def get_tests(self): # -> b81 (26) -> b82 (27) -> b83 (28) -> b84 (29) -> b87 (30) -> b88 (31) # \-> b85 (29) -> b86 (30) \-> b89a (32) # - # + self.log.info("Test re-orging blocks with OP_RETURN in them") self.next_block(84) tx1 = self.create_tx(out[29].tx, out[29].n, 0, CScript([OP_RETURN])) tx1.vout.append(CTxOut(0, CScript([OP_TRUE]))) @@ -1149,6 +1186,8 @@ def get_tests(self): self.update_block("89a", [tx]) yield self.rejected() + self.log.info("Test a re-org of one week's worth of blocks (1088 blocks)") + self.move_tip(88) LARGE_REORG_SIZE = 1088 test1 = TestInstance(sync_every_block=False) From 045eeb887092a631d49194e743859b1da84c1d5d Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Fri, 20 Oct 2017 13:27:55 -0400 Subject: [PATCH 037/900] Rename account to label where appropriate This change only updates strings and adds RPC aliases, but should simplify the implementation of address labels in https://github.com/bitcoin/bitcoin/pull/7729, by getting renaming out of the way and letting it focus on semantics. The difference between accounts and labels is that labels apply only to addresses, while accounts apply to both addresses and transactions (transactions have "from" and "to" accounts). The code associating accounts with transactions is clumsy and unreliable so we would like get rid of it. --- doc/release-notes.md | 10 ++ src/qt/paymentserver.cpp | 5 +- src/rpc/client.cpp | 4 + src/rpc/protocol.h | 5 +- src/wallet/rpcwallet.cpp | 206 ++++++++++++----------- src/wallet/wallet.cpp | 22 +-- src/wallet/wallet.h | 6 +- test/functional/wallet_accounts.py | 164 +++++++++--------- test/functional/wallet_import_rescan.py | 2 +- test/functional/wallet_listreceivedby.py | 60 +++---- 10 files changed, 253 insertions(+), 231 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index a79012722..b183ee0a5 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -63,6 +63,16 @@ RPC changes - The `createrawtransaction` RPC will now accept an array or dictionary (kept for compatibility) for the `outputs` parameter. This means the order of transaction outputs can be specified by the client. - The `fundrawtransaction` RPC will reject the previously deprecated `reserveChangeKey` option. +- Wallet `getnewaddress` and `addmultisigaddress` RPC `account` named + parameters have been renamed to `label` with no change in behavior. +- Wallet `getlabeladdress`, `getreceivedbylabel`, `listreceivedbylabel`, and + `setlabel` RPCs have been added to replace `getaccountaddress`, + `getreceivedbyaccount`, `listreceivedbyaccount`, and `setaccount` RPCs, + which are now deprecated. There is no change in behavior between the + new RPCs and deprecated RPCs. +- Wallet `listreceivedbylabel`, `listreceivedbyaccount` and `listunspent` RPCs + add `label` fields to returned JSON objects that previously only had + `account` fields. External wallet files --------------------- diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 92d7d7293..1d0b66dfd 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -634,8 +634,6 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& r payment.add_transactions(transaction.data(), transaction.size()); // Create a new refund address, or re-use: - QString account = tr("Refund from %1").arg(recipient.authenticatedMerchant); - std::string strAccount = account.toStdString(); CPubKey newKey; if (wallet->GetKeyFromPool(newKey)) { // BIP70 requests encode the scriptPubKey directly, so we are not restricted to address @@ -646,7 +644,8 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, const SendCoinsRecipient& r const OutputType change_type = wallet->m_default_change_type != OutputType::NONE ? wallet->m_default_change_type : wallet->m_default_address_type; wallet->LearnRelatedScripts(newKey, change_type); CTxDestination dest = GetDestinationForKey(newKey, change_type); - wallet->SetAddressBook(dest, strAccount, "refund"); + std::string label = tr("Refund from %1").arg(recipient.authenticatedMerchant).toStdString(); + wallet->SetAddressBook(dest, label, "refund"); CScript s = GetScriptForDestination(dest); payments::Output* refund_to = payment.add_refund_to(); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 0eeb3f98b..e12685da6 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -40,6 +40,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "settxfee", 0, "amount" }, { "getreceivedbyaddress", 1, "minconf" }, { "getreceivedbyaccount", 1, "minconf" }, + { "getreceivedbylabel", 1, "minconf" }, { "listreceivedbyaddress", 0, "minconf" }, { "listreceivedbyaddress", 1, "include_empty" }, { "listreceivedbyaddress", 2, "include_watchonly" }, @@ -47,6 +48,9 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listreceivedbyaccount", 0, "minconf" }, { "listreceivedbyaccount", 1, "include_empty" }, { "listreceivedbyaccount", 2, "include_watchonly" }, + { "listreceivedbylabel", 0, "minconf" }, + { "listreceivedbylabel", 1, "include_empty" }, + { "listreceivedbylabel", 2, "include_watchonly" }, { "getbalance", 1, "minconf" }, { "getbalance", 2, "include_watchonly" }, { "getblockhash", 0, "height" }, diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 00b92f195..ff63bf490 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -76,7 +76,7 @@ enum RPCErrorCode //! Wallet errors RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.) RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account - RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name + RPC_WALLET_INVALID_LABEL_NAME = -11, //!< Invalid label name RPC_WALLET_KEYPOOL_RAN_OUT = -12, //!< Keypool ran out, call keypoolrefill first RPC_WALLET_UNLOCK_NEEDED = -13, //!< Enter the wallet passphrase with walletpassphrase first RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect @@ -85,6 +85,9 @@ enum RPCErrorCode RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked RPC_WALLET_NOT_FOUND = -18, //!< Invalid wallet specified RPC_WALLET_NOT_SPECIFIED = -19, //!< No wallet specified (error when there are multiple wallets loaded) + + //! Backwards compatible aliases + RPC_WALLET_INVALID_ACCOUNT_NAME = RPC_WALLET_INVALID_LABEL_NAME, }; UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 9aae1a5e5..7c173278c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -124,12 +124,12 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.pushKV(item.first, item.second); } -std::string AccountFromValue(const UniValue& value) +std::string LabelFromValue(const UniValue& value) { - std::string strAccount = value.get_str(); - if (strAccount == "*") - throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name"); - return strAccount; + std::string label = value.get_str(); + if (label == "*") + throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name"); + return label; } UniValue getnewaddress(const JSONRPCRequest& request) @@ -141,12 +141,12 @@ UniValue getnewaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 2) throw std::runtime_error( - "getnewaddress ( \"account\" \"address_type\" )\n" + "getnewaddress ( \"label\" \"address_type\" )\n" "\nReturns a new Bitcoin address for receiving payments.\n" - "If 'account' is specified (DEPRECATED), it is added to the address book \n" - "so payments received with the address will be credited to 'account'.\n" + "If 'label' is specified, it is added to the address book \n" + "so payments received with the address will be associated with 'label'.\n" "\nArguments:\n" - "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n" + "1. \"label\" (string, optional) The label name for the address to be linked to. If not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name.\n" "2. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype.\n" "\nResult:\n" "\"address\" (string) The new bitcoin address\n" @@ -157,10 +157,10 @@ UniValue getnewaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - // Parse the account first so we don't generate a key if there's an error - std::string strAccount; + // Parse the label first so we don't generate a key if there's an error + std::string label; if (!request.params[0].isNull()) - strAccount = AccountFromValue(request.params[0]); + label = LabelFromValue(request.params[0]); OutputType output_type = pwallet->m_default_address_type; if (!request.params[1].isNull()) { @@ -182,23 +182,23 @@ UniValue getnewaddress(const JSONRPCRequest& request) pwallet->LearnRelatedScripts(newKey, output_type); CTxDestination dest = GetDestinationForKey(newKey, output_type); - pwallet->SetAddressBook(dest, strAccount, "receive"); + pwallet->SetAddressBook(dest, label, "receive"); return EncodeDestination(dest); } -CTxDestination GetAccountDestination(CWallet* const pwallet, std::string strAccount, bool bForceNew=false) +CTxDestination GetLabelDestination(CWallet* const pwallet, const std::string& label, bool bForceNew=false) { CTxDestination dest; - if (!pwallet->GetAccountDestination(dest, strAccount, bForceNew)) { + if (!pwallet->GetLabelDestination(dest, label, bForceNew)) { throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); } return dest; } -UniValue getaccountaddress(const JSONRPCRequest& request) +UniValue getlabeladdress(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { @@ -207,27 +207,27 @@ UniValue getaccountaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "getaccountaddress \"account\"\n" - "\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n" + "getlabeladdress \"label\"\n" + "\nReturns the current Bitcoin address for receiving payments to this label.\n" "\nArguments:\n" - "1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n" + "1. \"label\" (string, required) The label name for the address. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created and a new address created if there is no label by the given name.\n" "\nResult:\n" - "\"address\" (string) The account bitcoin address\n" + "\"address\" (string) The label bitcoin address\n" "\nExamples:\n" - + HelpExampleCli("getaccountaddress", "") - + HelpExampleCli("getaccountaddress", "\"\"") - + HelpExampleCli("getaccountaddress", "\"myaccount\"") - + HelpExampleRpc("getaccountaddress", "\"myaccount\"") + + HelpExampleCli("getlabeladdress", "") + + HelpExampleCli("getlabeladdress", "\"\"") + + HelpExampleCli("getlabeladdress", "\"mylabel\"") + + HelpExampleRpc("getlabeladdress", "\"mylabel\"") ); LOCK2(cs_main, pwallet->cs_wallet); - // Parse the account first so we don't generate a key if there's an error - std::string strAccount = AccountFromValue(request.params[0]); + // Parse the label first so we don't generate a key if there's an error + std::string label = LabelFromValue(request.params[0]); UniValue ret(UniValue::VSTR); - ret = EncodeDestination(GetAccountDestination(pwallet, strAccount)); + ret = EncodeDestination(GetLabelDestination(pwallet, label)); return ret; } @@ -281,7 +281,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) } -UniValue setaccount(const JSONRPCRequest& request) +UniValue setlabel(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { @@ -290,14 +290,14 @@ UniValue setaccount(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "setaccount \"address\" \"account\"\n" - "\nDEPRECATED. Sets the account associated with the given address.\n" + "setlabel \"address\" \"label\"\n" + "\nSets the label associated with the given address.\n" "\nArguments:\n" - "1. \"address\" (string, required) The bitcoin address to be associated with an account.\n" - "2. \"account\" (string, required) The account to assign the address to.\n" + "1. \"address\" (string, required) The bitcoin address to be associated with a label.\n" + "2. \"label\" (string, required) The label to assign the address to.\n" "\nExamples:\n" - + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") - + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"") + + HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") + + HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"") ); LOCK2(cs_main, pwallet->cs_wallet); @@ -307,23 +307,23 @@ UniValue setaccount(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); } - std::string strAccount; + std::string label; if (!request.params[1].isNull()) - strAccount = AccountFromValue(request.params[1]); + label = LabelFromValue(request.params[1]); - // Only add the account if the address is yours. + // Only add the label if the address is yours. if (IsMine(*pwallet, dest)) { - // Detect when changing the account of an address that is the 'unused current key' of another account: + // Detect when changing the label of an address that is the 'unused current key' of another label: if (pwallet->mapAddressBook.count(dest)) { - std::string strOldAccount = pwallet->mapAddressBook[dest].name; - if (dest == GetAccountDestination(pwallet, strOldAccount)) { - GetAccountDestination(pwallet, strOldAccount, true); + std::string old_label = pwallet->mapAddressBook[dest].name; + if (dest == GetLabelDestination(pwallet, old_label)) { + GetLabelDestination(pwallet, old_label, true); } } - pwallet->SetAddressBook(dest, strAccount, "receive"); + pwallet->SetAddressBook(dest, label, "receive"); } else - throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); + throw JSONRPCError(RPC_MISC_ERROR, "setlabel can only be used with own address"); return NullUniValue; } @@ -390,7 +390,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - std::string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = LabelFromValue(request.params[0]); // Find all addresses that have the given account UniValue ret(UniValue::VARR); @@ -552,7 +552,7 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) " [\n" " \"address\", (string) The bitcoin address\n" " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n" - " \"account\" (string, optional) DEPRECATED. The account\n" + " \"label\" (string, optional) The label\n" " ]\n" " ,...\n" " ]\n" @@ -720,7 +720,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) } -UniValue getreceivedbyaccount(const JSONRPCRequest& request) +UniValue getreceivedbylabel(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { @@ -729,22 +729,22 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "getreceivedbyaccount \"account\" ( minconf )\n" - "\nDEPRECATED. Returns the total amount received by addresses with in transactions with at least [minconf] confirmations.\n" + "getreceivedbylabel \"label\" ( minconf )\n" + "\nReturns the total amount received by addresses with