From e9c3215b776b07faeb5184249fc0e43876f26723 Mon Sep 17 00:00:00 2001 From: dexX7 Date: Fri, 19 Dec 2014 06:59:16 +0100 Subject: [PATCH 01/81] [Wallet] sort pending wallet transactions before reaccepting During startup, when adding pending wallet transactions, which spend outputs of other pending wallet transactions, back to the memory pool, and when they are added out of order, it appears as if they are orphans with missing inputs. Those transactions are then rejected and flagged as "conflicting" (= not in the memory pool, not in the block chain). To prevent this, transactions are explicitly sorted. --- src/wallet/wallet.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 44b416d49..207bb8c97 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1028,6 +1028,9 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) void CWallet::ReacceptWalletTransactions() { LOCK2(cs_main, cs_wallet); + std::map mapSorted; + + // Sort pending wallet transactions based on their initial wallet insertion order BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) { const uint256& wtxid = item.first; @@ -1036,13 +1039,19 @@ void CWallet::ReacceptWalletTransactions() int nDepth = wtx.GetDepthInMainChain(); - if (!wtx.IsCoinBase() && nDepth < 0) - { - // Try to add to memory pool - LOCK(mempool.cs); - wtx.AcceptToMemoryPool(false); + if (!wtx.IsCoinBase() && nDepth < 0) { + mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); } } + + // Try to add wallet transactions to memory pool + BOOST_FOREACH(PAIRTYPE(const int64_t, CWalletTx*)& item, mapSorted) + { + CWalletTx& wtx = *(item.second); + + LOCK(mempool.cs); + wtx.AcceptToMemoryPool(false); + } } void CWalletTx::RelayWalletTransaction() From 0df67f1f7ab4adfe9f0b3ba6276e737b37826464 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 31 Mar 2015 19:15:42 -0700 Subject: [PATCH 02/81] Simplify hash loop code --- src/miner.cpp | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index cf08b7822..44661fd13 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -365,33 +365,23 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& // // ScanHash scans nonces looking for a hash with at least some zero bits. -// The nonce is usually preserved between calls, but periodically or if the -// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at -// zero. +// The nonce is usually preserved between calls, but periodically the block is +// rebuilt and nNonce starts over at zero. // -bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) +bool static ScanHash(CBlockHeader *pblock, uint256 *phash) { - // Write the first 76 bytes of the block header to a double-SHA256 state. - CHash256 hasher; - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << *pblock; - assert(ss.size() == 80); - hasher.Write((unsigned char*)&ss[0], 76); - while (true) { - nNonce++; + pblock->nNonce++; - // Write the last 4 bytes of the block header (the nonce) to a copy of - // the double-SHA256 state, and compute the result. - CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash); + *phash = (CHashWriter(SER_GETHASH, 0) << *pblock).GetHash(); // Return the nonce if the hash has at least some zero bits, // caller will check if it has enough to reach the target if (((uint16_t*)phash)[15] == 0) return true; - // If nothing found after trying for a while, return -1 - if ((nNonce & 0xfff) == 0) + // If nothing found after trying for a while, return false. + if ((pblock->nNonce & 0xfff) == 0) return false; } } @@ -478,15 +468,13 @@ void static BitcoinMiner(CWallet *pwallet) int64_t nStart = GetTime(); arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); uint256 hash; - uint32_t nNonce = 0; while (true) { // Check if something found - if (ScanHash(pblock, nNonce, &hash)) + if (ScanHash(pblock, &hash)) { if (UintToArith256(hash) <= hashTarget) { // Found a solution - pblock->nNonce = nNonce; assert(hash == pblock->GetHash()); SetThreadPriority(THREAD_PRIORITY_NORMAL); @@ -508,7 +496,7 @@ void static BitcoinMiner(CWallet *pwallet) // Regtest mode doesn't require peers if (vNodes.empty() && Params().MiningRequiresPeers()) break; - if (nNonce >= 0xffff0000) + if (pblock->nNonce >= 0xffff0000) break; if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) break; From 6b04508e37c5dd18cec1cd61cc4356bd208aa991 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 31 Mar 2015 20:28:28 -0700 Subject: [PATCH 03/81] Introduce separate 'generate' RPC call --- qa/rpc-tests/bipdersig.py | 16 ++-- qa/rpc-tests/conflictedbalance.sh | 6 +- qa/rpc-tests/forknotify.py | 8 +- qa/rpc-tests/getblocktemplate_longpoll.py | 6 +- qa/rpc-tests/getblocktemplate_proposals.py | 2 +- qa/rpc-tests/getchaintips.py | 4 +- qa/rpc-tests/invalidateblock.py | 6 +- qa/rpc-tests/listtransactions.py | 2 +- qa/rpc-tests/mempool_coinbase_spends.py | 6 +- qa/rpc-tests/mempool_resurrect_test.py | 6 +- qa/rpc-tests/mempool_spendcoinbase.py | 2 +- qa/rpc-tests/receivedby.py | 6 +- qa/rpc-tests/rest.py | 2 +- qa/rpc-tests/smartfees.py | 6 +- qa/rpc-tests/txn_doublespend.py | 6 +- qa/rpc-tests/util.py | 2 +- qa/rpc-tests/wallet.py | 18 ++--- qa/rpc-tests/walletbackup.py | 12 +-- qa/rpc-tests/zapwallettxes.py | 6 +- src/miner.cpp | 86 ++++++++++++-------- src/miner.h | 2 + src/rpcclient.cpp | 1 + src/rpcmining.cpp | 91 ++++++++++------------ src/rpcserver.cpp | 1 + src/rpcserver.h | 1 + 25 files changed, 162 insertions(+), 142 deletions(-) diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py index 9f2cc8460..2c43bba86 100755 --- a/qa/rpc-tests/bipdersig.py +++ b/qa/rpc-tests/bipdersig.py @@ -29,14 +29,14 @@ class BIP66Test(BitcoinTestFramework): cnt = self.nodes[0].getblockcount() # Mine some old-version blocks - self.nodes[1].setgenerate(True, 100) + self.nodes[1].generate(100) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 100): raise AssertionError("Failed to mine 100 version=2 blocks") # Mine 750 new-version blocks for i in xrange(15): - self.nodes[2].setgenerate(True, 50) + self.nodes[2].generate(50) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 850): raise AssertionError("Failed to mine 750 version=3 blocks") @@ -44,7 +44,7 @@ class BIP66Test(BitcoinTestFramework): # TODO: check that new DERSIG rules are not enforced # Mine 1 new-version block - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 851): raise AssertionFailure("Failed to mine a version=3 blocks") @@ -53,26 +53,26 @@ class BIP66Test(BitcoinTestFramework): # Mine 198 new-version blocks for i in xrange(2): - self.nodes[2].setgenerate(True, 99) + self.nodes[2].generate(99) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 1049): raise AssertionError("Failed to mine 198 version=3 blocks") # Mine 1 old-version block - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 1050): raise AssertionError("Failed to mine a version=2 block after 949 version=3 blocks") # Mine 1 new-version blocks - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 1051): raise AssertionError("Failed to mine a version=3 block") # Mine 1 old-version blocks try: - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks") except JSONRPCException: pass @@ -81,7 +81,7 @@ class BIP66Test(BitcoinTestFramework): raise AssertionError("Accepted a version=2 block after 950 version=3 blocks") # Mine 1 new-version blocks - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 1052): raise AssertionError("Failed to mine a version=3 block") diff --git a/qa/rpc-tests/conflictedbalance.sh b/qa/rpc-tests/conflictedbalance.sh index a112244c7..3b6c8dc31 100755 --- a/qa/rpc-tests/conflictedbalance.sh +++ b/qa/rpc-tests/conflictedbalance.sh @@ -84,11 +84,11 @@ WaitPeers "$B1ARGS" 1 # 2 block, 50 XBT each == 100 XBT # These will be transactions "A" and "B" -$CLI $B1ARGS setgenerate true 2 +$CLI $B1ARGS generate 2 WaitBlocks # 100 blocks, 0 mature == 0 XBT -$CLI $B2ARGS setgenerate true 100 +$CLI $B2ARGS generate 100 WaitBlocks CheckBalance "$B1ARGS" 100 @@ -130,7 +130,7 @@ WaitPeers "$B1ARGS" 1 # Having B2 mine the next block puts the mutated # transaction C in the chain: -$CLI $B2ARGS setgenerate true 1 +$CLI $B2ARGS generate 1 WaitBlocks # B1 should still be able to spend 100, because D is conflicted diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py index ad2a748ca..af22ffb1a 100755 --- a/qa/rpc-tests/forknotify.py +++ b/qa/rpc-tests/forknotify.py @@ -34,12 +34,12 @@ class ForkNotifyTest(BitcoinTestFramework): def run_test(self): # Mine 51 up-version blocks - self.nodes[1].setgenerate(True, 51) + self.nodes[1].generate(51) self.sync_all() # -alertnotify should trigger on the 51'st, # but mine and sync another to give # -alertnotify time to write - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) self.sync_all() with open(self.alert_filename, 'r') as f: @@ -49,9 +49,9 @@ class ForkNotifyTest(BitcoinTestFramework): raise AssertionError("-alertnotify did not warn of up-version blocks") # Mine more up-version blocks, should not get more alerts: - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) self.sync_all() - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) self.sync_all() with open(self.alert_filename, 'r') as f: diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py index b749b260b..64fe49b83 100755 --- a/qa/rpc-tests/getblocktemplate_longpoll.py +++ b/qa/rpc-tests/getblocktemplate_longpoll.py @@ -51,7 +51,7 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): def run_test(self): print "Warning: this test will take about 70 seconds in the best case. Be patient." - self.nodes[0].setgenerate(True, 10) + self.nodes[0].generate(10) templat = self.nodes[0].getblocktemplate() longpollid = templat['longpollid'] # longpollid should not change between successive invocations if nothing else happens @@ -66,7 +66,7 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): assert(thr.is_alive()) # Test 2: test that longpoll will terminate if another node generates a block - self.nodes[1].setgenerate(True, 1) # generate a block on another node + self.nodes[1].generate(1) # generate a block on another node # check that thread will exit now that new transaction entered mempool thr.join(5) # wait 5 seconds or until thread exits assert(not thr.is_alive()) @@ -74,7 +74,7 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): # Test 3: test that longpoll will terminate if we generate a block ourselves thr = LongpollThread(self.nodes[0]) thr.start() - self.nodes[0].setgenerate(True, 1) # generate a block on another node + self.nodes[0].generate(1) # generate a block on another node thr.join(5) # wait 5 seconds or until thread exits assert(not thr.is_alive()) diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py index f65162002..a63f456d6 100755 --- a/qa/rpc-tests/getblocktemplate_proposals.py +++ b/qa/rpc-tests/getblocktemplate_proposals.py @@ -95,7 +95,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] - node.setgenerate(True, 1) # Mine a block to leave initial block download + node.generate(1) # Mine a block to leave initial block download tmpl = node.getblocktemplate() if 'coinbasetxn' not in tmpl: rawcoinbase = encodeUNum(tmpl['height']) diff --git a/qa/rpc-tests/getchaintips.py b/qa/rpc-tests/getchaintips.py index 84fe102d8..83a953728 100755 --- a/qa/rpc-tests/getchaintips.py +++ b/qa/rpc-tests/getchaintips.py @@ -23,8 +23,8 @@ class GetChainTipsTest (BitcoinTestFramework): # Split the network and build two chains of different lengths. self.split_network () - self.nodes[0].setgenerate (True, 10); - self.nodes[2].setgenerate (True, 20); + self.nodes[0].generate(10); + self.nodes[2].generate(20); self.sync_all () tips = self.nodes[1].getchaintips () diff --git a/qa/rpc-tests/invalidateblock.py b/qa/rpc-tests/invalidateblock.py index ccfcf00e3..fd8a8e578 100755 --- a/qa/rpc-tests/invalidateblock.py +++ b/qa/rpc-tests/invalidateblock.py @@ -28,12 +28,12 @@ class InvalidateTest(BitcoinTestFramework): def run_test(self): print "Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:" print "Mine 4 blocks on Node 0" - self.nodes[0].setgenerate(True, 4) + self.nodes[0].generate(4) assert(self.nodes[0].getblockcount() == 4) besthash = self.nodes[0].getbestblockhash() print "Mine competing 6 blocks on Node 1" - self.nodes[1].setgenerate(True, 6) + self.nodes[1].generate(6) assert(self.nodes[1].getblockcount() == 6) print "Connect nodes to force a reorg" @@ -61,7 +61,7 @@ class InvalidateTest(BitcoinTestFramework): self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) assert(self.nodes[2].getblockcount() == 2) print "..and then mine a block" - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) print "Verify all nodes are at the right height" time.sleep(5) for i in xrange(3): diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py index 8ee9d66a2..11e3635c0 100755 --- a/qa/rpc-tests/listtransactions.py +++ b/qa/rpc-tests/listtransactions.py @@ -44,7 +44,7 @@ class ListTransactionsTest(BitcoinTestFramework): {"txid":txid}, {"category":"receive","account":"","amount":Decimal("0.1"),"confirmations":0}) # mine a block, confirmations should change: - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) self.sync_all() check_array_result(self.nodes[0].listtransactions(), {"txid":txid}, diff --git a/qa/rpc-tests/mempool_coinbase_spends.py b/qa/rpc-tests/mempool_coinbase_spends.py index 7b4371276..853d031de 100755 --- a/qa/rpc-tests/mempool_coinbase_spends.py +++ b/qa/rpc-tests/mempool_coinbase_spends.py @@ -41,7 +41,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # Mine three blocks. After this, nodes[0] blocks # 101, 102, and 103 are spend-able. - new_blocks = self.nodes[1].setgenerate(True, 4) + new_blocks = self.nodes[1].generate(4) self.sync_all() node0_address = self.nodes[0].getnewaddress() @@ -62,7 +62,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # Broadcast and mine spend_102 and 103: spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw) spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw) - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) # Create 102_1 and 103_1: spend_102_1_raw = self.create_tx(spend_102_id, node1_address, 50) @@ -70,7 +70,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # Broadcast and mine 103_1: spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) # ... now put spend_101 and spend_102_1 in memory pools: spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw) diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py index 81db812bf..6f7f577e3 100755 --- a/qa/rpc-tests/mempool_resurrect_test.py +++ b/qa/rpc-tests/mempool_resurrect_test.py @@ -51,12 +51,12 @@ class MempoolCoinbaseTest(BitcoinTestFramework): spends1_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw ] blocks = [] - blocks.extend(self.nodes[0].setgenerate(True, 1)) + blocks.extend(self.nodes[0].generate(1)) spends2_raw = [ self.create_tx(txid, node0_address, 49.99) for txid in spends1_id ] spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ] - blocks.extend(self.nodes[0].setgenerate(True, 1)) + blocks.extend(self.nodes[0].generate(1)) # mempool should be empty, all txns confirmed assert_equal(set(self.nodes[0].getrawmempool()), set()) @@ -76,7 +76,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): assert(tx["confirmations"] == 0) # Generate another block, they should all get mined - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) # mempool should be empty, all txns confirmed assert_equal(set(self.nodes[0].getrawmempool()), set()) for txid in spends1_id+spends2_id: diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py index f0b34f290..ab5817c86 100755 --- a/qa/rpc-tests/mempool_spendcoinbase.py +++ b/qa/rpc-tests/mempool_spendcoinbase.py @@ -58,7 +58,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ]) # mine a block, spend_101 should get confirmed - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) assert_equal(set(self.nodes[0].getrawmempool()), set()) # ... and now height 102 can be spent: diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py index d3504e092..1a681e1aa 100755 --- a/qa/rpc-tests/receivedby.py +++ b/qa/rpc-tests/receivedby.py @@ -69,7 +69,7 @@ class ReceivedByTest(BitcoinTestFramework): { }, True) #Bury Tx under 10 block so it will be returned by listreceivedbyaddress - self.nodes[1].setgenerate(True, 10) + self.nodes[1].generate(10) self.sync_all() check_array_result(self.nodes[1].listreceivedbyaddress(), {"address":addr}, @@ -106,7 +106,7 @@ class ReceivedByTest(BitcoinTestFramework): raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance)) #Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress - self.nodes[1].setgenerate(True, 10) + self.nodes[1].generate(10) self.sync_all() balance = self.nodes[1].getreceivedbyaddress(addr) if balance != Decimal("0.1"): @@ -136,7 +136,7 @@ class ReceivedByTest(BitcoinTestFramework): if balance != balance_by_account: raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance)) - self.nodes[1].setgenerate(True, 10) + self.nodes[1].generate(10) self.sync_all() # listreceivedbyaccount should return updated account balance check_array_result(self.nodes[1].listreceivedbyaccount(), diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py index a9d41cf36..9b7008531 100755 --- a/qa/rpc-tests/rest.py +++ b/qa/rpc-tests/rest.py @@ -90,7 +90,7 @@ class RESTTest (BitcoinTestFramework): self.sync_all() # now mine the transactions - newblockhash = self.nodes[1].setgenerate(True, 1) + newblockhash = self.nodes[1].generate(1) self.sync_all() #check if the 3 tx show up in the new block diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py index 0c07ef8a5..4eb8bb484 100755 --- a/qa/rpc-tests/smartfees.py +++ b/qa/rpc-tests/smartfees.py @@ -51,7 +51,7 @@ class EstimateFeeTest(BitcoinTestFramework): # Mine blocks with node2 until the memory pool clears: count_start = self.nodes[2].getblockcount() while len(self.nodes[2].getrawmempool()) > 0: - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) self.sync_all() all_estimates = [ self.nodes[0].estimatefee(i) for i in range(1,20) ] @@ -70,7 +70,7 @@ class EstimateFeeTest(BitcoinTestFramework): Decimal("0.0"), min_fee, 20) tx_kbytes = (len(txhex)/2)/1000.0 fees_per_kb.append(float(fee)/tx_kbytes) - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) self.sync_all() all_estimates = [ self.nodes[0].estimatefee(i) for i in range(1,20) ] @@ -81,7 +81,7 @@ class EstimateFeeTest(BitcoinTestFramework): # Finish by mining a normal-sized block: while len(self.nodes[0].getrawmempool()) > 0: - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) self.sync_all() final_estimates = [ self.nodes[0].estimatefee(i) for i in range(1,20) ] diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py index 942d9fc66..fe9168944 100755 --- a/qa/rpc-tests/txn_doublespend.py +++ b/qa/rpc-tests/txn_doublespend.py @@ -58,7 +58,7 @@ class TxnMallTest(BitcoinTestFramework): # Have node0 mine a block: if (self.options.mine_block): - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) sync_blocks(self.nodes[0:2]) tx1 = self.nodes[0].gettransaction(txid1) @@ -88,11 +88,11 @@ class TxnMallTest(BitcoinTestFramework): # Now give doublespend to miner: mutated_txid = self.nodes[2].sendrawtransaction(doublespend["hex"]) # ... mine a block... - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) # Reconnect the split network, and sync chain: connect_nodes(self.nodes[1], 2) - self.nodes[2].setgenerate(True, 1) # Mine another block to make sure we sync + self.nodes[2].generate(1) # Mine another block to make sure we sync sync_blocks(self.nodes) # Re-fetch transaction info: diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py index ec65f783e..9ecee3195 100644 --- a/qa/rpc-tests/util.py +++ b/qa/rpc-tests/util.py @@ -109,7 +109,7 @@ def initialize_chain(test_dir): for peer in range(4): for j in range(25): set_node_times(rpcs, block_time) - rpcs[peer].setgenerate(True, 1) + rpcs[peer].generate(1) block_time += 10*60 # Must sync before next peer starts generating blocks sync_blocks(rpcs) diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 01e9fa57b..7616625b8 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -40,14 +40,14 @@ class WalletTest (BitcoinTestFramework): def run_test (self): print "Mining blocks..." - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) self.sync_all() - self.nodes[1].setgenerate(True, 101) + self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) @@ -63,11 +63,11 @@ class WalletTest (BitcoinTestFramework): assert_equal(walletinfo['immature_balance'], 0) # Have node0 mine a block, thus they will collect their own fee. - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) self.sync_all() # Have node1 generate 100 blocks (so node0 can recover the fee) - self.nodes[1].setgenerate(True, 100) + self.nodes[1].generate(100) self.sync_all() # node0 should end up with 100 btc in block rewards plus fees, but @@ -96,7 +96,7 @@ class WalletTest (BitcoinTestFramework): self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True) # Have node1 mine a block to confirm transactions: - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) self.sync_all() assert_equal(self.nodes[0].getbalance(), 0) @@ -107,28 +107,28 @@ class WalletTest (BitcoinTestFramework): address = self.nodes[0].getnewaddress("test") self.nodes[2].settxfee(Decimal('0.001')) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('89.99900000')) assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000')) # Send 10 BTC with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('79.99900000')) assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000')) # Sendmany 10 BTC txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", []) - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('69.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000')) # Sendmany 10 BTC with subtract fee from amount txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [address]) - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000')) diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py index 049697c2d..b9fc86223 100755 --- a/qa/rpc-tests/walletbackup.py +++ b/qa/rpc-tests/walletbackup.py @@ -77,7 +77,7 @@ class WalletBackupTest(BitcoinTestFramework): # Have the miner (node3) mine a block. # Must sync mempools before mining. sync_mempools(self.nodes) - self.nodes[3].setgenerate(True, 1) + self.nodes[3].generate(1) # As above, this mirrors the original bash test. def start_three(self): @@ -101,13 +101,13 @@ class WalletBackupTest(BitcoinTestFramework): def run_test(self): logging.info("Generating initial blockchain") - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) sync_blocks(self.nodes) - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) sync_blocks(self.nodes) - self.nodes[2].setgenerate(True, 1) + self.nodes[2].generate(1) sync_blocks(self.nodes) - self.nodes[3].setgenerate(True, 100) + self.nodes[3].generate(100) sync_blocks(self.nodes) assert_equal(self.nodes[0].getbalance(), 50) @@ -134,7 +134,7 @@ class WalletBackupTest(BitcoinTestFramework): self.do_one_round() # Generate 101 more blocks, so any fees paid mature - self.nodes[3].setgenerate(True, 101) + self.nodes[3].generate(101) self.sync_all() balance0 = self.nodes[0].getbalance() diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py index a77357590..045614e94 100755 --- a/qa/rpc-tests/zapwallettxes.py +++ b/qa/rpc-tests/zapwallettxes.py @@ -23,9 +23,9 @@ class ZapWalletTXesTest (BitcoinTestFramework): def run_test (self): print "Mining blocks..." - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) self.sync_all() - self.nodes[1].setgenerate(True, 101) + self.nodes[1].generate(101) self.sync_all() assert_equal(self.nodes[0].getbalance(), 50) @@ -33,7 +33,7 @@ class ZapWalletTXesTest (BitcoinTestFramework): txid0 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) txid1 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) self.sync_all() - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) self.sync_all() txid2 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) diff --git a/src/miner.cpp b/src/miner.cpp index 44661fd13..fdbc47a1c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -372,8 +372,7 @@ bool static ScanHash(CBlockHeader *pblock, uint256 *phash) { while (true) { pblock->nNonce++; - - *phash = (CHashWriter(SER_GETHASH, 0) << *pblock).GetHash(); + *phash = pblock->GetHash(); // Return the nonce if the hash has at least some zero bits, // caller will check if it has enough to reach the target @@ -425,6 +424,56 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese return true; } +bool static ScanLoop(CBlock *pblock, CBlockIndex *pindexPrev, CWallet *pwallet, CReserveKey& reservekey) +{ + UpdateTime(pblock, pindexPrev); + arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + + uint256 hash; + if (ScanHash(pblock, &hash)) { + if (UintToArith256(hash) <= hashTarget) { + // Found a solution + SetThreadPriority(THREAD_PRIORITY_NORMAL); + LogPrintf("BitcoinMiner:\n"); + LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); + ProcessBlockFound(pblock, *pwallet, reservekey); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + + return true; + } + } + + return false; +} + +bool MineBlock(CWallet *pwallet, uint256& hash) +{ + CReserveKey reservekey(pwallet); + unsigned int nExtraNonce = 0; + + while (true) { + CBlockIndex *pindexPrev = chainActive.Tip(); // Actually needs cs_main... + + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + if (!pblocktemplate.get()) { + return false; + } + + CBlock *pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + while (true) { + if (ScanLoop(pblock, pindexPrev, pwallet, reservekey)) { + hash = pblock->GetHash(); + return true; + } + boost::this_thread::interruption_point(); + if (pblock->nNonce >= 0xffff0000) + break; + } + } +} + void static BitcoinMiner(CWallet *pwallet) { LogPrintf("BitcoinMiner started\n"); @@ -448,7 +497,7 @@ void static BitcoinMiner(CWallet *pwallet) // Create new block // unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); + CBlockIndex* pindexPrev = chainActive.Tip(); // Actually needs cs_main... auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); if (!pblocktemplate.get()) @@ -466,30 +515,10 @@ void static BitcoinMiner(CWallet *pwallet) // Search // int64_t nStart = GetTime(); - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - uint256 hash; while (true) { // Check if something found - if (ScanHash(pblock, &hash)) - { - if (UintToArith256(hash) <= hashTarget) - { - // Found a solution - assert(hash == pblock->GetHash()); - - SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("BitcoinMiner:\n"); - LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, *pwallet, reservekey); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - - // In regression test mode, stop mining after a block is found. - if (Params().MineBlocksOnDemand()) - throw boost::thread_interrupted(); - - break; - } - } + if (ScanLoop(pblock, pindexPrev, pwallet, reservekey)) + break; // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); @@ -503,13 +532,6 @@ void static BitcoinMiner(CWallet *pwallet) if (pindexPrev != chainActive.Tip()) break; - // Update nTime every few seconds - UpdateTime(pblock, pindexPrev); - if (Params().AllowMinDifficultyBlocks()) - { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); - } } } } diff --git a/src/miner.h b/src/miner.h index 5d5c9c86c..549658ec1 100644 --- a/src/miner.h +++ b/src/miner.h @@ -24,6 +24,8 @@ struct CBlockTemplate /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); +/** Create a single block */ +bool MineBlock(CWallet *pwallet, uint256& hash); /** Generate a new block, without valid proof-of-work */ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index a45ea9839..428e1049d 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -29,6 +29,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getaddednodeinfo", 0 }, { "setgenerate", 0 }, { "setgenerate", 1 }, + { "generate", 0 }, { "getnetworkhashps", 0 }, { "getnetworkhashps", 1 }, { "sendtoaddress", 1 }, diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index fcba7e222..49c5c3ca5 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -113,6 +113,45 @@ Value getgenerate(const Array& params, bool fHelp) return GetBoolArg("-gen", false); } +Value generate(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "generate numblocks\n" + "\nMine blocks immediately (before the RPC call returns)\n" + "1. numblocks (numeric) How many blocks are generated immediately.\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks\n" + + HelpExampleCli("generate", "11") + ); + + if (pwalletMain == NULL) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); + + int nHeightStart = 0; + int nHeightEnd = 0; + int nHeight = 0; + int nGenerate = params[0].get_int(); + + { // Don't keep cs_main locked + LOCK(cs_main); + nHeightStart = chainActive.Height(); + nHeight = nHeightStart; + nHeightEnd = nHeightStart+nGenerate; + } + Array blockHashes; + while (nHeight < nHeightEnd) { + uint256 hash; + if (!MineBlock(pwalletMain, hash)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); + + ++nHeight; + blockHashes.push_back(hash.GetHex()); + } + return blockHashes; +} Value setgenerate(const Array& params, bool fHelp) { @@ -125,9 +164,6 @@ Value setgenerate(const Array& params, bool fHelp) "\nArguments:\n" "1. generate (boolean, required) Set to true to turn on generation, off to turn off.\n" "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" - " Note: in -regtest mode, genproclimit controls how many blocks are generated immediately.\n" - "\nResult\n" - "[ blockhashes ] (array, -regtest only) hashes of blocks generated\n" "\nExamples:\n" "\nSet the generation on with a limit of one processor\n" + HelpExampleCli("setgenerate", "true 1") + @@ -154,52 +190,9 @@ Value setgenerate(const Array& params, bool fHelp) fGenerate = false; } - // -regtest mode: don't return until nGenProcLimit blocks are generated - if (fGenerate && Params().MineBlocksOnDemand()) - { - int nHeightStart = 0; - int nHeightEnd = 0; - int nHeight = 0; - int nGenerate = (nGenProcLimit > 0 ? nGenProcLimit : 1); - CReserveKey reservekey(pwalletMain); - - { // Don't keep cs_main locked - LOCK(cs_main); - nHeightStart = chainActive.Height(); - nHeight = nHeightStart; - nHeightEnd = nHeightStart+nGenerate; - } - unsigned int nExtraNonce = 0; - Array blockHashes; - while (nHeight < nHeightEnd) - { - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); - if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); - CBlock *pblock = &pblocktemplate->block; - { - LOCK(cs_main); - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); - } - while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { - // Yes, there is a chance every nonce could fail to satisfy the -regtest - // target -- 1 in 2^(2^32). That ain't gonna happen. - ++pblock->nNonce; - } - CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); - ++nHeight; - blockHashes.push_back(pblock->GetHash().GetHex()); - } - return blockHashes; - } - else // Not -regtest: start generate thread, return immediately - { - mapArgs["-gen"] = (fGenerate ? "1" : "0"); - mapArgs ["-genproclimit"] = itostr(nGenProcLimit); - GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); - } + mapArgs["-gen"] = (fGenerate ? "1" : "0"); + mapArgs ["-genproclimit"] = itostr(nGenProcLimit); + GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); return Value::null; } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index d30fa32eb..0fd7769a1 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -312,6 +312,7 @@ static const CRPCCommand vRPCCommands[] = /* Coin generation */ { "generating", "getgenerate", &getgenerate, true, false }, { "generating", "setgenerate", &setgenerate, true, false }, + { "generating", "generate", &generate, true, false }, #endif /* Raw transactions */ diff --git a/src/rpcserver.h b/src/rpcserver.h index 7011d41fc..e7aaed8bd 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -162,6 +162,7 @@ extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fH extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value generate(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp); From e2edf95cd3f43331843676e49a82830128a95050 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 31 Mar 2015 20:35:04 -0700 Subject: [PATCH 04/81] Bugfix: make CreateNewBlock return pindexPrev --- src/miner.cpp | 16 ++++++++-------- src/miner.h | 4 ++-- src/rpcmining.cpp | 4 ++-- src/test/miner_tests.cpp | 27 ++++++++++++++------------- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index fdbc47a1c..7f01918ee 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -87,7 +87,7 @@ void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); } -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) +CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CBlockIndex*& pindexPrev) { // Create new block auto_ptr pblocktemplate(new CBlockTemplate()); @@ -132,7 +132,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { LOCK2(cs_main, mempool.cs); - CBlockIndex* pindexPrev = chainActive.Tip(); + pindexPrev = chainActive.Tip(); const int nHeight = pindexPrev->nHeight + 1; CCoinsViewCache view(pcoinsTip); @@ -385,14 +385,14 @@ bool static ScanHash(CBlockHeader *pblock, uint256 *phash) } } -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) +CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, CBlockIndex*& pindexPrev) { CPubKey pubkey; if (!reservekey.GetReservedKey(pubkey)) return NULL; CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; - return CreateNewBlock(scriptPubKey); + return CreateNewBlock(scriptPubKey, pindexPrev); } static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) @@ -452,9 +452,9 @@ bool MineBlock(CWallet *pwallet, uint256& hash) unsigned int nExtraNonce = 0; while (true) { - CBlockIndex *pindexPrev = chainActive.Tip(); // Actually needs cs_main... + CBlockIndex *pindexPrev; - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pindexPrev)); if (!pblocktemplate.get()) { return false; } @@ -497,9 +497,9 @@ void static BitcoinMiner(CWallet *pwallet) // Create new block // unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); // Actually needs cs_main... + CBlockIndex* pindexPrev; - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pindexPrev)); if (!pblocktemplate.get()) { LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); diff --git a/src/miner.h b/src/miner.h index 549658ec1..00ad29951 100644 --- a/src/miner.h +++ b/src/miner.h @@ -27,8 +27,8 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); /** Create a single block */ bool MineBlock(CWallet *pwallet, uint256& hash); /** Generate a new block, without valid proof-of-work */ -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); +CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CBlockIndex*& pindexPrev); +CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, CBlockIndex*& pindexPrev); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 49c5c3ca5..6f165028d 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -475,7 +475,7 @@ Value getblocktemplate(const Array& params, bool fHelp) // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew = chainActive.Tip(); + CBlockIndex* pindexPrevNew; nStart = GetTime(); // Create new block @@ -485,7 +485,7 @@ Value getblocktemplate(const Array& params, bool fHelp) pblocktemplate = NULL; } CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(scriptDummy); + pblocktemplate = CreateNewBlock(scriptDummy, pindexPrevNew); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 6ab9cb8a4..27c0a08de 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -62,7 +62,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) Checkpoints::fEnabled = false; // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + CBlockIndex* pindexPrev; + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) @@ -90,7 +91,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) delete pblocktemplate; // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -108,7 +109,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; mempool.clear(); @@ -128,14 +129,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; mempool.clear(); // orphan in mempool hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; mempool.clear(); @@ -153,7 +154,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 5900000000LL; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; mempool.clear(); @@ -164,7 +165,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; mempool.clear(); @@ -182,7 +183,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; mempool.clear(); @@ -196,17 +197,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; mempool.clear(); // subsidy changing int nHeight = chainActive.Height(); chainActive.Tip()->nHeight = 209999; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; chainActive.Tip()->nHeight = 210000; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); delete pblocktemplate; chainActive.Tip()->nHeight = nHeight; @@ -238,7 +239,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11)); BOOST_CHECK(!IsFinalTx(tx2)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); // Neither tx should have make it into the template. BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); @@ -251,7 +252,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 1)); BOOST_CHECK(IsFinalTx(tx2)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3); delete pblocktemplate; From 00dcaf4bebb6e238b5711530a8a5e4f8fdb6b455 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 12 Jan 2015 09:55:48 -0500 Subject: [PATCH 05/81] Change download logic to allow calling getheaders/getdata on inbound peers SendMessages will now call getheaders on both inbound and outbound peers, once the headers chain is close to synced. It will also try downloading blocks from inbound peers once we're out of initial block download (so inbound peers will participate in parallel block fetching for the last day or two of blocks being downloaded). --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3ceacf32e..a74111593 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4459,9 +4459,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle) if (pindexBestHeader == NULL) pindexBestHeader = chainActive.Tip(); bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. - if (!state.fSyncStarted && !pto->fClient && fFetch && !fImporting && !fReindex) { + if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { // Only actively request headers from a single peer, unless we're close to today. - if (nSyncStarted == 0 || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { + if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { state.fSyncStarted = true; nSyncStarted++; CBlockIndex *pindexStart = pindexBestHeader->pprev ? pindexBestHeader->pprev : pindexBestHeader; @@ -4549,7 +4549,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Message: getdata (blocks) // vector vGetData; - if (!pto->fDisconnect && !pto->fClient && fFetch && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vector vToDownload; NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); From f702d1c66df1534d3fad881f4f72160818a8305c Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Wed, 8 Apr 2015 14:31:53 +0200 Subject: [PATCH 06/81] move ThreadFlushWalletDB declaration to walletdb.h --- src/wallet/db.h | 3 --- src/wallet/walletdb.h | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/wallet/db.h b/src/wallet/db.h index 0c2c139d8..790ae5041 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -25,9 +25,6 @@ class COutPoint; extern unsigned int nWalletDBUpdated; -void ThreadFlushWalletDB(const std::string& strWalletFile); - - class CDBEnv { private: diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index a1c38b9d3..e5f64ffaa 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -138,5 +138,6 @@ private: }; bool BackupWallet(const CWallet& wallet, const std::string& strDest); +void ThreadFlushWalletDB(const std::string& strFile); #endif // BITCOIN_WALLETDB_H From 4ac79f99b02e1d288dda353c15f4183180e538df Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 9 Apr 2015 17:36:10 +0200 Subject: [PATCH 07/81] Fix travis after merging #5957 New wallet tests have been added in the meantime and need to be updated to use `generate` instead of `setgenerate`. --- qa/rpc-tests/wallet.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 0301f160c..5f3178c60 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -163,13 +163,13 @@ class WalletTest (BitcoinTestFramework): txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2); txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) - self.nodes[1].setgenerate(True, 1) #mine a block, tx should not be in there + self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000')); #should not be changed because tx was not broadcasted #now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex']) - self.nodes[1].setgenerate(True, 1) + self.nodes[1].generate(1) self.sync_all() txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), Decimal('61.99800000')); #should not be @@ -186,7 +186,7 @@ class WalletTest (BitcoinTestFramework): connect_nodes_bi(self.nodes,0,2) sync_blocks(self.nodes) - self.nodes[0].setgenerate(True, 1) + self.nodes[0].generate(1) sync_blocks(self.nodes) #tx should be added to balance because after restarting the nodes tx should be broadcastet From 48265f3cf4e62b6c6267b3e67c71a8780f2e2cc1 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 10 Apr 2015 07:33:06 +0200 Subject: [PATCH 08/81] Revert mining changes in #5957 This reverts commit e2edf95cd3f43331843676e49a82830128a95050 6b04508e37c5dd18cec1cd61cc4356bd208aa991 0df67f1f7ab4adfe9f0b3ba6276e737b37826464, except the changes to the RPC tests. A `generate` RPC call is introduced based on the old code. --- src/miner.cpp | 122 ++++++++++++++++++--------------------- src/miner.h | 6 +- src/rpcmining.cpp | 33 ++++++++--- src/test/miner_tests.cpp | 27 +++++---- 4 files changed, 97 insertions(+), 91 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 7f01918ee..cf08b7822 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -87,7 +87,7 @@ void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); } -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CBlockIndex*& pindexPrev) +CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { // Create new block auto_ptr pblocktemplate(new CBlockTemplate()); @@ -132,7 +132,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CBlockIndex*& pind { LOCK2(cs_main, mempool.cs); - pindexPrev = chainActive.Tip(); + CBlockIndex* pindexPrev = chainActive.Tip(); const int nHeight = pindexPrev->nHeight + 1; CCoinsViewCache view(pcoinsTip); @@ -365,34 +365,45 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& // // ScanHash scans nonces looking for a hash with at least some zero bits. -// The nonce is usually preserved between calls, but periodically the block is -// rebuilt and nNonce starts over at zero. +// The nonce is usually preserved between calls, but periodically or if the +// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at +// zero. // -bool static ScanHash(CBlockHeader *pblock, uint256 *phash) +bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) { + // Write the first 76 bytes of the block header to a double-SHA256 state. + CHash256 hasher; + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << *pblock; + assert(ss.size() == 80); + hasher.Write((unsigned char*)&ss[0], 76); + while (true) { - pblock->nNonce++; - *phash = pblock->GetHash(); + nNonce++; + + // Write the last 4 bytes of the block header (the nonce) to a copy of + // the double-SHA256 state, and compute the result. + CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash); // Return the nonce if the hash has at least some zero bits, // caller will check if it has enough to reach the target if (((uint16_t*)phash)[15] == 0) return true; - // If nothing found after trying for a while, return false. - if ((pblock->nNonce & 0xfff) == 0) + // If nothing found after trying for a while, return -1 + if ((nNonce & 0xfff) == 0) return false; } } -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, CBlockIndex*& pindexPrev) +CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) { CPubKey pubkey; if (!reservekey.GetReservedKey(pubkey)) return NULL; CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; - return CreateNewBlock(scriptPubKey, pindexPrev); + return CreateNewBlock(scriptPubKey); } static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) @@ -424,56 +435,6 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese return true; } -bool static ScanLoop(CBlock *pblock, CBlockIndex *pindexPrev, CWallet *pwallet, CReserveKey& reservekey) -{ - UpdateTime(pblock, pindexPrev); - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - - uint256 hash; - if (ScanHash(pblock, &hash)) { - if (UintToArith256(hash) <= hashTarget) { - // Found a solution - SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("BitcoinMiner:\n"); - LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, *pwallet, reservekey); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - - return true; - } - } - - return false; -} - -bool MineBlock(CWallet *pwallet, uint256& hash) -{ - CReserveKey reservekey(pwallet); - unsigned int nExtraNonce = 0; - - while (true) { - CBlockIndex *pindexPrev; - - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pindexPrev)); - if (!pblocktemplate.get()) { - return false; - } - - CBlock *pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - while (true) { - if (ScanLoop(pblock, pindexPrev, pwallet, reservekey)) { - hash = pblock->GetHash(); - return true; - } - boost::this_thread::interruption_point(); - if (pblock->nNonce >= 0xffff0000) - break; - } - } -} - void static BitcoinMiner(CWallet *pwallet) { LogPrintf("BitcoinMiner started\n"); @@ -497,9 +458,9 @@ void static BitcoinMiner(CWallet *pwallet) // Create new block // unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev; + CBlockIndex* pindexPrev = chainActive.Tip(); - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pindexPrev)); + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); if (!pblocktemplate.get()) { LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); @@ -515,23 +476,52 @@ void static BitcoinMiner(CWallet *pwallet) // Search // int64_t nStart = GetTime(); + arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + uint256 hash; + uint32_t nNonce = 0; while (true) { // Check if something found - if (ScanLoop(pblock, pindexPrev, pwallet, reservekey)) - break; + if (ScanHash(pblock, nNonce, &hash)) + { + if (UintToArith256(hash) <= hashTarget) + { + // Found a solution + pblock->nNonce = nNonce; + assert(hash == pblock->GetHash()); + + SetThreadPriority(THREAD_PRIORITY_NORMAL); + LogPrintf("BitcoinMiner:\n"); + LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); + ProcessBlockFound(pblock, *pwallet, reservekey); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + + // In regression test mode, stop mining after a block is found. + if (Params().MineBlocksOnDemand()) + throw boost::thread_interrupted(); + + break; + } + } // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); // Regtest mode doesn't require peers if (vNodes.empty() && Params().MiningRequiresPeers()) break; - if (pblock->nNonce >= 0xffff0000) + if (nNonce >= 0xffff0000) break; if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) break; if (pindexPrev != chainActive.Tip()) break; + // Update nTime every few seconds + UpdateTime(pblock, pindexPrev); + if (Params().AllowMinDifficultyBlocks()) + { + // Changing pblock->nTime can change work required on testnet: + hashTarget.SetCompact(pblock->nBits); + } } } } diff --git a/src/miner.h b/src/miner.h index 00ad29951..5d5c9c86c 100644 --- a/src/miner.h +++ b/src/miner.h @@ -24,11 +24,9 @@ struct CBlockTemplate /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); -/** Create a single block */ -bool MineBlock(CWallet *pwallet, uint256& hash); /** Generate a new block, without valid proof-of-work */ -CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CBlockIndex*& pindexPrev); -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, CBlockIndex*& pindexPrev); +CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); +CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 6f165028d..1e6531f68 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -119,6 +119,7 @@ Value generate(const Array& params, bool fHelp) throw runtime_error( "generate numblocks\n" "\nMine blocks immediately (before the RPC call returns)\n" + "\nNote: this function can only be used on the regtest network\n" "1. numblocks (numeric) How many blocks are generated immediately.\n" "\nResult\n" "[ blockhashes ] (array) hashes of blocks generated\n" @@ -129,11 +130,14 @@ Value generate(const Array& params, bool fHelp) if (pwalletMain == NULL) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); + if (!Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); int nHeightStart = 0; int nHeightEnd = 0; int nHeight = 0; int nGenerate = params[0].get_int(); + CReserveKey reservekey(pwalletMain); { // Don't keep cs_main locked LOCK(cs_main); @@ -141,18 +145,33 @@ Value generate(const Array& params, bool fHelp) nHeight = nHeightStart; nHeightEnd = nHeightStart+nGenerate; } + unsigned int nExtraNonce = 0; Array blockHashes; - while (nHeight < nHeightEnd) { - uint256 hash; - if (!MineBlock(pwalletMain, hash)) + while (nHeight < nHeightEnd) + { + auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); - + CBlock *pblock = &pblocktemplate->block; + { + LOCK(cs_main); + IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + } + while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { + // Yes, there is a chance every nonce could fail to satisfy the -regtest + // target -- 1 in 2^(2^32). That ain't gonna happen. + ++pblock->nNonce; + } + CValidationState state; + if (!ProcessNewBlock(state, NULL, pblock)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; - blockHashes.push_back(hash.GetHex()); + blockHashes.push_back(pblock->GetHash().GetHex()); } return blockHashes; } + Value setgenerate(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) @@ -475,7 +494,7 @@ Value getblocktemplate(const Array& params, bool fHelp) // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew; + CBlockIndex* pindexPrevNew = chainActive.Tip(); nStart = GetTime(); // Create new block @@ -485,7 +504,7 @@ Value getblocktemplate(const Array& params, bool fHelp) pblocktemplate = NULL; } CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(scriptDummy, pindexPrevNew); + pblocktemplate = CreateNewBlock(scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 27c0a08de..6ab9cb8a4 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -62,8 +62,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) Checkpoints::fEnabled = false; // Simple block creation, nothing special yet: - CBlockIndex* pindexPrev; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) @@ -91,7 +90,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) delete pblocktemplate; // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -109,7 +108,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -129,14 +128,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); // orphan in mempool hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -154,7 +153,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 5900000000LL; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -165,7 +164,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -183,7 +182,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -197,17 +196,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); // subsidy changing int nHeight = chainActive.Height(); chainActive.Tip()->nHeight = 209999; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = 210000; - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = nHeight; @@ -239,7 +238,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11)); BOOST_CHECK(!IsFinalTx(tx2)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); // Neither tx should have make it into the template. BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1); @@ -252,7 +251,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 1)); BOOST_CHECK(IsFinalTx(tx2)); - BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey, pindexPrev)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3); delete pblocktemplate; From fd311996e877d567a4e34a19b47e94d66e07100a Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 25 Mar 2015 15:00:32 -0400 Subject: [PATCH 09/81] consensus: don't use arith_uint256 in consensus.h Requiring arith_uint256 at such a base level is not good for modularity. --- src/chainparams.cpp | 4 ++-- src/chainparams.h | 3 +-- src/consensus/params.h | 3 +-- src/pow.cpp | 9 +++++---- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8633d51b2..97312b366 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -105,7 +105,7 @@ public: consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; - consensus.powLimit = ~arith_uint256(0) >> 32; + consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; @@ -245,7 +245,7 @@ public: consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; - consensus.powLimit = ~arith_uint256(0) >> 1; + consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; pchMessageStart[2] = 0xb5; diff --git a/src/chainparams.h b/src/chainparams.h index d0613beb4..e5e691cc5 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -6,7 +6,6 @@ #ifndef BITCOIN_CHAINPARAMS_H #define BITCOIN_CHAINPARAMS_H -#include "arith_uint256.h" #include "chainparamsbase.h" #include "checkpoints.h" #include "consensus/params.h" @@ -45,7 +44,7 @@ public: const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } - const arith_uint256& ProofOfWorkLimit() const { return consensus.powLimit; } + const uint256& ProofOfWorkLimit() const { return consensus.powLimit; } int SubsidyHalvingInterval() const { return consensus.nSubsidyHalvingInterval; } int EnforceBlockUpgradeMajority() const { return consensus.nMajorityEnforceBlockUpgrade; } int RejectBlockOutdatedMajority() const { return consensus.nMajorityRejectBlockOutdated; } diff --git a/src/consensus/params.h b/src/consensus/params.h index c4cfa48c7..35d447b71 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -6,7 +6,6 @@ #ifndef BITCOIN_CONSENSUS_CONSENSUS_PARAMS_H #define BITCOIN_CONSENSUS_CONSENSUS_PARAMS_H -#include "arith_uint256.h" #include "uint256.h" namespace Consensus { @@ -21,7 +20,7 @@ struct Params { int nMajorityRejectBlockOutdated; int nMajorityWindow; /** Proof of work parameters */ - arith_uint256 powLimit; + uint256 powLimit; bool fPowAllowMinDifficultyBlocks; int64_t nPowTargetSpacing; int64_t nPowTargetTimespan; diff --git a/src/pow.cpp b/src/pow.cpp index cf7ac387f..fc6ed4f3d 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -13,7 +13,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { - unsigned int nProofOfWorkLimit = params.powLimit.GetCompact(); + unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); // Genesis block if (pindexLast == NULL) @@ -61,6 +61,7 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF nActualTimespan = params.nPowTargetTimespan*4; // Retarget + const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); arith_uint256 bnNew; arith_uint256 bnOld; bnNew.SetCompact(pindexLast->nBits); @@ -68,8 +69,8 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF bnNew *= nActualTimespan; bnNew /= params.nPowTargetTimespan; - if (bnNew > params.powLimit) - bnNew = params.powLimit; + if (bnNew > bnPowLimit) + bnNew = bnPowLimit; /// debug print LogPrintf("GetNextWorkRequired RETARGET\n"); @@ -89,7 +90,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& bnTarget.SetCompact(nBits, &fNegative, &fOverflow); // Check range - if (fNegative || bnTarget == 0 || fOverflow || bnTarget > params.powLimit) + if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) return error("CheckProofOfWork(): nBits below minimum work"); // Check proof of work matches claimed amount From 0b9dc9c8f5943a8389faa1fd0e52fa5ac6a4a759 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sun, 12 Apr 2015 17:56:32 +0200 Subject: [PATCH 10/81] [move] move listunspent to wallet/rpcwallet.cpp --- src/rpcrawtransaction.cpp | 111 ------------------------------------- src/wallet/rpcwallet.cpp | 112 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 111 deletions(-) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index a79b4e339..c979217a1 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -193,117 +193,6 @@ Value getrawtransaction(const Array& params, bool fHelp) return result; } -#ifdef ENABLE_WALLET -Value listunspent(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 3) - throw runtime_error( - "listunspent ( minconf maxconf [\"address\",...] )\n" - "\nReturns array of unspent transaction outputs\n" - "with between minconf and maxconf (inclusive) confirmations.\n" - "Optionally filter to only include txouts paid to specified addresses.\n" - "Results are an array of Objects, each of which has:\n" - "{txid, vout, scriptPubKey, amount, confirmations}\n" - "\nArguments:\n" - "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" - "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" - "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n" - " [\n" - " \"address\" (string) bitcoin address\n" - " ,...\n" - " ]\n" - "\nResult\n" - "[ (array of json object)\n" - " {\n" - " \"txid\" : \"txid\", (string) the transaction id \n" - " \"vout\" : n, (numeric) the vout value\n" - " \"address\" : \"address\", (string) the bitcoin address\n" - " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n" - " \"scriptPubKey\" : \"key\", (string) the script key\n" - " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" - " \"confirmations\" : n (numeric) The number of confirmations\n" - " }\n" - " ,...\n" - "]\n" - - "\nExamples\n" - + HelpExampleCli("listunspent", "") - + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") - + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") - ); - - RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type)); - - int nMinDepth = 1; - if (params.size() > 0) - nMinDepth = params[0].get_int(); - - int nMaxDepth = 9999999; - if (params.size() > 1) - nMaxDepth = params[1].get_int(); - - set setAddress; - if (params.size() > 2) { - Array inputs = params[2].get_array(); - BOOST_FOREACH(Value& input, inputs) { - CBitcoinAddress address(input.get_str()); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str()); - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); - setAddress.insert(address); - } - } - - Array results; - vector vecOutputs; - assert(pwalletMain != NULL); - LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->AvailableCoins(vecOutputs, false); - BOOST_FOREACH(const COutput& out, vecOutputs) { - if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) - continue; - - if (setAddress.size()) { - CTxDestination address; - if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) - continue; - - if (!setAddress.count(address)) - continue; - } - - CAmount nValue = out.tx->vout[out.i].nValue; - const CScript& pk = out.tx->vout[out.i].scriptPubKey; - Object entry; - entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); - entry.push_back(Pair("vout", out.i)); - CTxDestination address; - if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { - entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); - if (pwalletMain->mapAddressBook.count(address)) - entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); - } - entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); - if (pk.IsPayToScriptHash()) { - CTxDestination address; - if (ExtractDestination(pk, address)) { - const CScriptID& hash = boost::get(address); - CScript redeemScript; - if (pwalletMain->GetCScript(hash, redeemScript)) - entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); - } - } - entry.push_back(Pair("amount",ValueFromAmount(nValue))); - entry.push_back(Pair("confirmations",out.nDepth)); - entry.push_back(Pair("spendable", out.fSpendable)); - results.push_back(entry); - } - - return results; -} -#endif - Value createrawtransaction(const Array& params, bool fHelp) { if (fHelp || params.size() != 2) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 29f3eda15..f94a2ce8e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2118,3 +2118,115 @@ Value resendwallettransactions(const Array& params, bool fHelp) } return result; } + +Value listunspent(const Array& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + + if (fHelp || params.size() > 3) + throw runtime_error( + "listunspent ( minconf maxconf [\"address\",...] )\n" + "\nReturns array of unspent transaction outputs\n" + "with between minconf and maxconf (inclusive) confirmations.\n" + "Optionally filter to only include txouts paid to specified addresses.\n" + "Results are an array of Objects, each of which has:\n" + "{txid, vout, scriptPubKey, amount, confirmations}\n" + "\nArguments:\n" + "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" + "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" + "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n" + " [\n" + " \"address\" (string) bitcoin address\n" + " ,...\n" + " ]\n" + "\nResult\n" + "[ (array of json object)\n" + " {\n" + " \"txid\" : \"txid\", (string) the transaction id \n" + " \"vout\" : n, (numeric) the vout value\n" + " \"address\" : \"address\", (string) the bitcoin address\n" + " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n" + " \"scriptPubKey\" : \"key\", (string) the script key\n" + " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" + " \"confirmations\" : n (numeric) The number of confirmations\n" + " }\n" + " ,...\n" + "]\n" + + "\nExamples\n" + + HelpExampleCli("listunspent", "") + + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + ); + + RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type)); + + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + + int nMaxDepth = 9999999; + if (params.size() > 1) + nMaxDepth = params[1].get_int(); + + set setAddress; + if (params.size() > 2) { + Array inputs = params[2].get_array(); + BOOST_FOREACH(Value& input, inputs) { + CBitcoinAddress address(input.get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str()); + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); + setAddress.insert(address); + } + } + + Array results; + vector vecOutputs; + assert(pwalletMain != NULL); + LOCK2(cs_main, pwalletMain->cs_wallet); + pwalletMain->AvailableCoins(vecOutputs, false); + BOOST_FOREACH(const COutput& out, vecOutputs) { + if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) + continue; + + if (setAddress.size()) { + CTxDestination address; + if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + continue; + + if (!setAddress.count(address)) + continue; + } + + CAmount nValue = out.tx->vout[out.i].nValue; + const CScript& pk = out.tx->vout[out.i].scriptPubKey; + Object entry; + entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); + entry.push_back(Pair("vout", out.i)); + CTxDestination address; + if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { + entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); + if (pwalletMain->mapAddressBook.count(address)) + entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); + } + entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + if (pk.IsPayToScriptHash()) { + CTxDestination address; + if (ExtractDestination(pk, address)) { + const CScriptID& hash = boost::get(address); + CScript redeemScript; + if (pwalletMain->GetCScript(hash, redeemScript)) + entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + } + } + entry.push_back(Pair("amount",ValueFromAmount(nValue))); + entry.push_back(Pair("confirmations",out.nDepth)); + entry.push_back(Pair("spendable", out.fSpendable)); + results.push_back(entry); + } + + return results; +} \ No newline at end of file From b9fb692d04e90967b14c6988553c9121c5eea64e Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sun, 12 Apr 2015 17:56:44 +0200 Subject: [PATCH 11/81] Push down RPC reqWallet flag --- src/init.cpp | 5 -- src/rpcserver.cpp | 177 +++++++++++++++++++-------------------- src/rpcserver.h | 1 - src/wallet/rpcdump.cpp | 16 ++++ src/wallet/rpcwallet.cpp | 114 +++++++++++++++++++++++++ 5 files changed, 216 insertions(+), 97 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 53e521983..eb3a3fe58 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -242,11 +242,6 @@ void OnRPCStopped() void OnRPCPreCommand(const CRPCCommand& cmd) { -#ifdef ENABLE_WALLET - if (cmd.reqWallet && !pwalletMain) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); -#endif - // Observe safe mode string strWarning = GetWarnings("rpc"); if (strWarning != "" && !GetBoolArg("-disablesafemode", false) && diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 0fd7769a1..e2df41fe2 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -193,11 +193,6 @@ string CRPCTable::help(string strCommand) const continue; if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand) continue; -#ifdef ENABLE_WALLET - if (pcmd->reqWallet && !pwalletMain) - continue; -#endif - try { Array params; @@ -271,114 +266,114 @@ Value stop(const Array& params, bool fHelp) * Call Table */ static const CRPCCommand vRPCCommands[] = -{ // category name actor (function) okSafeMode reqWallet - // --------------------- ------------------------ ----------------------- ---------- --------- +{ // category name actor (function) okSafeMode + // --------------------- ------------------------ ----------------------- ---------- /* Overall control/query calls */ - { "control", "getinfo", &getinfo, true, false }, /* uses wallet if enabled */ - { "control", "help", &help, true, false }, - { "control", "stop", &stop, true, false }, + { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */ + { "control", "help", &help, true }, + { "control", "stop", &stop, true }, /* P2P networking */ - { "network", "getnetworkinfo", &getnetworkinfo, true, false }, - { "network", "addnode", &addnode, true, false }, - { "network", "getaddednodeinfo", &getaddednodeinfo, true, false }, - { "network", "getconnectioncount", &getconnectioncount, true, false }, - { "network", "getnettotals", &getnettotals, true, false }, - { "network", "getpeerinfo", &getpeerinfo, true, false }, - { "network", "ping", &ping, true, false }, + { "network", "getnetworkinfo", &getnetworkinfo, true }, + { "network", "addnode", &addnode, true }, + { "network", "getaddednodeinfo", &getaddednodeinfo, true }, + { "network", "getconnectioncount", &getconnectioncount, true }, + { "network", "getnettotals", &getnettotals, true }, + { "network", "getpeerinfo", &getpeerinfo, true }, + { "network", "ping", &ping, true }, /* Block chain and UTXO */ - { "blockchain", "getblockchaininfo", &getblockchaininfo, true, false }, - { "blockchain", "getbestblockhash", &getbestblockhash, true, false }, - { "blockchain", "getblockcount", &getblockcount, true, false }, - { "blockchain", "getblock", &getblock, true, false }, - { "blockchain", "getblockhash", &getblockhash, true, false }, - { "blockchain", "getchaintips", &getchaintips, true, false }, - { "blockchain", "getdifficulty", &getdifficulty, true, false }, - { "blockchain", "getmempoolinfo", &getmempoolinfo, true, false }, - { "blockchain", "getrawmempool", &getrawmempool, true, false }, - { "blockchain", "gettxout", &gettxout, true, false }, - { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false }, - { "blockchain", "verifychain", &verifychain, true, false }, + { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, + { "blockchain", "getbestblockhash", &getbestblockhash, true }, + { "blockchain", "getblockcount", &getblockcount, true }, + { "blockchain", "getblock", &getblock, true }, + { "blockchain", "getblockhash", &getblockhash, true }, + { "blockchain", "getchaintips", &getchaintips, true }, + { "blockchain", "getdifficulty", &getdifficulty, true }, + { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, + { "blockchain", "getrawmempool", &getrawmempool, true }, + { "blockchain", "gettxout", &gettxout, true }, + { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true }, + { "blockchain", "verifychain", &verifychain, true }, /* Mining */ - { "mining", "getblocktemplate", &getblocktemplate, true, false }, - { "mining", "getmininginfo", &getmininginfo, true, false }, - { "mining", "getnetworkhashps", &getnetworkhashps, true, false }, - { "mining", "prioritisetransaction", &prioritisetransaction, true, false }, - { "mining", "submitblock", &submitblock, true, false }, + { "mining", "getblocktemplate", &getblocktemplate, true }, + { "mining", "getmininginfo", &getmininginfo, true }, + { "mining", "getnetworkhashps", &getnetworkhashps, true }, + { "mining", "prioritisetransaction", &prioritisetransaction, true }, + { "mining", "submitblock", &submitblock, true }, #ifdef ENABLE_WALLET /* Coin generation */ - { "generating", "getgenerate", &getgenerate, true, false }, - { "generating", "setgenerate", &setgenerate, true, false }, - { "generating", "generate", &generate, true, false }, + { "generating", "getgenerate", &getgenerate, true }, + { "generating", "setgenerate", &setgenerate, true }, + { "generating", "generate", &generate, true }, #endif /* Raw transactions */ - { "rawtransactions", "createrawtransaction", &createrawtransaction, true, false }, - { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false }, - { "rawtransactions", "decodescript", &decodescript, true, false }, - { "rawtransactions", "getrawtransaction", &getrawtransaction, true, false }, - { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false }, - { "rawtransactions", "signrawtransaction", &signrawtransaction, false, false }, /* uses wallet if enabled */ + { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, + { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true }, + { "rawtransactions", "decodescript", &decodescript, true }, + { "rawtransactions", "getrawtransaction", &getrawtransaction, true }, + { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false }, + { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */ /* Utility functions */ - { "util", "createmultisig", &createmultisig, true, false }, - { "util", "validateaddress", &validateaddress, true, false }, /* uses wallet if enabled */ - { "util", "verifymessage", &verifymessage, true, false }, - { "util", "estimatefee", &estimatefee, true, false }, - { "util", "estimatepriority", &estimatepriority, true, false }, + { "util", "createmultisig", &createmultisig, true }, + { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */ + { "util", "verifymessage", &verifymessage, true }, + { "util", "estimatefee", &estimatefee, true }, + { "util", "estimatepriority", &estimatepriority, true }, /* Not shown in help */ - { "hidden", "invalidateblock", &invalidateblock, true, false }, - { "hidden", "reconsiderblock", &reconsiderblock, true, false }, - { "hidden", "setmocktime", &setmocktime, true, false }, + { "hidden", "invalidateblock", &invalidateblock, true }, + { "hidden", "reconsiderblock", &reconsiderblock, true }, + { "hidden", "setmocktime", &setmocktime, true }, #ifdef ENABLE_WALLET - { "hidden", "resendwallettransactions", &resendwallettransactions, true, true }, + { "hidden", "resendwallettransactions", &resendwallettransactions, true}, #endif #ifdef ENABLE_WALLET /* Wallet */ - { "wallet", "addmultisigaddress", &addmultisigaddress, true, true }, - { "wallet", "backupwallet", &backupwallet, true, true }, - { "wallet", "dumpprivkey", &dumpprivkey, true, true }, - { "wallet", "dumpwallet", &dumpwallet, true, true }, - { "wallet", "encryptwallet", &encryptwallet, true, true }, - { "wallet", "getaccountaddress", &getaccountaddress, true, true }, - { "wallet", "getaccount", &getaccount, true, true }, - { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, true }, - { "wallet", "getbalance", &getbalance, false, true }, - { "wallet", "getnewaddress", &getnewaddress, true, true }, - { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, true }, - { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, true }, - { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, true }, - { "wallet", "gettransaction", &gettransaction, false, true }, - { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, true }, - { "wallet", "getwalletinfo", &getwalletinfo, false, true }, - { "wallet", "importprivkey", &importprivkey, true, true }, - { "wallet", "importwallet", &importwallet, true, true }, - { "wallet", "importaddress", &importaddress, true, true }, - { "wallet", "keypoolrefill", &keypoolrefill, true, true }, - { "wallet", "listaccounts", &listaccounts, false, true }, - { "wallet", "listaddressgroupings", &listaddressgroupings, false, true }, - { "wallet", "listlockunspent", &listlockunspent, false, true }, - { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, true }, - { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, true }, - { "wallet", "listsinceblock", &listsinceblock, false, true }, - { "wallet", "listtransactions", &listtransactions, false, true }, - { "wallet", "listunspent", &listunspent, false, true }, - { "wallet", "lockunspent", &lockunspent, true, true }, - { "wallet", "move", &movecmd, false, true }, - { "wallet", "sendfrom", &sendfrom, false, true }, - { "wallet", "sendmany", &sendmany, false, true }, - { "wallet", "sendtoaddress", &sendtoaddress, false, true }, - { "wallet", "setaccount", &setaccount, true, true }, - { "wallet", "settxfee", &settxfee, true, true }, - { "wallet", "signmessage", &signmessage, true, true }, - { "wallet", "walletlock", &walletlock, true, true }, - { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, true }, - { "wallet", "walletpassphrase", &walletpassphrase, true, true }, + { "wallet", "addmultisigaddress", &addmultisigaddress, true }, + { "wallet", "backupwallet", &backupwallet, true }, + { "wallet", "dumpprivkey", &dumpprivkey, true }, + { "wallet", "dumpwallet", &dumpwallet, true }, + { "wallet", "encryptwallet", &encryptwallet, true }, + { "wallet", "getaccountaddress", &getaccountaddress, true }, + { "wallet", "getaccount", &getaccount, true }, + { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true }, + { "wallet", "getbalance", &getbalance, false }, + { "wallet", "getnewaddress", &getnewaddress, true }, + { "wallet", "getrawchangeaddress", &getrawchangeaddress, true }, + { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false }, + { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false }, + { "wallet", "gettransaction", &gettransaction, false }, + { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false }, + { "wallet", "getwalletinfo", &getwalletinfo, false }, + { "wallet", "importprivkey", &importprivkey, true }, + { "wallet", "importwallet", &importwallet, true }, + { "wallet", "importaddress", &importaddress, true }, + { "wallet", "keypoolrefill", &keypoolrefill, true }, + { "wallet", "listaccounts", &listaccounts, false }, + { "wallet", "listaddressgroupings", &listaddressgroupings, false }, + { "wallet", "listlockunspent", &listlockunspent, false }, + { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false }, + { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false }, + { "wallet", "listsinceblock", &listsinceblock, false }, + { "wallet", "listtransactions", &listtransactions, false }, + { "wallet", "listunspent", &listunspent, false }, + { "wallet", "lockunspent", &lockunspent, true }, + { "wallet", "move", &movecmd, false }, + { "wallet", "sendfrom", &sendfrom, false }, + { "wallet", "sendmany", &sendmany, false }, + { "wallet", "sendtoaddress", &sendtoaddress, false }, + { "wallet", "setaccount", &setaccount, true }, + { "wallet", "settxfee", &settxfee, true }, + { "wallet", "signmessage", &signmessage, true }, + { "wallet", "walletlock", &walletlock, true }, + { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, + { "wallet", "walletpassphrase", &walletpassphrase, true }, #endif // ENABLE_WALLET }; diff --git a/src/rpcserver.h b/src/rpcserver.h index e7aaed8bd..c3200d8c3 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -98,7 +98,6 @@ public: std::string name; rpcfn_type actor; bool okSafeMode; - bool reqWallet; }; /** diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index b9c92a06c..ab951d1d7 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -25,6 +25,7 @@ using namespace json_spirit; using namespace std; void EnsureWalletIsUnlocked(); +bool EnsureWalletIsAvailable(bool avoidException); std::string static EncodeDumpTime(int64_t nTime) { return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); @@ -71,6 +72,9 @@ std::string DecodeDumpString(const std::string &str) { Value importprivkey(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( "importprivkey \"bitcoinprivkey\" ( \"label\" rescan )\n" @@ -142,6 +146,9 @@ Value importprivkey(const Array& params, bool fHelp) Value importaddress(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( "importaddress \"address\" ( \"label\" rescan )\n" @@ -212,6 +219,9 @@ Value importaddress(const Array& params, bool fHelp) Value importwallet(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 1) throw runtime_error( "importwallet \"filename\"\n" @@ -313,6 +323,9 @@ Value importwallet(const Array& params, bool fHelp) Value dumpprivkey(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 1) throw runtime_error( "dumpprivkey \"bitcoinaddress\"\n" @@ -348,6 +361,9 @@ Value dumpprivkey(const Array& params, bool fHelp) Value dumpwallet(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 1) throw runtime_error( "dumpwallet \"filename\"\n" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f94a2ce8e..2c3507fb3 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -37,6 +37,18 @@ std::string HelpRequiringPassphrase() : ""; } +bool EnsureWalletIsAvailable(bool avoidException) +{ + if (!pwalletMain) + { + if (!avoidException) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); + else + return false; + } + return true; +} + void EnsureWalletIsUnlocked() { if (pwalletMain->IsLocked()) @@ -77,6 +89,9 @@ string AccountFromValue(const Value& value) Value getnewaddress(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 1) throw runtime_error( "getnewaddress ( \"account\" )\n" @@ -153,6 +168,9 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false) Value getaccountaddress(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 1) throw runtime_error( "getaccountaddress \"account\"\n" @@ -182,6 +200,9 @@ Value getaccountaddress(const Array& params, bool fHelp) Value getrawchangeaddress(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 1) throw runtime_error( "getrawchangeaddress\n" @@ -214,6 +235,9 @@ Value getrawchangeaddress(const Array& params, bool fHelp) Value setaccount(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "setaccount \"bitcoinaddress\" \"account\"\n" @@ -257,6 +281,9 @@ Value setaccount(const Array& params, bool fHelp) Value getaccount(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 1) throw runtime_error( "getaccount \"bitcoinaddress\"\n" @@ -286,6 +313,9 @@ Value getaccount(const Array& params, bool fHelp) Value getaddressesbyaccount(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 1) throw runtime_error( "getaddressesbyaccount \"account\"\n" @@ -351,6 +381,9 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr Value sendtoaddress(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 2 || params.size() > 5) throw runtime_error( "sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n" @@ -404,6 +437,9 @@ Value sendtoaddress(const Array& params, bool fHelp) Value listaddressgroupings(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp) throw runtime_error( "listaddressgroupings\n" @@ -453,6 +489,9 @@ Value listaddressgroupings(const Array& params, bool fHelp) Value signmessage(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 2) throw runtime_error( "signmessage \"bitcoinaddress\" \"message\"\n" @@ -506,6 +545,9 @@ Value signmessage(const Array& params, bool fHelp) Value getreceivedbyaddress(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n" @@ -561,6 +603,9 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) Value getreceivedbyaccount(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getreceivedbyaccount \"account\" ( minconf )\n" @@ -647,6 +692,9 @@ CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminef Value getbalance(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 3) throw runtime_error( "getbalance ( \"account\" minconf includeWatchonly )\n" @@ -719,6 +767,9 @@ Value getbalance(const Array& params, bool fHelp) Value getunconfirmedbalance(const Array ¶ms, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 0) throw runtime_error( "getunconfirmedbalance\n" @@ -732,6 +783,9 @@ Value getunconfirmedbalance(const Array ¶ms, bool fHelp) Value movecmd(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 3 || params.size() > 5) throw runtime_error( "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" @@ -799,6 +853,9 @@ Value movecmd(const Array& params, bool fHelp) Value sendfrom(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 3 || params.size() > 6) throw runtime_error( "sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n" @@ -859,6 +916,9 @@ Value sendfrom(const Array& params, bool fHelp) Value sendmany(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 2 || params.size() > 5) throw runtime_error( "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n" @@ -965,6 +1025,9 @@ extern CScript _createmultisig_redeemScript(const Array& params); Value addmultisigaddress(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 2 || params.size() > 3) { string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" @@ -1143,6 +1206,9 @@ Value ListReceived(const Array& params, bool fByAccounts) Value listreceivedbyaddress(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 3) throw runtime_error( "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n" @@ -1177,6 +1243,9 @@ Value listreceivedbyaddress(const Array& params, bool fHelp) Value listreceivedbyaccount(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 3) throw runtime_error( "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n" @@ -1304,6 +1373,9 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar Value listtransactions(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 4) throw runtime_error( "listtransactions ( \"account\" count from includeWatchonly)\n" @@ -1415,6 +1487,9 @@ Value listtransactions(const Array& params, bool fHelp) Value listaccounts(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 2) throw runtime_error( "listaccounts ( minconf includeWatchonly)\n" @@ -1492,6 +1567,9 @@ Value listaccounts(const Array& params, bool fHelp) Value listsinceblock(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp) throw runtime_error( "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n" @@ -1580,6 +1658,9 @@ Value listsinceblock(const Array& params, bool fHelp) Value gettransaction(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "gettransaction \"txid\" ( includeWatchonly )\n" @@ -1655,6 +1736,9 @@ Value gettransaction(const Array& params, bool fHelp) Value backupwallet(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 1) throw runtime_error( "backupwallet \"destination\"\n" @@ -1678,6 +1762,9 @@ Value backupwallet(const Array& params, bool fHelp) Value keypoolrefill(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 1) throw runtime_error( "keypoolrefill ( newsize )\n" @@ -1719,6 +1806,9 @@ static void LockWallet(CWallet* pWallet) Value walletpassphrase(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) throw runtime_error( "walletpassphrase \"passphrase\" timeout\n" @@ -1776,6 +1866,9 @@ Value walletpassphrase(const Array& params, bool fHelp) Value walletpassphrasechange(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) throw runtime_error( "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n" @@ -1819,6 +1912,9 @@ Value walletpassphrasechange(const Array& params, bool fHelp) Value walletlock(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) throw runtime_error( "walletlock\n" @@ -1855,6 +1951,9 @@ Value walletlock(const Array& params, bool fHelp) Value encryptwallet(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) throw runtime_error( "encryptwallet \"passphrase\"\n" @@ -1909,6 +2008,9 @@ Value encryptwallet(const Array& params, bool fHelp) Value lockunspent(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n" @@ -1990,6 +2092,9 @@ Value lockunspent(const Array& params, bool fHelp) Value listlockunspent(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() > 0) throw runtime_error( "listlockunspent\n" @@ -2036,6 +2141,9 @@ Value listlockunspent(const Array& params, bool fHelp) Value settxfee(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() < 1 || params.size() > 1) throw runtime_error( "settxfee amount\n" @@ -2062,6 +2170,9 @@ Value settxfee(const Array& params, bool fHelp) Value getwalletinfo(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 0) throw runtime_error( "getwalletinfo\n" @@ -2099,6 +2210,9 @@ Value getwalletinfo(const Array& params, bool fHelp) Value resendwallettransactions(const Array& params, bool fHelp) { + if (!EnsureWalletIsAvailable(fHelp)) + return Value::null; + if (fHelp || params.size() != 0) throw runtime_error( "resendwallettransactions\n" From 4e382177eda203e799310350ffb2efc28d010799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Thu, 9 Apr 2015 15:58:34 +0200 Subject: [PATCH 12/81] Chainparams: Refactor: Remove redundant HashGenesisBlock() getter --- src/chainparams.h | 1 - src/init.cpp | 7 ++++--- src/main.cpp | 17 +++++++++++------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/chainparams.h b/src/chainparams.h index d0613beb4..03b4be8e1 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -41,7 +41,6 @@ public: }; const Consensus::Params& GetConsensus() const { return consensus; } - const uint256& HashGenesisBlock() const { return consensus.hashGenesisBlock; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } diff --git a/src/init.cpp b/src/init.cpp index 53e521983..0d98b2b92 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -607,6 +607,7 @@ bool AppInit2(boost::thread_group& threadGroup) #endif // ********************************************************* Step 2: parameter interactions + const CChainParams& chainparams = Params(); // Set this early so that parameter interactions go to console fPrintToConsole = GetBoolArg("-printtoconsole", false); @@ -699,8 +700,8 @@ bool AppInit2(boost::thread_group& threadGroup) InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench.")); // Checkmempool and checkblockindex default to true in regtest mode - mempool.setSanityCheck(GetBoolArg("-checkmempool", Params().DefaultConsistencyChecks())); - fCheckBlockIndex = GetBoolArg("-checkblockindex", Params().DefaultConsistencyChecks()); + mempool.setSanityCheck(GetBoolArg("-checkmempool", chainparams.DefaultConsistencyChecks())); + fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); Checkpoints::fEnabled = GetBoolArg("-checkpoints", true); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency @@ -1043,7 +1044,7 @@ bool AppInit2(boost::thread_group& threadGroup) // If the loaded chain has a wrong genesis, bail out immediately // (we're likely using a testnet datadir, or the other way around). - if (!mapBlockIndex.empty() && mapBlockIndex.count(Params().HashGenesisBlock()) == 0) + if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); // Initialize the block index (no-op if non-empty database was already loaded) diff --git a/src/main.cpp b/src/main.cpp index 8fb676630..247c2c786 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1680,6 +1680,7 @@ static int64_t nTimeTotal = 0; bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { + const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); // Check it again in case a previous version let a bad block in if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) @@ -1691,7 +1692,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) - if (block.GetHash() == Params().HashGenesisBlock()) { + if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { if (!fJustCheck) view.SetBestBlock(pindex->GetBlockHash()); return true; @@ -2541,8 +2542,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev) { + const Consensus::Params& consensusParams = Params().GetConsensus(); uint256 hash = block.GetHash(); - if (hash == Params().HashGenesisBlock()) + if (hash == consensusParams.hashGenesisBlock) return true; assert(pindexPrev); @@ -2612,6 +2614,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex) { + const CChainParams& chainparams = Params(); AssertLockHeld(cs_main); // Check for duplicate uint256 hash = block.GetHash(); @@ -2632,7 +2635,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc // Get prev block index CBlockIndex* pindexPrev = NULL; - if (hash != Params().HashGenesisBlock()) { + if (hash != chainparams.GetConsensus().hashGenesisBlock) { BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); if (mi == mapBlockIndex.end()) return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); @@ -3119,6 +3122,7 @@ bool InitBlockIndex() { bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) { + const CChainParams& chainparams = Params(); // Map of disk positions for blocks with unknown parent (only used for reindex) static std::multimap mapBlocksUnknownParent; int64_t nStart = GetTimeMillis(); @@ -3164,7 +3168,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // detect out of order blocks, and store them for later uint256 hash = block.GetHash(); - if (hash != Params().HashGenesisBlock() && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { + if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), block.hashPrevBlock.ToString()); if (dbp) @@ -3179,7 +3183,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) nLoaded++; if (state.IsError()) break; - } else if (hash != Params().HashGenesisBlock() && mapBlockIndex[hash]->nHeight % 1000 == 0) { + } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); } @@ -3221,6 +3225,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) void static CheckBlockIndex() { + const Consensus::Params& consensusParams = Params().GetConsensus(); if (!fCheckBlockIndex) { return; } @@ -3263,7 +3268,7 @@ void static CheckBlockIndex() // Begin: actual consistency checks. if (pindex->pprev == NULL) { // Genesis block checks. - assert(pindex->GetBlockHash() == Params().HashGenesisBlock()); // Genesis block's hash must match. + assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match. assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block. } // HAVE_DATA is equivalent to VALID_TRANSACTIONS and equivalent to nTx > 0 (we stored the number of transactions in the block) From ea9e82df739dfc1e84b42cc42c6a65c243cca03d Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 13 Apr 2015 15:04:08 +0200 Subject: [PATCH 13/81] [squashme] fix listunspent code indentation --- src/wallet/rpcwallet.cpp | 106 +++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2c3507fb3..e03cd5b84 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2239,64 +2239,64 @@ Value listunspent(const Array& params, bool fHelp) return Value::null; if (fHelp || params.size() > 3) - throw runtime_error( - "listunspent ( minconf maxconf [\"address\",...] )\n" - "\nReturns array of unspent transaction outputs\n" - "with between minconf and maxconf (inclusive) confirmations.\n" - "Optionally filter to only include txouts paid to specified addresses.\n" - "Results are an array of Objects, each of which has:\n" - "{txid, vout, scriptPubKey, amount, confirmations}\n" - "\nArguments:\n" - "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" - "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" - "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n" - " [\n" - " \"address\" (string) bitcoin address\n" - " ,...\n" - " ]\n" - "\nResult\n" - "[ (array of json object)\n" - " {\n" - " \"txid\" : \"txid\", (string) the transaction id \n" - " \"vout\" : n, (numeric) the vout value\n" - " \"address\" : \"address\", (string) the bitcoin address\n" - " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n" - " \"scriptPubKey\" : \"key\", (string) the script key\n" - " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" - " \"confirmations\" : n (numeric) The number of confirmations\n" - " }\n" - " ,...\n" - "]\n" - - "\nExamples\n" - + HelpExampleCli("listunspent", "") - + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") - + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") - ); - + throw runtime_error( + "listunspent ( minconf maxconf [\"address\",...] )\n" + "\nReturns array of unspent transaction outputs\n" + "with between minconf and maxconf (inclusive) confirmations.\n" + "Optionally filter to only include txouts paid to specified addresses.\n" + "Results are an array of Objects, each of which has:\n" + "{txid, vout, scriptPubKey, amount, confirmations}\n" + "\nArguments:\n" + "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" + "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" + "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n" + " [\n" + " \"address\" (string) bitcoin address\n" + " ,...\n" + " ]\n" + "\nResult\n" + "[ (array of json object)\n" + " {\n" + " \"txid\" : \"txid\", (string) the transaction id \n" + " \"vout\" : n, (numeric) the vout value\n" + " \"address\" : \"address\", (string) the bitcoin address\n" + " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n" + " \"scriptPubKey\" : \"key\", (string) the script key\n" + " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" + " \"confirmations\" : n (numeric) The number of confirmations\n" + " }\n" + " ,...\n" + "]\n" + + "\nExamples\n" + + HelpExampleCli("listunspent", "") + + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + ); + RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type)); - + int nMinDepth = 1; if (params.size() > 0) - nMinDepth = params[0].get_int(); - + nMinDepth = params[0].get_int(); + int nMaxDepth = 9999999; if (params.size() > 1) - nMaxDepth = params[1].get_int(); - + nMaxDepth = params[1].get_int(); + set setAddress; if (params.size() > 2) { Array inputs = params[2].get_array(); BOOST_FOREACH(Value& input, inputs) { CBitcoinAddress address(input.get_str()); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str()); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str()); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); - setAddress.insert(address); + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); + setAddress.insert(address); } } - + Array results; vector vecOutputs; assert(pwalletMain != NULL); @@ -2304,17 +2304,17 @@ Value listunspent(const Array& params, bool fHelp) pwalletMain->AvailableCoins(vecOutputs, false); BOOST_FOREACH(const COutput& out, vecOutputs) { if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) - continue; - + continue; + if (setAddress.size()) { CTxDestination address; if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) - continue; - + continue; + if (!setAddress.count(address)) - continue; + continue; } - + CAmount nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; Object entry; @@ -2324,7 +2324,7 @@ Value listunspent(const Array& params, bool fHelp) if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); if (pwalletMain->mapAddressBook.count(address)) - entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); + entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); } entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); if (pk.IsPayToScriptHash()) { @@ -2333,7 +2333,7 @@ Value listunspent(const Array& params, bool fHelp) const CScriptID& hash = boost::get(address); CScript redeemScript; if (pwalletMain->GetCScript(hash, redeemScript)) - entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); } } entry.push_back(Pair("amount",ValueFromAmount(nValue))); @@ -2341,6 +2341,6 @@ Value listunspent(const Array& params, bool fHelp) entry.push_back(Pair("spendable", out.fSpendable)); results.push_back(entry); } - + return results; } \ No newline at end of file From e8e8904ddae09ef9dc444bcdd2955109c9e9ce64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 10 Apr 2015 18:35:09 +0200 Subject: [PATCH 14/81] Chainparams: Cleanup: Delete CChainParams getters to attributes from Consensus::Params --- src/chainparams.h | 4 ---- src/main.cpp | 6 ++++-- src/rpcmining.cpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/chainparams.h b/src/chainparams.h index e5e691cc5..d604c1d76 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -44,7 +44,6 @@ public: const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } - const uint256& ProofOfWorkLimit() const { return consensus.powLimit; } int SubsidyHalvingInterval() const { return consensus.nSubsidyHalvingInterval; } int EnforceBlockUpgradeMajority() const { return consensus.nMajorityEnforceBlockUpgrade; } int RejectBlockOutdatedMajority() const { return consensus.nMajorityRejectBlockOutdated; } @@ -62,9 +61,6 @@ public: bool AllowMinDifficultyBlocks() const { return consensus.fPowAllowMinDifficultyBlocks; } /** Make standard checks */ bool RequireStandard() const { return fRequireStandard; } - int64_t TargetTimespan() const { return consensus.nPowTargetTimespan; } - int64_t TargetSpacing() const { return consensus.nPowTargetSpacing; } - int64_t DifficultyAdjustmentInterval() const { return consensus.nPowTargetTimespan / consensus.nPowTargetSpacing; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } /** In the future use NetworkIDString() for RPC fields */ diff --git a/src/main.cpp b/src/main.cpp index 8fb676630..5878d3dc0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3577,6 +3577,7 @@ void static ProcessGetData(CNode* pfrom) bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { + const CChainParams& chainparams = Params(); RandAddSeedPerfmon(); LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) @@ -3836,7 +3837,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // not a direct successor. pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash); CNodeState *nodestate = State(pfrom->GetId()); - if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - Params().TargetSpacing() * 20 && + if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - chainparams.GetConsensus().nPowTargetSpacing * 20 && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vToFetch.push_back(inv); // Mark block as in flight already, even though the actual "getdata" message only goes out @@ -4499,6 +4500,7 @@ bool ProcessMessages(CNode* pfrom) bool SendMessages(CNode* pto, bool fSendTrickle) { + const Consensus::Params& consensusParams = Params().GetConsensus(); { // Don't send anything until we get their version message if (pto->nVersion == 0) @@ -4686,7 +4688,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link // being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes // to unreasonably increase our timeout. - if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * Params().TargetSpacing() * (4 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) { + if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * consensusParams.nPowTargetSpacing * (4 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id); pto->fDisconnect = true; } diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 1e6531f68..f8cd8791c 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -45,7 +45,7 @@ Value GetNetworkHashPS(int lookup, int height) { // If lookup is -1, then use blocks since last difficulty change. if (lookup <= 0) - lookup = pb->nHeight % Params().DifficultyAdjustmentInterval() + 1; + lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1; // If lookup is larger than chain, then set it to chain length. if (lookup > pb->nHeight) From eb63bf86cf6dc99f150574463df6ffb013a34493 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 13 Apr 2015 17:55:41 +0100 Subject: [PATCH 15/81] Fix missing lock in submitblock --- src/rpcmining.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 1e6531f68..949fe3ed5 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -629,14 +629,19 @@ Value submitblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); uint256 hash = block.GetHash(); - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) { - CBlockIndex *pindex = mi->second; - if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) - return "duplicate"; - if (pindex->nStatus & BLOCK_FAILED_MASK) - return "duplicate-invalid"; - // Otherwise, we might only have the header - process the block before returning + bool fBlockPresent = false; + { + LOCK(cs_main); + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) { + CBlockIndex *pindex = mi->second; + if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) + return "duplicate"; + if (pindex->nStatus & BLOCK_FAILED_MASK) + return "duplicate-invalid"; + // Otherwise, we might only have the header - process the block before returning + fBlockPresent = true; + } } CValidationState state; @@ -644,7 +649,7 @@ Value submitblock(const Array& params, bool fHelp) RegisterValidationInterface(&sc); bool fAccepted = ProcessNewBlock(state, NULL, &block); UnregisterValidationInterface(&sc); - if (mi != mapBlockIndex.end()) + if (fBlockPresent) { if (fAccepted && !sc.found) return "duplicate-inconclusive"; From c1ecee8f723c2635fbd51100fa09acdb0cbec8a0 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 13 Apr 2015 12:26:28 -0400 Subject: [PATCH 16/81] Set nSequenceId when a block is fully linked Also adds a test to CheckBlockIndex --- src/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8fb676630..6feebd24b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2349,10 +2349,6 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl pindexNew->nUndoPos = 0; pindexNew->nStatus |= BLOCK_HAVE_DATA; pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS); - { - LOCK(cs_nBlockSequenceId); - pindexNew->nSequenceId = nBlockSequenceId++; - } setDirtyBlockIndex.insert(pindexNew); if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) { @@ -2365,6 +2361,10 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl CBlockIndex *pindex = queue.front(); queue.pop_front(); pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; + { + LOCK(cs_nBlockSequenceId); + pindex->nSequenceId = nBlockSequenceId++; + } if (chainActive.Tip() == NULL || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) { setBlockIndexCandidates.insert(pindex); } @@ -3269,6 +3269,7 @@ void static CheckBlockIndex() // HAVE_DATA is equivalent to VALID_TRANSACTIONS and equivalent to nTx > 0 (we stored the number of transactions in the block) assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0)); assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); + if (pindex->nChainTx == 0) assert(pindex->nSequenceId == 0); // nSequenceId can't be set for blocks that aren't linked // All parents having data is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set. assert((pindexFirstMissing != NULL) == (pindex->nChainTx == 0)); // nChainTx == 0 is used to signal that all parent block's transaction data is available. assert((pindexFirstNotTransactionsValid != NULL) == (pindex->nChainTx == 0)); From 0421c18f3a261f04e83a03f59884e5798af74fd9 Mon Sep 17 00:00:00 2001 From: mrbandrews Date: Thu, 9 Apr 2015 11:08:39 -0400 Subject: [PATCH 17/81] Fix CheckBlockIndex for reindex. Some tests in CheckBlockIndex require chainActive.Tip(), but when reindexing, chainActive has not been set on the first call to CheckBlockIndex. reindex.py starts a node, mines 3 blocks, stops, and reindexes with CheckBlockIndex enabled. --- qa/rpc-tests/reindex.py | 34 ++++++++++++++++++++++++++++++++++ src/main.cpp | 8 ++++++++ 2 files changed, 42 insertions(+) create mode 100755 qa/rpc-tests/reindex.py diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py new file mode 100755 index 000000000..fe767586b --- /dev/null +++ b/qa/rpc-tests/reindex.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 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 -reindex with CheckBlockIndex +# +from test_framework import BitcoinTestFramework +from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException +from util import * +import os.path + +class ReindexTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self): + self.nodes = [] + self.is_network_split = False + self.nodes.append(start_node(0, self.options.tmpdir)) + + def run_test(self): + self.nodes[0].generate(3) + stop_node(self.nodes[0], 0) + wait_bitcoinds() + self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex", "-checkblockindex=1"]) + assert_equal(self.nodes[0].getblockcount(), 3) + print "Success" + +if __name__ == '__main__': + ReindexTest().main() diff --git a/src/main.cpp b/src/main.cpp index 8fb676630..a9051118a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3227,6 +3227,14 @@ void static CheckBlockIndex() LOCK(cs_main); + // During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain, + // so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when + // iterating the block tree require that chainActive has been initialized.) + if (chainActive.Height() < 0) { + assert(mapBlockIndex.size() <= 1); + return; + } + // Build forward-pointing map of the entire block tree. std::multimap forward; for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { From bebe7282ffbfbc260bfc020f1b62710fdfd07cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Fri, 10 Apr 2015 18:42:50 +0200 Subject: [PATCH 18/81] Chainparams: Refactor: Remove redundant AllowMinDifficultyBlocks() getter --- src/chainparams.h | 2 -- src/miner.cpp | 22 ++++++++++++---------- src/miner.h | 3 ++- src/rpcmining.cpp | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/chainparams.h b/src/chainparams.h index 119a7a81d..069209447 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -56,8 +56,6 @@ public: bool MiningRequiresPeers() const { return fMiningRequiresPeers; } /** Default value for -checkmempool and -checkblockindex argument */ bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } - /** Allow mining of a min-difficulty block */ - bool AllowMinDifficultyBlocks() const { return consensus.fPowAllowMinDifficultyBlocks; } /** Make standard checks */ bool RequireStandard() const { return fRequireStandard; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ diff --git a/src/miner.cpp b/src/miner.cpp index cf08b7822..3abd2d68e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -6,11 +6,12 @@ #include "miner.h" #include "amount.h" -#include "primitives/transaction.h" +#include "chainparams.h" #include "hash.h" #include "main.h" #include "net.h" #include "pow.h" +#include "primitives/transaction.h" #include "timedata.h" #include "util.h" #include "utilmoneystr.h" @@ -78,13 +79,13 @@ public: } }; -void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) +void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); // Updating time can change work required on testnet: - if (Params().AllowMinDifficultyBlocks()) - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + if (consensusParams.fPowAllowMinDifficultyBlocks) + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); } CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) @@ -325,7 +326,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(pblock, pindexPrev); + UpdateTime(pblock, Params().GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -440,6 +441,7 @@ void static BitcoinMiner(CWallet *pwallet) LogPrintf("BitcoinMiner started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("bitcoin-miner"); + const CChainParams& chainparams = Params(); // Each thread has its own key and counter CReserveKey reservekey(pwallet); @@ -447,7 +449,7 @@ void static BitcoinMiner(CWallet *pwallet) try { while (true) { - if (Params().MiningRequiresPeers()) { + if (chainparams.MiningRequiresPeers()) { // Busy-wait for the network to come online so we don't waste time mining // on an obsolete chain. In regtest mode we expect to fly solo. while (vNodes.empty()) @@ -496,7 +498,7 @@ void static BitcoinMiner(CWallet *pwallet) SetThreadPriority(THREAD_PRIORITY_LOWEST); // In regression test mode, stop mining after a block is found. - if (Params().MineBlocksOnDemand()) + if (chainparams.MineBlocksOnDemand()) throw boost::thread_interrupted(); break; @@ -506,7 +508,7 @@ void static BitcoinMiner(CWallet *pwallet) // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); // Regtest mode doesn't require peers - if (vNodes.empty() && Params().MiningRequiresPeers()) + if (vNodes.empty() && chainparams.MiningRequiresPeers()) break; if (nNonce >= 0xffff0000) break; @@ -516,8 +518,8 @@ void static BitcoinMiner(CWallet *pwallet) break; // Update nTime every few seconds - UpdateTime(pblock, pindexPrev); - if (Params().AllowMinDifficultyBlocks()) + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) { // Changing pblock->nTime can change work required on testnet: hashTarget.SetCompact(pblock->nBits); diff --git a/src/miner.h b/src/miner.h index 5d5c9c86c..0be3152d9 100644 --- a/src/miner.h +++ b/src/miner.h @@ -14,6 +14,7 @@ class CBlockIndex; class CReserveKey; class CScript; class CWallet; +namespace Consensus { class Params; }; struct CBlockTemplate { @@ -29,6 +30,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); -void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev); +void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); #endif // BITCOIN_MINER_H diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 18f0ec0f8..851d113f3 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -514,7 +514,7 @@ Value getblocktemplate(const Array& params, bool fHelp) CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime - UpdateTime(pblock, pindexPrev); + UpdateTime(pblock, Params().GetConsensus(), pindexPrev); pblock->nNonce = 0; static const Array aCaps = boost::assign::list_of("proposal"); From 5a53d7cda37677f393cddcc483523eb2cbfaf88d Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 12 Dec 2014 10:15:34 +0100 Subject: [PATCH 19/81] [Qt] paymentserver: do not log NULL certificates - also add a few more comments in PaymentServer::LoadRootCAs --- src/qt/paymentserver.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index ad489de34..f05bfc059 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -143,13 +143,20 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) int nRootCerts = 0; const QDateTime currentTime = QDateTime::currentDateTime(); - foreach (const QSslCertificate& cert, certList) - { + + foreach (const QSslCertificate& cert, certList) { + // Don't log NULL certificates + if (cert.isNull()) + continue; + + // Not yet active/valid, or expired certificate if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) { ReportInvalidCertificate(cert); continue; } + #if QT_VERSION >= 0x050000 + // Blacklisted certificate if (cert.isBlacklisted()) { ReportInvalidCertificate(cert); continue; From 6e17a747661bc1c737b10f77d1df87d37e49fbb8 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 12 Dec 2014 10:17:56 +0100 Subject: [PATCH 20/81] [Qt] paymentserver: better logging of invalid certs Before and after was tested in Windows: before: GUI: ReportInvalidCertificate : Payment server found an invalid certificate: ("Microsoft Authenticode(tm) Root Authority") GUI: ReportInvalidCertificate : Payment server found an invalid certificate: () GUI: ReportInvalidCertificate : Payment server found an invalid certificate: () GUI: ReportInvalidCertificate : Payment server found an invalid certificate: () after: GUI: ReportInvalidCertificate: Payment server found an invalid certificate: "01" ("Microsoft Authenticode(tm) Root Authority") () () GUI: ReportInvalidCertificate: Payment server found an invalid certificate: "01" () () ("Copyright (c) 1997 Microsoft Corp.", "Microsoft Time Stamping Service Root", "Microsoft Corporation") GUI: ReportInvalidCertificate: Payment server found an invalid certificate: "4a:19:d2:38:8c:82:59:1c:a5:5d:73:5f:15:5d:dc:a3" () () ("NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc.", "VeriSign Time Stamping Service Root", "VeriSign, Inc.") GUI: ReportInvalidCertificate: Payment server found an invalid certificate: "e4:9e:fd:f3:3a:e8:0e:cf:a5:11:3e:19:a4:24:02:32" () () ("Class 3 Public Primary Certification Authority") --- src/qt/paymentserver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index f05bfc059..1d35de6f0 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -97,7 +97,11 @@ static QList savedPaymentRequests; static void ReportInvalidCertificate(const QSslCertificate& cert) { - qDebug() << "ReportInvalidCertificate: Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName); +#if QT_VERSION < 0x050000 + qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName); +#else + qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName); +#endif } // From d19ae3cf665de269c5dc4e2d9ed5ebe954b88be8 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 12 Dec 2014 10:21:07 +0100 Subject: [PATCH 21/81] [Qt] remove unused PaymentRequestPlus::getPKIType function --- src/qt/paymentrequestplus.cpp | 6 ------ src/qt/paymentrequestplus.h | 1 - 2 files changed, 7 deletions(-) diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index b69461ad9..de222fe14 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -59,12 +59,6 @@ bool PaymentRequestPlus::IsInitialized() const return paymentRequest.IsInitialized(); } -QString PaymentRequestPlus::getPKIType() const -{ - if (!IsInitialized()) return QString("none"); - return QString::fromStdString(paymentRequest.pki_type()); -} - bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) const { merchant.clear(); diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h index 61f8a3415..99a7186b8 100644 --- a/src/qt/paymentrequestplus.h +++ b/src/qt/paymentrequestplus.h @@ -29,7 +29,6 @@ public: bool SerializeToString(std::string* output) const; bool IsInitialized() const; - QString getPKIType() const; // Returns true if merchant's identity is authenticated, and // returns human-readable merchant identity in merchant bool getMerchant(X509_STORE* certStore, QString& merchant) const; From 9b14aefee379345a051f2d4cdd92fe8cd52a658d Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 12 Dec 2014 16:14:44 +0100 Subject: [PATCH 22/81] [Qt] take care of a missing typecast in PaymentRequestPlus::getMerchant() --- src/qt/paymentrequestplus.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index de222fe14..7e9729eeb 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -118,7 +118,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c // The first cert is the signing cert, the rest are untrusted certs that chain // to a valid root authority. OpenSSL needs them separately. STACK_OF(X509) *chain = sk_X509_new_null(); - for (int i = certs.size()-1; i > 0; i--) { + for (int i = certs.size() - 1; i > 0; i--) { sk_X509_push(chain, certs[i]); } X509 *signing_cert = certs[0]; @@ -166,9 +166,8 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c EVP_MD_CTX_init(&ctx); if (!EVP_VerifyInit_ex(&ctx, digestAlgorithm, NULL) || !EVP_VerifyUpdate(&ctx, data_to_verify.data(), data_to_verify.size()) || - !EVP_VerifyFinal(&ctx, (const unsigned char*)paymentRequest.signature().data(), paymentRequest.signature().size(), pubkey)) { - - throw SSLVerifyError("Bad signature, invalid PaymentRequest."); + !EVP_VerifyFinal(&ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) { + throw SSLVerifyError("Bad signature, invalid payment request."); } // OpenSSL API for getting human printable strings from certs is baroque. From 35d15959b0b6eb58e87b351d8f58952fa8e90103 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Mon, 12 Jan 2015 14:24:01 +0100 Subject: [PATCH 23/81] [Qt] constify first parameter of processPaymentRequest() --- src/qt/paymentserver.cpp | 2 +- src/qt/paymentserver.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 1d35de6f0..e7c2f6a08 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -526,7 +526,7 @@ bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentR return request.parse(data); } -bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoinsRecipient& recipient) +bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient) { if (!optionsModel) return false; diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 6bf5ac2ee..32ed27983 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -131,7 +131,7 @@ protected: bool eventFilter(QObject *object, QEvent *event); private: - bool processPaymentRequest(PaymentRequestPlus& request, SendCoinsRecipient& recipient); + bool processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient); void fetchRequest(const QUrl& url); // Setup networking From 06087bda87214e3f4995a0de65633511d4158d78 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Mon, 12 Jan 2015 14:26:52 +0100 Subject: [PATCH 24/81] [Qt] minor comment updates in PaymentServer --- src/qt/paymentserver.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index e7c2f6a08..09e9949b1 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -312,7 +312,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : // Install global event filter to catch QFileOpenEvents // on Mac: sent when you click bitcoin: links - // other OSes: helpful when dealing with payment request files (in the future) + // other OSes: helpful when dealing with payment request files if (parent) parent->installEventFilter(this); @@ -343,14 +343,13 @@ PaymentServer::~PaymentServer() } // -// OSX-specific way of handling bitcoin: URIs and -// PaymentRequest mime types +// OSX-specific way of handling bitcoin: URIs and PaymentRequest mime types. +// Also used by paymentservertests.cpp and when opening a payment request file +// via "Open URI..." menu entry. // bool PaymentServer::eventFilter(QObject *object, QEvent *event) { - // clicking on bitcoin: URIs creates FileOpen events on the Mac - if (event->type() == QEvent::FileOpen) - { + if (event->type() == QEvent::FileOpen) { QFileOpenEvent *fileEvent = static_cast(event); if (!fileEvent->file().isEmpty()) handleURIOrFile(fileEvent->file()); @@ -571,9 +570,9 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString())); } else if (!recipient.authenticatedMerchant.isEmpty()) { - // Insecure payments to custom bitcoin addresses are not supported - // (there is no good way to tell the user where they are paying in a way - // they'd have a chance of understanding). + // Unauthenticated payment requests to custom bitcoin addresses are not supported + // (there is no good way to tell the user where they are paying in a way they'd + // have a chance of understanding). emit message(tr("Payment request rejected"), tr("Unverified payment requests to custom payment scripts are unsupported."), CClientUIInterface::MSG_ERROR); From 6171e494fcd38a4e9a2921e066c10720a74e0ddb Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Tue, 3 Feb 2015 22:44:33 +0100 Subject: [PATCH 25/81] [Qt] Use identical strings for expired payment request message - used in sendcoinsdialog.cpp and paymentserver.cpp - removes an unneded translation string --- src/qt/sendcoinsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 774667d4a..59939fa87 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -531,7 +531,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), 10000000)); break; case WalletModel::PaymentRequestExpired: - msgParams.first = tr("Payment request expired!"); + msgParams.first = tr("Payment request expired."); msgParams.second = CClientUIInterface::MSG_ERROR; break; // included to prevent a compiler warning. From 30c43d9821ca54a9fa69b8becce6e1bd8d4f0e25 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 16 Apr 2015 10:32:47 +0200 Subject: [PATCH 26/81] miner.h: fix clang warning because of class/struct mix - class 'Params' was previously declared as a struct --- src/miner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.h b/src/miner.h index 0be3152d9..96a6b70ec 100644 --- a/src/miner.h +++ b/src/miner.h @@ -14,7 +14,7 @@ class CBlockIndex; class CReserveKey; class CScript; class CWallet; -namespace Consensus { class Params; }; +namespace Consensus { struct Params; }; struct CBlockTemplate { From b74dcb3b4aa29958d22135f2d6c015578069e83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Thu, 16 Apr 2015 16:20:01 +0200 Subject: [PATCH 27/81] Separate CTranslationInterface from CClientUIInterface --- src/bitcoin-cli.cpp | 2 -- src/bitcoin-tx.cpp | 2 -- src/bitcoind.cpp | 1 - src/init.cpp | 2 +- src/qt/bitcoin.cpp | 2 +- src/qt/transactiondesc.cpp | 1 - src/rpcclient.cpp | 1 - src/test/test_bitcoin.cpp | 2 +- src/ui_interface.h | 13 ------------- src/util.cpp | 1 + src/util.h | 20 ++++++++++++++++++++ 11 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 2fa8de6fd..1269d7a11 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -12,8 +12,6 @@ #include -#define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */ - using namespace std; using namespace json_spirit; diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 78f5c2c4b..075d52940 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -11,7 +11,6 @@ #include "keystore.h" #include "script/script.h" #include "script/sign.h" -#include "ui_interface.h" // for _(...) #include "univalue/univalue.h" #include "util.h" #include "utilstrencodings.h" @@ -26,7 +25,6 @@ using namespace std; static bool fCreateBlank; static map registers; -CClientUIInterface uiInterface; static bool AppInitRawTx(int argc, char* argv[]) { diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index a0a96c2df..84df00527 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -8,7 +8,6 @@ #include "init.h" #include "main.h" #include "noui.h" -#include "ui_interface.h" #include "util.h" #include diff --git a/src/init.cpp b/src/init.cpp index 4d9c233c8..7f95b5f92 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -68,7 +68,7 @@ enum BindFlags { }; static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; -CClientUIInterface uiInterface; +CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h ////////////////////////////////////////////////////////////////////////////// // diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 3ae780abf..1abce1eb2 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -533,7 +533,7 @@ int main(int argc, char *argv[]) // Now that QSettings are accessible, initialize translations QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); - uiInterface.Translate.connect(Translate); + translationInterface.Translate.connect(Translate); // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 9b235f913..a7f705d2b 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -14,7 +14,6 @@ #include "main.h" #include "script/script.h" #include "timedata.h" -#include "ui_interface.h" #include "util.h" #include "wallet/wallet.h" diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 428e1049d..ccb7cf15e 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -7,7 +7,6 @@ #include "rpcprotocol.h" #include "util.h" -#include "ui_interface.h" #include #include diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index a2cb78c98..4057eccbe 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -20,7 +20,7 @@ #include #include -CClientUIInterface uiInterface; +CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h CWallet* pwalletMain; extern bool fPrintToConsole; diff --git a/src/ui_interface.h b/src/ui_interface.h index 3f11a1dda..32a92a4b8 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -78,9 +78,6 @@ public: /** Progress message during initialization. */ boost::signals2::signal InitMessage; - /** Translate a message to the native language of the user. */ - boost::signals2::signal Translate; - /** Number of network connections changed. */ boost::signals2::signal NotifyNumConnectionsChanged; @@ -102,14 +99,4 @@ public: extern CClientUIInterface uiInterface; -/** - * Translation function: Call Translate signal on UI interface, which returns a boost::optional result. - * If no translation slot is registered, nothing is returned, and simply return the input. - */ -inline std::string _(const char* psz) -{ - boost::optional rv = uiInterface.Translate(psz); - return rv ? (*rv) : psz; -} - #endif // BITCOIN_UI_INTERFACE_H diff --git a/src/util.cpp b/src/util.cpp index 5fef3a40d..78c773150 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -104,6 +104,7 @@ string strMiscWarning; bool fLogTimestamps = false; bool fLogIPs = false; volatile bool fReopenDebugLog = false; +CTranslationInterface translationInterface; /** Init OpenSSL library multithreading support */ static CCriticalSection** ppmutexOpenSSL; diff --git a/src/util.h b/src/util.h index 9b5a4153d..483d9d785 100644 --- a/src/util.h +++ b/src/util.h @@ -25,8 +25,17 @@ #include #include +#include #include +/** Signals for translation. */ +class CTranslationInterface +{ +public: + /** Translate a message to the native language of the user. */ + boost::signals2::signal Translate; +}; + extern std::map mapArgs; extern std::map > mapMultiArgs; extern bool fDebug; @@ -37,6 +46,17 @@ extern std::string strMiscWarning; extern bool fLogTimestamps; extern bool fLogIPs; extern volatile bool fReopenDebugLog; +extern CTranslationInterface translationInterface; + +/** + * Translation function: Call Translate signal on UI interface, which returns a boost::optional result. + * If no translation slot is registered, nothing is returned, and simply return the input. + */ +inline std::string _(const char* psz) +{ + boost::optional rv = translationInterface.Translate(psz); + return rv ? (*rv) : psz; +} void SetupEnvironment(); From 67a79493976a3d5f5dac6ec64993fc3f415cac43 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 16 Mar 2015 16:30:49 +0100 Subject: [PATCH 28/81] privacy: Stream isolation for Tor According to Tor's extensions to the SOCKS protocol (https://gitweb.torproject.org/torspec.git/tree/socks-extensions.txt) it is possible to perform stream isolation by providing authentication to the proxy. Each set of credentials will create a new circuit, which makes it harder to correlate connections. This patch adds an option, `-proxyrandomize` (on by default) that randomizes credentials for every outgoing connection, thus creating a new circuit. 2015-03-16 15:29:59 SOCKS5 Sending proxy authentication 3842137544:3256031132 --- src/init.cpp | 13 +-- src/netbase.cpp | 180 ++++++++++++++++++++++++---------------- src/netbase.h | 16 +++- src/qt/optionsmodel.cpp | 4 +- src/rpcmisc.cpp | 2 +- src/rpcnet.cpp | 3 +- 6 files changed, 134 insertions(+), 84 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4d9c233c8..8f52d254f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -301,6 +301,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1)); strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), 8333, 18333)); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); + strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1)); strUsage += HelpMessageOpt("-seednode=", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); #ifdef USE_UPNP @@ -351,7 +352,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-flushwallet", strprintf(_("Run a thread to flush wallet periodically (default: %u)"), 1)); strUsage += HelpMessageOpt("-stopafterblockimport", strprintf(_("Stop running after importing blocks from disk (default: %u)"), 0)); } - string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net"; // Don't translate these and qt below + string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + @@ -891,10 +892,10 @@ bool AppInit2(boost::thread_group& threadGroup) } } - CService addrProxy; + proxyType addrProxy; bool fProxy = false; if (mapArgs.count("-proxy")) { - addrProxy = CService(mapArgs["-proxy"], 9050); + addrProxy = proxyType(CService(mapArgs["-proxy"], 9050), GetArg("-proxyrandomize", true)); if (!addrProxy.IsValid()) return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"])); @@ -904,14 +905,14 @@ bool AppInit2(boost::thread_group& threadGroup) fProxy = true; } - // -onion can override normal proxy, -noonion disables tor entirely + // -onion can override normal proxy, -noonion disables connecting to .onion entirely if (!(mapArgs.count("-onion") && mapArgs["-onion"] == "0") && (fProxy || mapArgs.count("-onion"))) { - CService addrOnion; + proxyType addrOnion; if (!mapArgs.count("-onion")) addrOnion = addrProxy; else - addrOnion = CService(mapArgs["-onion"], 9050); + addrOnion = proxyType(CService(mapArgs["-onion"], 9050), GetArg("-proxyrandomize", true)); if (!addrOnion.IsValid()) return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs["-onion"])); SetProxy(NET_TOR, addrOnion); diff --git a/src/netbase.cpp b/src/netbase.cpp index a2ac6575b..1837cfa9c 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -12,6 +12,7 @@ #include "hash.h" #include "sync.h" #include "uint256.h" +#include "random.h" #include "util.h" #include "utilstrencodings.h" @@ -38,7 +39,7 @@ using namespace std; // Settings static proxyType proxyInfo[NET_MAX]; -static CService nameProxy; +static proxyType nameProxy; static CCriticalSection cs_proxyInfos; int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; bool fNameLookup = false; @@ -285,59 +286,100 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock return len == 0; } -bool static Socks5(string strDest, int port, SOCKET& hSocket) +struct ProxyCredentials +{ + std::string username; + std::string password; +}; + +/** Connect using SOCKS5 (as described in RFC1928) */ +bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket) { LogPrintf("SOCKS5 connecting %s\n", strDest); - if (strDest.size() > 255) - { + if (strDest.size() > 255) { CloseSocket(hSocket); return error("Hostname too long"); } - char pszSocks5Init[] = "\5\1\0"; - ssize_t nSize = sizeof(pszSocks5Init) - 1; - - ssize_t ret = send(hSocket, pszSocks5Init, nSize, MSG_NOSIGNAL); - if (ret != nSize) - { + // Accepted authentication methods + std::vector vSocks5Init; + vSocks5Init.push_back(0x05); + if (auth) { + vSocks5Init.push_back(0x02); // # METHODS + vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED + vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929) + } else { + vSocks5Init.push_back(0x01); // # METHODS + vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED + } + ssize_t ret = send(hSocket, (const char*)begin_ptr(vSocks5Init), vSocks5Init.size(), MSG_NOSIGNAL); + if (ret != (ssize_t)vSocks5Init.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); } char pchRet1[2]; - if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) - { + if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { CloseSocket(hSocket); return error("Error reading proxy response"); } - if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00) - { + if (pchRet1[0] != 0x05) { CloseSocket(hSocket); return error("Proxy failed to initialize"); } - string strSocks5("\5\1"); - strSocks5 += '\000'; strSocks5 += '\003'; - strSocks5 += static_cast(std::min((int)strDest.size(), 255)); - strSocks5 += strDest; - strSocks5 += static_cast((port >> 8) & 0xFF); - strSocks5 += static_cast((port >> 0) & 0xFF); - ret = send(hSocket, strSocks5.data(), strSocks5.size(), MSG_NOSIGNAL); - if (ret != (ssize_t)strSocks5.size()) - { + if (pchRet1[1] == 0x02 && auth) { + // Perform username/password authentication (as described in RFC1929) + std::vector vAuth; + vAuth.push_back(0x01); + if (auth->username.size() > 255 || auth->password.size() > 255) + return error("Proxy username or password too long"); + vAuth.push_back(auth->username.size()); + vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); + vAuth.push_back(auth->password.size()); + vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); + ret = send(hSocket, (const char*)begin_ptr(vAuth), vAuth.size(), MSG_NOSIGNAL); + if (ret != (ssize_t)vAuth.size()) { + CloseSocket(hSocket); + return error("Error sending authentication to proxy"); + } + LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); + char pchRetA[2]; + if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { + CloseSocket(hSocket); + return error("Error reading proxy authentication response"); + } + if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) { + CloseSocket(hSocket); + return error("Proxy authentication unsuccesful"); + } + } else if (pchRet1[1] == 0x00) { + // Perform no authentication + } else { + CloseSocket(hSocket); + return error("Proxy requested wrong authentication method %02x", pchRet1[1]); + } + std::vector vSocks5; + vSocks5.push_back(0x05); // VER protocol version + vSocks5.push_back(0x01); // CMD CONNECT + vSocks5.push_back(0x00); // RSV Reserved + vSocks5.push_back(0x03); // ATYP DOMAINNAME + vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function + vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end()); + vSocks5.push_back((port >> 8) & 0xFF); + vSocks5.push_back((port >> 0) & 0xFF); + ret = send(hSocket, (const char*)begin_ptr(vSocks5), vSocks5.size(), MSG_NOSIGNAL); + if (ret != (ssize_t)vSocks5.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); } char pchRet2[4]; - if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) - { + if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) { CloseSocket(hSocket); return error("Error reading proxy response"); } - if (pchRet2[0] != 0x05) - { + if (pchRet2[0] != 0x05) { CloseSocket(hSocket); return error("Proxy failed to accept request"); } - if (pchRet2[1] != 0x00) - { + if (pchRet2[1] != 0x00) { CloseSocket(hSocket); switch (pchRet2[1]) { @@ -352,8 +394,7 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket) default: return error("Proxy error: unknown"); } } - if (pchRet2[2] != 0x00) - { + if (pchRet2[2] != 0x00) { CloseSocket(hSocket); return error("Error: malformed proxy response"); } @@ -375,13 +416,11 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket) } default: CloseSocket(hSocket); return error("Error: malformed proxy response"); } - if (!ret) - { + if (!ret) { CloseSocket(hSocket); return error("Error reading from proxy"); } - if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) - { + if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { CloseSocket(hSocket); return error("Error reading from proxy"); } @@ -471,7 +510,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe return true; } -bool SetProxy(enum Network net, CService addrProxy) { +bool SetProxy(enum Network net, const proxyType &addrProxy) { assert(net >= 0 && net < NET_MAX); if (!addrProxy.IsValid()) return false; @@ -489,7 +528,7 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut) { return true; } -bool SetNameProxy(CService addrProxy) { +bool SetNameProxy(const proxyType &addrProxy) { if (!addrProxy.IsValid()) return false; LOCK(cs_proxyInfos); @@ -497,7 +536,7 @@ bool SetNameProxy(CService addrProxy) { return true; } -bool GetNameProxy(CService &nameProxyOut) { +bool GetNameProxy(proxyType &nameProxyOut) { LOCK(cs_proxyInfos); if(!nameProxy.IsValid()) return false; @@ -513,35 +552,47 @@ bool HaveNameProxy() { bool IsProxy(const CNetAddr &addr) { LOCK(cs_proxyInfos); for (int i = 0; i < NET_MAX; i++) { - if (addr == (CNetAddr)proxyInfo[i]) + if (addr == (CNetAddr)proxyInfo[i].proxy) return true; } return false; } +static bool ConnectThroughProxy(const proxyType &proxy, const std::string strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed) +{ + SOCKET hSocket = INVALID_SOCKET; + // first connect to proxy server + if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) { + if (outProxyConnectionFailed) + *outProxyConnectionFailed = true; + return false; + } + // do socks negotiation + if (proxy.randomize_credentials) { + ProxyCredentials random_auth; + random_auth.username = strprintf("%i", insecure_rand()); + random_auth.password = strprintf("%i", insecure_rand()); + if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket)) + return false; + } else { + if (!Socks5(strDest, (unsigned short)port, 0, hSocket)) + return false; + } + + hSocketRet = hSocket; + return true; +} + bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed) { proxyType proxy; if (outProxyConnectionFailed) *outProxyConnectionFailed = false; - // no proxy needed (none set for target network) - if (!GetProxy(addrDest.GetNetwork(), proxy)) + + if (GetProxy(addrDest.GetNetwork(), proxy)) + return ConnectThroughProxy(proxy, addrDest.ToStringIP(), addrDest.GetPort(), hSocketRet, nTimeout, outProxyConnectionFailed); + else // no proxy needed (none set for target network) return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout); - - SOCKET hSocket = INVALID_SOCKET; - - // first connect to proxy server - if (!ConnectSocketDirectly(proxy, hSocket, nTimeout)) { - if (outProxyConnectionFailed) - *outProxyConnectionFailed = true; - return false; - } - // do socks negotiation - if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket)) - return false; - - hSocketRet = hSocket; - return true; } bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed) @@ -554,9 +605,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest SplitHostPort(string(pszDest), port, strDest); - SOCKET hSocket = INVALID_SOCKET; - - CService nameProxy; + proxyType nameProxy; GetNameProxy(nameProxy); CService addrResolved(CNetAddr(strDest, fNameLookup && !HaveNameProxy()), port); @@ -569,18 +618,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest if (!HaveNameProxy()) return false; - // first connect to name proxy server - if (!ConnectSocketDirectly(nameProxy, hSocket, nTimeout)) { - if (outProxyConnectionFailed) - *outProxyConnectionFailed = true; - return false; - } - // do socks negotiation - if (!Socks5(strDest, (unsigned short)port, hSocket)) - return false; - - hSocketRet = hSocket; - return true; + return ConnectThroughProxy(nameProxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed); } void CNetAddr::Init() diff --git a/src/netbase.h b/src/netbase.h index b42c2dffa..6d2ca4afb 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -168,15 +168,25 @@ class CService : public CNetAddr } }; -typedef CService proxyType; +class proxyType +{ +public: + proxyType(): randomize_credentials(false) {} + proxyType(const CService &proxy, bool randomize_credentials=false): proxy(proxy), randomize_credentials(randomize_credentials) {} + + bool IsValid() const { return proxy.IsValid(); } + + CService proxy; + bool randomize_credentials; +}; enum Network ParseNetwork(std::string net); std::string GetNetworkName(enum Network net); void SplitHostPort(std::string in, int &portOut, std::string &hostOut); -bool SetProxy(enum Network net, CService addrProxy); +bool SetProxy(enum Network net, const proxyType &addrProxy); bool GetProxy(enum Network net, proxyType &proxyInfoOut); bool IsProxy(const CNetAddr &addr); -bool SetNameProxy(CService addrProxy); +bool SetNameProxy(const proxyType &addrProxy); bool HaveNameProxy(); bool LookupHost(const char *pszName, std::vector& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index a169ed6b5..41d6acf35 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -335,8 +335,8 @@ bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const proxyType curProxy; if (GetProxy(NET_IPV4, curProxy)) { proxy.setType(QNetworkProxy::Socks5Proxy); - proxy.setHostName(QString::fromStdString(curProxy.ToStringIP())); - proxy.setPort(curProxy.GetPort()); + proxy.setHostName(QString::fromStdString(curProxy.proxy.ToStringIP())); + proxy.setPort(curProxy.proxy.GetPort()); return true; } diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 938d79513..f5bef2a07 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -90,7 +90,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); - obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string()))); + obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); #ifdef ENABLE_WALLET diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 6306fd440..bdee5b9f2 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -371,7 +371,8 @@ static Array GetNetworksInfo() obj.push_back(Pair("name", GetNetworkName(network))); obj.push_back(Pair("limited", IsLimited(network))); obj.push_back(Pair("reachable", IsReachable(network))); - obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.ToStringIPPort() : string())); + obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())); + obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials)); networks.push_back(obj); } return networks; From 1d5b47a9033738743e5323409777b1415a0d0af7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 19 Apr 2015 11:10:13 -0700 Subject: [PATCH 29/81] nLastTry is only used for addrman entries No need to define it for every CAddress, as it's memory only anyway. --- src/addrman.cpp | 4 ++-- src/addrman.h | 13 +++++++------ src/net.cpp | 2 +- src/protocol.cpp | 1 - src/protocol.h | 3 --- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index 5d9527f0e..cefd70a1b 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -332,10 +332,10 @@ void CAddrMan::Attempt_(const CService& addr, int64_t nTime) info.nAttempts++; } -CAddress CAddrMan::Select_() +CAddrInfo CAddrMan::Select_() { if (size() == 0) - return CAddress(); + return CAddrInfo(); // Use a 50% chance for choosing between tried and new table entries. if (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0)) { diff --git a/src/addrman.h b/src/addrman.h index 8116d0b76..5badd4ef9 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -22,6 +22,10 @@ */ class CAddrInfo : public CAddress { +public: + //! last try whatsoever by us (memory only) + int64_t nLastTry; + private: //! where knowledge about this address first came from CNetAddr source; @@ -29,9 +33,6 @@ private: //! last successful connection by us int64_t nLastSuccess; - //! last try whatsoever by us: - // int64_t CAddress::nLastTry - //! connection attempts since last successful attempt int nAttempts; @@ -231,7 +232,7 @@ protected: //! Select an address to connect to. //! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100) - CAddress Select_(); + CAddrInfo Select_(); #ifdef DEBUG_ADDRMAN //! Perform consistency check. Returns an error code or zero. @@ -533,9 +534,9 @@ public: * Choose an address to connect to. * nUnkBias determines how much "new" entries are favored over "tried" ones (0-100). */ - CAddress Select() + CAddrInfo Select() { - CAddress addrRet; + CAddrInfo addrRet; { LOCK(cs); Check(); diff --git a/src/net.cpp b/src/net.cpp index 48e6367f2..e5f67262c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1221,7 +1221,7 @@ void ThreadOpenConnections() int nTries = 0; while (true) { - CAddress addr = addrman.Select(); + CAddrInfo addr = addrman.Select(); // if we selected an invalid address, restart if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) diff --git a/src/protocol.cpp b/src/protocol.cpp index 568580a59..dd855aa33 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -89,7 +89,6 @@ void CAddress::Init() { nServices = NODE_NETWORK; nTime = 100000000; - nLastTry = 0; } CInv::CInv() diff --git a/src/protocol.h b/src/protocol.h index fd23eae1f..b5e65032a 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -116,9 +116,6 @@ public: // disk and network only unsigned int nTime; - - // memory only - int64_t nLastTry; }; /** inv message data */ From a784f90c9892f06b9fea4e7579f5eca3585482c3 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 19 Apr 2015 11:47:56 -0700 Subject: [PATCH 30/81] Cap nAttempts penalty at 8 and switch to pow instead of a division loop. On hosts that had spent some time with a failed internet connection their nAttempts penalty was going through the roof (e.g. thousands for all peers) and as a result the connect search was pegging the CPU and failing to get more than a 4 connections after days of running (because it was taking so long per try). --- src/addrman.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index 5d9527f0e..094c913e9 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -67,9 +67,8 @@ double CAddrInfo::GetChance(int64_t nNow) const if (nSinceLastTry < 60 * 10) fChance *= 0.01; - // deprioritize 50% after each failed attempt - for (int n = 0; n < nAttempts; n++) - fChance /= 1.5; + // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages. + fChance *= pow(0.66, min(nAttempts, 8)); return fChance; } From 2eadeb27ed40d4dcb252a9d993d3946435f6e22e Mon Sep 17 00:00:00 2001 From: dexX7 Date: Mon, 20 Apr 2015 11:50:33 +0200 Subject: [PATCH 31/81] QA: stop nodes after RPC tests, even with --nocleanup `--nocleanup` should provide a way to preserve test data, but should not have an impact on whether nodes are to be stopped after the test execution. In particular, when currently running RPC tests with `--nocleanup`, then it may result in several active `bitcoind` processes, which are not terminated properly. --- qa/rpc-tests/test_framework.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/test_framework.py b/qa/rpc-tests/test_framework.py index 4c8a11b82..8de7a4b5e 100755 --- a/qa/rpc-tests/test_framework.py +++ b/qa/rpc-tests/test_framework.py @@ -128,10 +128,12 @@ class BitcoinTestFramework(object): print("Unexpected exception caught during testing: "+str(e)) traceback.print_tb(sys.exc_info()[2]) + print("Stopping nodes") + stop_nodes(self.nodes) + wait_bitcoinds() + if not self.options.nocleanup: print("Cleaning up") - stop_nodes(self.nodes) - wait_bitcoinds() shutil.rmtree(self.options.tmpdir) if success: From 60c146938e9b30bb25c639bb3d795942525e3ba1 Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 30 Jan 2015 10:08:46 +0100 Subject: [PATCH 32/81] [Qt] header group cleanup - seperate core from GUI headers where this was missing - remove an unneeded new-line --- src/qt/bitcoin.cpp | 1 - src/qt/coincontroldialog.cpp | 2 +- src/qt/recentrequeststablemodel.cpp | 3 ++- src/qt/splashscreen.cpp | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 3ae780abf..069601ab6 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -107,7 +107,6 @@ static QString GetLangTerritory() /** Set up translations */ static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator) { - // Remove old translators QApplication::removeTranslator(&qtTranslatorBase); QApplication::removeTranslator(&qtTranslator); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index e4e9015c8..0a60632bf 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -8,12 +8,12 @@ #include "addresstablemodel.h" #include "bitcoinunits.h" #include "guiutil.h" -#include "init.h" #include "optionsmodel.h" #include "scicon.h" #include "walletmodel.h" #include "coincontrol.h" +#include "init.h" #include "main.h" #include "wallet/wallet.h" diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 5221ec3e2..543b977d8 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -5,9 +5,10 @@ #include "recentrequeststablemodel.h" #include "bitcoinunits.h" -#include "clientversion.h" #include "guiutil.h" #include "optionsmodel.h" + +#include "clientversion.h" #include "streams.h" #include diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 414fe02ff..8430e017c 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -4,11 +4,12 @@ #include "splashscreen.h" +#include "networkstyle.h" + #include "clientversion.h" #include "init.h" -#include "networkstyle.h" -#include "ui_interface.h" #include "util.h" +#include "ui_interface.h" #include "version.h" #ifdef ENABLE_WALLET From fa535f9a5bb96895dc62cc975348e0944037596a Mon Sep 17 00:00:00 2001 From: sandakersmann Date: Mon, 2 Feb 2015 15:36:41 +0100 Subject: [PATCH 33/81] Remove folder and images for bootstrap.md --- doc/img/bootstrap1.png | Bin 55028 -> 0 bytes doc/img/bootstrap2.png | Bin 35195 -> 0 bytes doc/img/bootstrap4.png | Bin 110060 -> 0 bytes doc/img/bootstrap5.png | Bin 20825 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 doc/img/bootstrap1.png delete mode 100644 doc/img/bootstrap2.png delete mode 100644 doc/img/bootstrap4.png delete mode 100644 doc/img/bootstrap5.png diff --git a/doc/img/bootstrap1.png b/doc/img/bootstrap1.png deleted file mode 100644 index 075930791b6e7adfa28671acf2768adaff400bb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55028 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

_AJVB12%3VER}WuS9PcIh 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%0D*Z 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%0AW|G2d_<1J6MQm(?QJx81uI?iUc37x6 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 DwJ)mq diff --git a/doc/img/bootstrap5.png b/doc/img/bootstrap5.png deleted file mode 100644 index d8d9baaf37acf58203b5c51857fb049ac894a310..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20825 zcmeFYXIzudw=Wu+bWmxcG)1W*BE2JuNbevZO{5b*TBL+feu#j8N|D|>gr3lwg(jgx zXdx&i)C6gvCEWPm`|Nwqx%-|s_ukKWarO&H=9$bhGi$!zwbsn66>F%k$w+sT4gdf! zYCV5y3;`O?`V1o zOex#<6;_q9x?SLay-uoGUJb&0;a{wnw>fI}2Z_jGnO3)KvkNYVvPxqPx(d)(ZfFdC z&Oh2qA_$cfx?A&CLiue*!ovEM4_**sjW5%}_kC>wPP}hsT{eAH*GB2`-_@l9-cIE) zatnITu1QqGHD!42KUriWH4HCxv?kxGT&o>bn2B|z-Qzg6xO-PFX&Q4&r>KeY!$=-< zd;ijk6Y$SJmBk0GBD;^&@9nhfZA-C<1`26mO?7NG@ zSm!(znD8jVHO&{cne@pjyX#xVLMNZGL1*hw25HfIHgDJMK?=#k+onWmHr}jy*!Z2e z+3j`-UvOwLn`~04TFeHSn9jSUv&x#$(Sy=5AW||AeQukmK)GmCnHPg@YBX^KtyJA^ z*J+WH(`t71yYxA@emq0o`4j(oCV0dwPe`_?-t*$;c&~ps*iVbnoIE2Q(9sLadT2fuv#Qc~ldEn8GJcw;!=`c}6Ajua zn^-CWqaqm=?)W%`HAvcIk#!HtP#uIOtIU+#X5Lt%Dzk@z(B2!y2xR8Y&{uHSF};;H z53>6_dLL{l@NmGW#%t_jx|i2qz;}q$T|$=qO)4a5gha)RJpaTvBYcEAVCr|~g{7*a z)xYwab%>fcT(;VkSf`1;I^-Aen4ShQew=e|Z3Ge+ENZoGPt5P?7s#s;%$1M&e++@# zr^KhI1&Alh#GaW*cQM*P8$q3*e%ckwEGZfZu(S6mn3of~Hl28oRFT@NE*5H&xd>d$gb3n@)W!R5!E@`AU>X2G z$^_0E1{@S6ZwF8XGP-LATpYW$vrWB{jX;QK zWMczDmh9V)+Sb$4Hm3=SQhP2>&)!gQ-LVY1ZM375Y>m6d3{3439Og-)HbdSg<2aP9hgePC4nc}20U0f;a&=nCg z4|4mYeMdp0Lr*aEbyw;B*G@VQq=}Qf8(lpV;Bd{EA1_NW1ZM87zO?yJYkofB?MC<^ zd~+6QW0=(;-n9Ph)*(Xig6x}5j$e1iF$T?PckQ`<*Dxzql<}p&NhWsefr)Q zaaUAjQc1kG2?s`Q5vv=e5=as637&)mZ$IooN0;B}oIL?4l9PbpRy)Gi6D;fdS^For z>K*rd;XZfX=JUR8(+)vvCvUKU#({v)PO@gnXYw*w57BkD9omhlwzF$jt&?6T?OEzY zlna2oYrG4+3x%adky)cx7_Pu6qH^ZnCSU5V@hzZm3trENU-7YQbAQw~zfm9d#*l#k zzE*eEx1&~1Z~Cmsd&%CjL-IlL^AirX#;=c|I9^|1U3wvy{0=L?UlT)VRLjRF`zoDX zBMhxOr%zm?LuZt-+YxNeRwbf$t*hz?mR&V!SiW!#Xm{;mnv47-tl|cX{lw4FdmCAh zyegIH_EXoEE5zT=KsJg4%~@xQm-P<_LXSt~7i`O!uN+BHdCFdX^KLzL&KpeHN;?PoR^JLqIPD~uR@eML9eF_0VB=e&OMWri-Z651;^cK#5+$Ro_O`6mQFs8(9a&_4S zLUX^tzt)d={9-I|1n}x_4I+z?d`ns&UjRO4cVpZv`j-vu-^bx50}|AK`vd6f{ii0J z;ql+fWeM2Q9Vzc~1<+p)r>Ej>B}NTYSs9L|Z5cpRig=#~D}yn7Af|s+E>n+IOF!-b zfNCnUr+LS@NlF#4cQcaoAJF4SLxL9okaYX+Lx580waD-vZL$rpdCKCd+~Lm+xl?AJ zEVhItH?8|s!Q>@NEIwR#p=pGQfLUU< zyD5Iut%+Ohu4+fTPOghS_SO={N^sdqKizguAg|vX3ctTXB!UCJmM zgdZ-K>7MmueS3jDOio25WIr$nBRlWj8Wf~}|C}%>0-wsD7KFr`a<`QFu^!rtO2?T? z_enixd)*YK@u45}a%edIS|c3F1Tm96X=m;fP@Wfx9<4vqAzHLK5G|(@3raD!>}SAw zpp$k9W%sTFNsJHN}2Ft4=MGv@Jf zm+k;^_t~mkZ@Y%aAF7sW=XP91l)E075^&=bpz5)It$6t4lGaTYAD155k|pae9kJvcV+!Q6tL35ybDWxyHJdI z$>Til>OSJDFU0uUOyLOY&u%FF1-i^K?FL| zM#&|MhZnPfe#@JkO)sF$@hxLtss;arv&D*UR6)YF&Nw`TbO5DpmlaFunhyu%cb76RUq1}X3p@zCC zP4oW42Y;S}gM*xYH5ro23m$#~a75(o$Oy=|T zzyZ~^o%1<=`R60zJ|#isPwgJ+PyIF4_r&KDk$}?$F0_pfrz!@Gba!cK_7o3At+ijC z@U{nd)Ykv0cSm=nB1l?F@NrQfb%P`M#R|EP`@nptVbbuKI&WyhHw0OzjOQ#=7HwP9 zF$SNna9vB$@bGYJl3~*n-G1IQ!~V=8AgrlNfeR|m^h^{CX;K-CpV15{f`x*bh>em~ zKYfc}Qi4|TaLsKfblj@0q%-#dso<0aE^n8SpUpXH#8 zWDVXM;c|g&H*fx~c@wOVVplCl%%~{g#gv;pb%j~&_|92Cii=GqRKC=TWmQNkM+3k#~H?+evqq}(!++j!A`A^!s6pI8u3SE?PnWb=|}wYX!U+= zf8gr82>7%g|76-5NrwvThq)sYJ%j*n&1}TT9G+;RkFx@8MtmA8MU+}BRz_ldF~z@s zzXB6aF(dxCrOq79ZjB6$xZSz=9FG=m55K16-pfgGqEF|8TawQqr<>hV;ODqFwdLim z&^6xshP}V;NOBbJy?-cp>Hp=ENxsKBt`M@LgAdAa*sB$rpd{0Imv-1{4uVdSOidSk zOh+pZrikb~k8j%R6w5q>zR>FmN*8!JXMwbv8@+q(YQmc%TO6cJm$5cGk^VDao}!fwk3jQDiZ<;y%pJr7IA(U((sG zH=kVlEhe%2E-1dHlW&MJi+j=KYpl7UVKKA0ml@^(H>^S<1@1jya#Fx`l(1RAE@su@ zK?dkpg^J^=%-SZ~aGt##xublRq_riVUsl+zxn1c& zy*-#WYT>#dv$fRRNW^PijvYv{ZzC|O=1*V$^DY;cVAZ$6NUkFJxTp79Nv2PLolWRt z=ID3Po48R3^mpNPMov~B9SvjG<0;`^W4~U34}Uzck!kqy?z_J+_EXxB#XtK$zv{Xd z)a+W9o4sgNISu~uj1gB@9(WC#w)81EM2!~$(-gDT5c$(VlY{Iu#el>oPnCcAM`*nf zu$lc?EIA}KR2;9{b~60P=G8YmI2N}{}dI{l4p*6 zF7XH$xhK)~*4_np;hQYege%~#dNf_-Sl));*&^-4_dd5ph9|2CEEhpS^YwI8#`Ekh z3)JVECp-OQMK<%Yrtefnedbs!3BZMxPPOt@O>w!$s%M+7d&O(V&}%pO89YvH^6)N* zi_y8G1t6IW_jf#+E>>)UPw=8J6_4)rn92CbAqVQJv{bkAUSEVR{rERr z>UIGr?r7{cIT*J49@jy6%(8#ud?+d9pK|MdpL@1*HnMhe2&F(j9&a9$P4mm?Z(6ch zPO<2RKeMOIWNnO|v~|RLb#zpn;XjyaWdI!%I@`0PIRd$Q%JRI-7i>||#V#D&5*Xq! zt;AMFw{@#cjN6FnL`qisq|GfrxVGRfh+JDo`)D1vUIiXkQGSFEblMdj$6vy2J>Wd% z>+nz%VZs@x!dfUVZeV;q5jAx2DvJe>qVO0%^)3kMd>eam{PEye}(H^>GRcBuS_d=~x8pG+A zhf+6#cVSeTB`K^~OJh~FU8PRAuCi}22Z*krP)OcItV}Gbo!JA^dne)Ml3oa&qcVSt zvY8GEMaw<;bT4{-);*v2=W90%a{1=Uc`s4lU=J-$I$n?$?q)Ic$yd9)*gR}Z+f`ecq22??alZ#JCXZ=JU@3_&Cj*m z2U^~{*Q$z$*d_$iWwxm~*|q^4M8%sU)H3$>nOyr5mFHXiYUy&m7DL@0$evQCX0Me z?9+rH_k;TZBap{N^;eF!t8a~Bi}%@YTh%M8>u}Uged6!JAG%`CpE&RUluCNV$c}5& zrg02YS3{by&#`xBimNQ9C0$>Tdlh?6^>vko!CwHrGyIvuYl1pPg+Xs z1~?<1M{7J4y3>$q)tqFSl?ZI=meS2oM4S$b8&?R^RL_}}qQ#ia)_ZC6h`p_C>zTx} z$zgGr!#6UJx3pzp@ik%X=cAI*>RIc;G6$4-lUD}jgAGSJ>-9&w;O3)UUHY{TP{oJ^ zCXw%ys>hN6#dXg$>EcXH4L6k7vqry&En^o`YmsP_C*0ERlR32Z9$#Emfj{ObD6F6Z__0hOb|H*nn(0!VZfR1CTc8$)1R=BGW+P( z-v;xPPMMOuK)krI6ydH-VUw;}T9&>Fy=@wd_rXS5_zgX+qr67WIC{C53X@Fi^i0Lz z=w*Gq*o#2Ez4o7v*rvA`V7si)MH>wfq5H^BzkM^3VEgeyQtOowXG;V6^F~Wnwb0pW zGdt)TyrJIls}k4Gr{Ws%vE+ar$xMIUp3+0c-~*)iCWIJR^h$iEEDu4nlEiqM8X46K zXP;RCwBvQJ+Vkk_6wzLZLmc}3#BbE!YxkdHqkvsRDZ-8$_0G;3fmqulXNvH4c0tz> zi$OF-<|u;xt0y!sggsU*$`u_Y?5cO}Moq8w(4RM5$%0So#aba-rJ^<>4$q2R1?+g!J?yBiwdL78i z<3jODQ@$e&IZhG1(Ws>y<}6r~v08d50|@+L0DC$H~EsqnprbTmrT5s)(J zH4AxJ7{q)#bkseR*&WRT81vDS5m;`d$`c{{C^`Gq?PY?OEIb@)w@%&9wCkj18*XXXA#90mRApEitG za_ieqzMcsLOT1f2`}dm5V#t!^y0>zRRjqg60g2a0-i9FOPWuIFIOSAB-q0Em{Ce{! zHsV|{&%AX5G!iz@VLJAs%Lv}x|%(vz_;_ntbG5;SLv{? z0Pt}TP<2o0*^0nD(ebc9<|*r93+f*$Dk5Mj$tZDWla?Va%=&0n@oGP?%LdZ+3Ui9g zE0A+h?Z^D~Ya@9j@4Fz5)nSsSp~@%Uu4M+E&uyVvQ)z=q(AR#JY7?o;XKG$4bM5xo zQcG7Ge*JM9rj(c&x&nZCu$8trzj6T=d)Y)Mh) zxYA6&&M`>l?t$)2m!${=xZ;(O8@Fz$W|FosogoNxGi|Z2pP8YdecHTwH)3=W4qSkN zLlPT9&yRPpj%ycKRC`Xh%`MrJzMUz4nmQ2`eo4f3qqs8cx6&FSe)>>wG1+j^Wsvo{ zph1#!*~}MJahb^rX{rTHJ=~KIrNcFz8P5s&f|!a>oYR_%6!_V@>x8`1D_ok6^{IDp zgpdU1QOklUe6w(eP1Cy%H!DBAp@0Q{3*MFNMb_*;+!d3JCR`sR1})(8^@Xp7F17SAsCkE`fsq zYTu*=(*X-qLLr-i!8?~-WlZBhHXfcD>t}fXvx;;2(}*N^+6>2ylSsfVp?^}oY-JVz zv(>fA5`j{eyt12BNi!lY)-W>fETr2?D{Wj=81=X$btMjyF(0^&It%>WX!WNn>ynsd zm2#q&&=h^T{pbh?+3vNb4Zh^?Dj*zCH#s#SAnN>4UO0}|szi*e$LfWk23RlXdvnr# z;JE!!LvsJ%%-1wlj_votJ!}gP#NqV14h55JrLX2UnM^kP;C!5(5} zP)1iBo!jgNR@l$ne|h!_g>*hzy+SQBm)R?YkDp_$!TQ~zpMuoY*4ZPOhrRDw*p5BH zFviVD)`mf^n+RF8w?AbrW#1I6<(^r=aZPm*qD9`cle4XJY>9iXZ75#0KWn}eeuB$f z7QCbM^dQa4=$0SP_5Q;EycLDXSUs$7!~+~!H$gyYM&?kLRcXMG)(i4}bL5r{x2W!0 zrWbGqQXkFM-1bc9Ba>I7NBpEVc@me|GUETAzCry{n-|xp4rva_p z)-cvb!;PX-Vx9@tySZz_2xqOMS9|2eX&*_16UN+(GZ*d&&7$4vLPZ~{&bq)#{me{k zpTL_(sR6Ea0-P*ka6d(EArI(6ziOFxQby4w0b#8ViYgy4OnC2BHHT-Mw!`sM3qs@! z4MMxSiBc7{#JAfS!54}y8{^i&+tobR+!wxD4CD~UuK!2?Kekxf6X(7UEZ9h7#N|r) z9&%eX-Ji~|ZN2{lgyO-`^Bh)(t1U4KpsxQ7o)7s{sbOv z-l$~yb?+?HFXB-%CMy#1iRCbbm91i+<2b;Yd240*eCkoPt_$9yN;>P{NMqd=CDYaY z^{cyZ@0nc{lniPM@E!;%_drSD-JZQu?$&8~_)VNqJ<{DIK%0S?ehmX!lL&kak?ao_+4V&etX+CHXx8 zz-;SwxGmT(6%HXp)abMfbmY~q`+*Oc@6Xq$5wV6wMzN)DZJ;`1f6D(fT1~dn`4YD} zl>y5yq=abREA>f`U4!27Key{D;~hRN@VY#>>jXWRUeau4H0cj?IO_|tnUd}>1tzfy zHEh&bt??Rv{}ttKkzH#BJUR^eCmh>e}g z=#!QVpvB2GqXx@c+H5SlIcebM|0J^3Q76Ikmq^{Mk0$(bF9<+Hw(!%F5a86HWw$S& z(1hlX9#6Amo95QMPRO>mIHcq^e~Gq|;7dZ$kpFkqw4HQ7ndrw`d~;q#orUTF7NN{X zTl3E#5OC)M)$aCpM@fNrb85x+{<$LVcfqw)?+&g?n$uRM+12{77uC~pTBSD`a?(12 zp^S{m$N-5oe{1_@F|q;yA@2n^w6F-+TNyQJg_+vQaw2J5Hkv$Nwop#53e3#` z%c1Hc%Qxi`i@0p;Yrw74^soY;;I1Uq`F;b<8n=+?_^0b3*Q6?RW%Pj#>Maw#EIZFY z$bycSY?-5hK`%s8-@Ow(Le#>xR-|(L0zGWPPS^B5f}|GMg!Gch+n&!o(AWQxZx1Q! z-LIlQwuElJB$T~VlC}@QzaRxwOfIK|uMl#=_tM1t`MPH_5)&CrD!6-`yJo|rPJznO zvN{G`=}OQ+vn?^Wnx%2pJ!4WGH$U70|RJvznVu8A%KypuW zf;5L)X(#V}D-8Ix%+$tL3LU|*RQ!x-8lQH78R@WX?-h`1G~XYueb#JzvFsye*`{T1 zxhtth{AHLEV2iS-fHtdsGg!UH3uHMe)5OMHl!j?Pm>Au-{Ay zf3Z`CiqQ3?!#X*QbgqJS=XVcr;vypc#3gMVoq&@)2NShLm$Ze*-^4ibA{+GjTz?cb zvpnjBC+GAP_J03cc8ctG;0^6&IeCmGV^X|#@h?9ZYJc_AYrQk8;vUTF3HQE;-VMBd zIl<$C*un(;vm1rwrL;@VO#F74#vRoX|865IN*$(n$c0ciOl1c`Mk(!}IT5pgdjYPl z@9*4E*Ii~S-TQbQmiWQ6*$dnx=#mr1%st`4$?JBiDLP%Y9R|kCcvt9rd4SEWs;G!J z)%Xt-?OQ_sC|7M>NZX&U$RPpCPPb*1I+{BA$Kn^~D)-^FNRwuBv4S&-@GYCj&$g=h zStGS2S2r7|;x7rm4uYL}A)8D6<_e&OlXFP_=KLG+Z3_bff8>6UoLlZv5W$(SRg$2e zcVvh5FRke~H6!ffk&38T_m#!l8{r)-K8J)S3-pJA%zwDnNs z=VAV7&k}d6F!IV~tn8^9*^Y)&&s8E*L+Nl{ibCpwk zc>XDaJ~ga7zV9VI8+%K_?DQ8V@^Jp&};=7Ix0w z#@M!!%(wk)ZCjO9+2%I^;rK+uxyveLK>O4gvM4qLN?lqLN+I1)KVY^_-BDW_t#(? zjsMNl)vBCK;#V0PpFnX$M^&wi*J3r{oH>2eusj%#tzhDwSA?Bg!#xAAS68=rUgK`8 zwtIX$*zR$jS9zz|H1(0J^Juovmxa=E=E4mn?f&-TP1h-%KBQ%)B+if9vsn`&=lgD+ zXi-QP%s#NBEcWP;x|sDl#b!zryzE8$1l(0MKEhS(t zlXTQeasUl&f}Z|EN3Szg@#LSO><5&kQ&yAq!-k5kA8oD~z7kGjr$J&hdN~p)PE163@0&_%ewYHs!_%coB8xKX#}X zvz_2{>j)xnwaxjdrm`Pi?cU|<@=5Z#R{^<1;+7TRq19DxWQ}i0GStthx1&H zQU~LD+UJ`$^%7KSqr9|r`ABzIQ!C`Ye%9mK%&OIDB_>bzjG@d{ayczZ645N7(9HbFpODKLW z4tZH@wxI1)NY>~=9?|E6J&g+Zu{Sdmr(}`@6q=eG1y`JU*C0*&RHs=+A541WJ(yf7 zWK(!zxB1RtH{f!WHq-wcG!3HZao=-eVZ1(soIN#dqf6f*ebT1V#o9~Pf3DIpH zzYP<*s$(R>XXzC*n~gnnsi6y@h6iX=HC`26A_M&zfN8$s{(Vfp3?cX4u^wmu{+f+N_PIoeY`OG?8l+u`j>53*$NcT*^zI~J(e{9Sbt z5^$JM%Q^8j53eAbZlXzH`@2zZ$Z2NUNaxZf#1m#FWi0pLq*!!)7R-vq|HRdu6Vfs+g8P@^&W25GLVkHFinQ zQJ@3+qm7r{+GJBeP3(it!wGfZT!&V@%hAl1wpN@z3`U?PU2(dQ=Tx)Tj=3&5>5o1z%PU&Ke3xO#j@s%KNf(Nm;SQ zBb%5gO9Su;u4{Hz_TTt;u)qMdZVv2w0{~prEutn1)a}`tu1Y#(FL1r_uRswg)1oEr z0XSfmM7F;HCsn<>gK(<+V9~$Da1+fUCWgM)#~?mZN$P1b;nl;xkJo>-M1?P0S!*K& z(vkvNsKl#x^>zM!UA~tP{IA~v%2fXK`u{Nw)eMU{+8WG3Q z&g_CF3nHudtyq?Z!Hd-_mcDAAKX#ekv$8ASd_mZ56Ll%gp= zDXf#e6xbTAqas$wJRBH1+wp{s*3mmk_t?IDRVp++^H5&cM$)tTA=q~pfjBPAO0RC= z-0a$2*K4@t)-dNfJRJ1MukS9x?^u2^qe`n>{^P_y^&)=jp&VrmL0tkvQId~XEj>Ub zH`oxl1rsft3a&G%rX|M$vt4~cs-3=BgbI^IjLfh{TsBWtXqLBem}hCLVJ0SBLF*Si zYNd{2N6W;_|6PVmt*mFZH;S-+6r+mmwig)c@UiPcC0X~H$ncpv=o?-E^bfS=-b(Jv zsLIG;4igKct8%u~5RL5YS`dFX53l%`Kj)lb^ZJXj!-EKEn+1yPS`WM2!olMg)xls4 z7vTbKhz*g)zR6mhnn%LB`7p~93byemukVLajc;=s?a;zEjmCe>l#%t{phQQ6%Sr*S z+7rk6Jo);XEy)jb zvkr2^TWx%v-Z@*%@sW3+#xb%%fXD}s<4z|>(u6>zsoJHi9|oK!Ap^y1UuA_SXql9y z7iO~+2}_neKWYu@XYy%wyX#h;=}z|#@oQiXS{|mt`4&w8fci$iF^nR)Kj{U*#Lr8VhH2T7&@e%t2fA`N9D`Y!ACTHHB zcs$6qBHega@A^#CGkCho^tDLyt+0AMSV~2dIhra7TmI5X6H*HL9G7%-FVp`1aHyN< zR2x7IoI!5UCdt$DT)*0!AMAcnf0nayILG{APS`bz<&6^BAwg_bBKPJA z6QzEN05f^$3i(7zcJ}(ri|?*#)vZGJ1hZa(l){Z9TxWmbL`>UnwDa==&sY?4e`ZZ8 zr8mrid_BdUTCMdIjQtR%%aR(gVEN>nbq|~!3Yx!GSFH{_r|Xl6R)EPItEbm|ZDELR zOO^Y9M;N-kDpYq_v^ZCJ)t9*@%^c>N2{t%W^8}RLU)cR2W-lOkhP`UK0Bb2cK6?X! z9C;$NGw)&Id*qh3@%0L6xNJJou9%!1qV{?U-ffTR>1?7l>s;>+{;39am+P}9O{Sw@ z)4FF^qX$%>+NRa`N-6vou7A^`E4!N2E^v28W2Cj`l-lg{bM2i-zK7U01P8nNC%(abyPE5k$X z%BJ4a+S)s@=Vst~I(@ajopi|8^cRI&?dL!A;i@J7 zAxkrmTXJ$@ITYyfH?mbKQGk*BcTpiL+sDsoE%a9xKNp|nG|tadjjB{aSMCbZSQi#= zof1v26;IbOc|Z6YS~}e%M)pQBCHG62Qr3iv(8?S4GY=>0C)blv2Wd5&Z;X9kbvT=; zy1}3pXz+<%CZY(ZqB zzgCgPLMpK&qbh_@>bv(r8YBG7k;U`2lAdsU6%XkUX&S_9=Hvl>2mUa*Ow@m7IM>J{ zOBT+^;Or3xmL$nwY)2Y+^`ndp{{_{b?+l2RQ44D>$$PMdD?zr^rK(0SQLV8xXGq4% z#c6WNPSgF@9_FEiQlki2xAhw=tRDuZOfOX?SW+Hkn7_YyPcRej@=xi)fWyR;0_m78 zBTz#)5O9qo=bnn+cLS;Egx*unOf1xha&A|#k41^ep8KuPR9xE2=a@Bch-#3XnjZ%{ z30cMx!5`9VnwoT-=A0x8q)s!$=~U92wkZVwF^@hx2*SpYR)} zEaMDvRlZrIsLjeb1S-%=&%Om^~}s3L#C&FR}H+UL16ceI#KbB@KTB z@pY~?afKQp_lv%}4()IbJ@?P+FTNWRb1Ou)FuY@E!CJ-%>=)Kw<*<1HRrt0l(`4bm1X zXaTuhVSV26?=CK=yG6@LnYzW#Z0#@e0;&I!$;bG=Ps93u&#C{Ea34Sphxun>_mdSt8SI9cbHznth-32|J9D$BbVA#A=&oix2oB z5n1wmmK>yR5C#V{UN0FPFf8m&v0YK=b9Fvr_#rR-OF;GXI&2@x zT}RYyOv@P^Tb{$hW0UV)HZ}5|cVuL4@o3rxM;Z&9ABZOP2g>eGf5|KS%%b;DQhgG* z`q0fihw8jq*KUAiTdI*HkY&@c&`5yE^X^e}RPm*~-D8E2dSlj)-g7m|WZQio^bB9_ ztJ`^~>7AGBEuWdcjO?3ls7A^7%s=pJV{L`f5^r9TIBlkwE8>YP>X?O{-q8Lx ziL^de^23f+L$6G(j?VmMEdzC5@9Rsq=~ooH{>K?Z(%B0Q^QPQ7S6>dNRO~0*&J7)| zWg$&muZjfN3^*@=rdcsTi{JQqitV<|>sL}v#|%z)&ApOes2m(s`^Rj%u!8kQFO)hCohUTFg zL?2Gv+m&3LCIh(IdKRckNtrr0IIs(?vElozTr;@R~twXtmgfSjf0ZkVNIhRVeTzidCIK}USr(j}+l zU{uxaTMV;Bt!*bOC+8-^^(%ndNp|7{)g zw>2+oSzyknVOAn4;1a=6Y2ECl?*XtO9l8oeb&G!7J>XRhtj^l@`=i0(wzu3%BEZ$< z^vH1AC*npiJQ4y|+$Z<5 zJ;>Q+8I~0wUQYogASoeNeMooPNAa<5kbCtMQPfOa&#wZOQ$Q0@;Y$KE@3*9%@9JIM zixIXkYt6q-x%{+p^INy?n)Z*rKGOMe2OmHG6MoIaY6%*-Mgv}u81LUv#FsLVZ?&Kd z-kWSN>ymb!(p@ot{5Nk#4M?Us8y*)QfApuH*W=gMXl*^cX+>N|5#;h59ehc^AN5l6 z$_?tDW0<+*mc1;S=fkq=;7$m#e;IjwYq;Vsq#Xp>>WA4n#pGG|`ZnZ-VC9t$h9!fK z=Uj4vvb-lnYdZ=_<7u&;8Cj|y4ph8P3LKcH#<|XkLMGe2N0IyZrSU}W){#f;`hFUJ z^;h_0rr0d6(%U+11^*30jfRy3Iy$eg13)Cnc~7ymx2|^**vH+kW>? zx!Jf3A!PH83->vH4BV{e3O|DO-v;Ob*D*Ze>&f%P=kqW0WE2;dSK=v) zD;^^4;mhA5+?%3EQRn&RqhO%R0-Of)ry}KA9%lBw-Nj=ka0Q<}`eSfMtkI2zpxU?OOJA+Pi8w zUN*o|R|kBOS2FaH06S0=L}+zJg%8Ht&fNXs*0&>E862}-Y77nMl+>sQs>t;9Wh#wL zM`ov2YaQ&Td}>nA52a)luYC`D{{2#`U$#Yzq^&TxDT}vN>BDH*Tl1Aj68U( zu(L0^_;iSMvmm=OwqzVLC(6%H}0RR+p1Tqi!8Zu*v2%j4MC*tXO4 ztbj>9S>fBaAF~MPj^%)sDiXOB6&^>3Eh78S{g5>hB)%0qhjrOEkaD?fjmF3I=^yte z=9n%Wd9wWjH*>?@)Tj=z`N9)yiQ#^kZ}7!ps!5ujl&p9BTdJj7k(R4!9Aw7ss%gh> z^4%g$cpAUWVK@}94`m#(k~Cha4g7L+tNc@!FzNP%7CwVw+J{Aj0UJORR^4Hpk0d2w z&WM|sHzbK$HGAc-0Ghl|^Rxic269n(Y8X=W8_wNcxo}DwC$nG`sJO7^GK~=pc#@ak zj$C6%ecEJU>Dpqcs=Ltqy2@hM-UYS(`$iO?**q+Em*@K0QwuE}Pw!7}?T~EAzeOu| zl5CrOGk*C?{8>B4udFOQ5FW%z8pV>LoAo9&(~q)K$*r#}Zd!UFGpus?!)B_(cilg- zt;$hQDLac=H~x+iYuu^NbQ+1ApMh?p8# zqFL5ow`KsslMzhEj63Hzg9wTU;4jq7@&Z;puuX*`3K)LP+`Qc33ANiPWNExF;nsA6 zla7lj=EM6*(W(W}sryOp=w~I@jNBJmlg-%~jCC&~usoSDE3UK;qbK`I=7NHTvShUe zV~sMa=k&Wp6!T;Vw05_ruhn^-F}R(r4t+g;zZnNZ*(^G7#zs&bN;xsW&$G*d1msbl zCJ@1-OQoL_8JGbsi*E-O;KVs?394=TNN$(>`NTQ)51K;vZljuqiz{Q?zX%R>+(3K0 z*#D=re}ujPdjrAn7E!?l_PM~kF10Me9#~xB2WoRMRWpvY#|q;g(!U-iQP3ZyMsMrP z+;cm3EXsMAkXsn@Y-IX-E{hX!TG}fxe;k?a6u)Cr5 z&0*^k#=o2(yHtJz&ka=SiSZ`nJ=pCuD6m$U3b4p2djO?B9N))_Ub#%v>d?Wl+my4- zQBT)fQ-hm~6fWBoGf}(hN&GZ4H+Ua9XPf*V0SXEA_E=3A>lRd<`3$YED2xWI8#6^y zC#5OVR+we4H)~DOIDa`YaG4`upLH_Nai6=Rz~{Hm5jR8rMKM#Rnq|QRInF?}9dq_# zrKC;L)F7SaQzrWYgo<);|G|n&P7GcnU!#C?Qjhaj|M$pM-}6<=u^;t1(QGW6c8OD% zt}I0N(_L@4h2v`$nP9-ylG_6KC0du{=9^OO#F}dAZ8xDcS!Qjs-$iRQK54v-0?hmd z*%-j-PGnmhYytWbU!c)*;#{p}^He1^t7zhLo2;RGQ zuXgO%p@Unus`E=PY4@~g3VG}?MVY*=UAww_I9iVRUOX!-Lx;b7M+IN}Q+pTAP>6#u}^wpQ2J3)eNRTy>IXvK_sK#O(`QOK}wS9BX{PENv@fNZVLa3`C!#y-w8lj4*X z7*&`;d#Y30J~>F2nr1BMvDffA(JXA3Gr<&4=T_GCS65NE-Jo?V18V=BR)HD{$NjF> zcrDP<4a>A>&3Iis+Rm@jh7C(iZeVvK^Q<)vE0^dMgThsnyryw7+ zJ5U8XuECvj1bZ$3!0Bq+wr$#K3iTKNV%Dx=#@|QtM{3GoZkenEdrM9B9vcH zs6D%OICmBD=tjBAt*^g7g>{QLu(Y5C>Q&N>aBTgAdRm<1mM4Z0{ov)gX zJ=p795-^@1*fdUjnbMvG>xv&{g$+Vy_@HN@sMBENAexB8_3l9T*t}od*y?g<(?~NT!n8E0C1AoKKgdBumAr4f#U#d`o_V7>fNP_ zVjp=#gXYZ9puhiJ1-*MK^MME4JsfTDxff}{#@?Ej6(yCGs7zsM(<(wC5p5I|747^c zfNc%xsrS*$zUCHF7);aj$;WcP`Z&dA`f7}$oc`vv zKf5(XGo60y?f}yfDN0E9FRN~h#!WKMUokMazRYvD{o(C%Ojbh8-CG>Njx$hg#~h<6 zsq+*&eS~kBN!1T^%*=Epq?qOQzW@H;05EC9^w^-?h=Oa#`Kzybp07HNy~^u!^Ki0k z(43j3Xle?pm)PzwZko2Nay)>qn~W*?zhS$^jMihzAJUqMZobp!{V|h!w0<@USm}2C zap%{}T~m2yA$MPT@RG{sajNly+xKIa+i+ww&LC;>jb@{b7DgLHAmAWlj?R)l6i>Tfj-+8URoI6ebe*PhS z{M^rUPR=vBqURp1+7+($9XdGU0Z!zPg?;wfXHIH}knz8Iz5I=buXksCdJnryQN0GK zeb>JFiFmPJo%&wmM_=23l`|>m2lu9Lq%3ZfvX(#dvpr&$A zefR@_^UgcZd9?0+ag(BY4shqH%31x<$ruxGaxHmcy3*nXi(Bsl005kxY{kF@7hIsT z&pum2h73{PzJ1lHQzv!r-d&NAkxuJv?5}>M($1Zg{=M&M?f?9bUK=+~+dlkIqyG9= zcP~e?g@1pmf^B8E>f85eWyBbztPa=P>4)^@r$_YKx?ajX>!%G40FH+({09aA_2Gda zpz8hX6O$)tUUT^MT>t<8oG^AgKwjQ{?caaE84!G=q(nu<#j@jbb8>UFub@ydGyklx zVZ+pW;zUK8LiFgr{6*c)I?LTda5fmQtpc`?fA)wAG&=D|y7=2a*Ja z*Up{Qqepk0(Yv?0ck8NN{rc*nM;_4?Pd=%uP3kdxxVv@TY#>luA-}nIN%TNV00000 zaC!;s0z`Kp0002sG!?81P~dcZHNoA1fcgt|cOU@X!`*=Zcuie*2l5y6ZLNQ>X}`Me z4nzU@-&rB{I|~4Cl%PRC zuVI%d+C&cB23_D>P}_FyU2#FR_e2E%peflO-aIl-}<5XPr8blBP0QD3!2mk=!RADQw zqI(Zk_aUPQ0sx>MY!JYxDFDDJt-QR Date: Mon, 2 Feb 2015 21:19:50 +0800 Subject: [PATCH 34/81] Add x86_64* i686* mips* and arm* to depends .gitignore --- depends/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/depends/.gitignore b/depends/.gitignore index 82c48638b..1f163897b 100644 --- a/depends/.gitignore +++ b/depends/.gitignore @@ -3,3 +3,7 @@ work/ built/ sources/ config.site +x86_64* +i686* +mips* +arm* From 0b2f93091f2a30f994bee2a006d66771b92eacca Mon Sep 17 00:00:00 2001 From: charlescharles Date: Sun, 8 Feb 2015 17:45:13 -0500 Subject: [PATCH 35/81] Fix docs for 'complete' field in 'signrawtransaction' response --- src/rpcrawtransaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index c979217a1..8393a8502 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -419,7 +419,7 @@ Value signrawtransaction(const Array& params, bool fHelp) "\nResult:\n" "{\n" " \"hex\": \"value\", (string) The raw transaction with signature(s) (hex-encoded string)\n" - " \"complete\": n (numeric) if transaction has a complete set of signature (0 if not)\n" + " \"complete\": true|false (boolean) if transaction has a complete set of signature\n" "}\n" "\nExamples:\n" From 9bdd03fb406da991bc7619b28a609c635cca488b Mon Sep 17 00:00:00 2001 From: Michael Ford Date: Thu, 5 Feb 2015 21:33:27 +0800 Subject: [PATCH 36/81] Point to the Debian 7.8 installer Link to 7.7 is broken. --- doc/gitian-building.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 25d3b8390..d285fffdb 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -74,11 +74,11 @@ In the VirtualBox GUI click "Create" and choose the following parameters in the - Disk size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side - Push the `Create` button -Get the [Debian 7.7 net installer](http://cdimage.debian.org/debian-cd/7.7.0/amd64/iso-cd/debian-7.7.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). +Get the [Debian 7.8 net installer](http://cdimage.debian.org/debian-cd/7.8.0/amd64/iso-cd/debian-7.8.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). This DVD image can be validated using a SHA256 hashing tool, for example on Unixy OSes by entering the following in a terminal: - echo "d440e85b4121f94608748139f25dbce1ad36771348b002fe07d4d44b9d9e623f debian-7.7.0-amd64-netinst.iso" | sha256sum -c + echo "e39c36d6adc0fd86c6edb0e03e22919086c883b37ca194d063b8e3e8f6ff6a3a debian-7.8.0-amd64-netinst.iso" | sha256sum -c # (must return OK) After creating the VM, we need to configure it. From 30c1db1c612ef2622d4eb72f0b7f12f311cac7cd Mon Sep 17 00:00:00 2001 From: Nicolas Benoit Date: Tue, 24 Feb 2015 18:32:34 +0100 Subject: [PATCH 37/81] Replaced current function names with __func__ in LogPrintf() calls. --- src/main.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8dd61a372..75738dace 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1233,14 +1233,14 @@ void CheckForkWarningConditions() } if (pindexBestForkTip && pindexBestForkBase) { - LogPrintf("CheckForkWarningConditions: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", + LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); fLargeWorkForkFound = true; } else { - LogPrintf("CheckForkWarningConditions: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n"); + LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); fLargeWorkInvalidChainFound = true; } } @@ -1298,10 +1298,10 @@ void Misbehaving(NodeId pnode, int howmuch) int banscore = GetArg("-banscore", 100); if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) { - LogPrintf("Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", state->name, state->nMisbehavior-howmuch, state->nMisbehavior); + LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); state->fShouldBan = true; } else - LogPrintf("Misbehaving: %s (%d -> %d)\n", state->name, state->nMisbehavior-howmuch, state->nMisbehavior); + LogPrintf("%s: %s (%d -> %d)\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); } void static InvalidChainFound(CBlockIndex* pindexNew) @@ -1309,11 +1309,11 @@ void static InvalidChainFound(CBlockIndex* pindexNew) if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) pindexBestInvalid = pindexNew; - LogPrintf("InvalidChainFound: invalid block=%s height=%d log2_work=%.8g date=%s\n", + LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime())); - LogPrintf("InvalidChainFound: current best=%s height=%d log2_work=%.8g date=%s\n", + LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime())); CheckForkWarningConditions(); @@ -1921,7 +1921,7 @@ void static UpdateTip(CBlockIndex *pindexNew) { nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); - LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", + LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", __func__, chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize()); @@ -1941,7 +1941,7 @@ void static UpdateTip(CBlockIndex *pindexNew) { pindex = pindex->pprev; } if (nUpgraded > 0) - LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, (int)CBlock::CURRENT_VERSION); + LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION); if (nUpgraded > 100/2) { // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: @@ -2936,7 +2936,7 @@ bool static LoadBlockIndexDB() // Check whether we have a transaction index pblocktree->ReadFlag("txindex", fTxIndex); - LogPrintf("LoadBlockIndexDB(): transaction index %s\n", fTxIndex ? "enabled" : "disabled"); + LogPrintf("%s(): transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled"); // Load pointer to end of best chain BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); @@ -2946,7 +2946,7 @@ bool static LoadBlockIndexDB() PruneBlockIndexCandidates(); - LogPrintf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s progress=%f\n", + LogPrintf("%s(): hashBestChain=%s height=%d date=%s progress=%f\n", __func__, chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), Checkpoints::GuessVerificationProgress(chainActive.Tip())); @@ -3492,7 +3492,7 @@ void static ProcessGetData(CNode* pfrom) send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && (mi->second->GetBlockTime() > pindexBestHeader->GetBlockTime() - 30 * 24 * 60 * 60); if (!send) { - LogPrintf("ProcessGetData(): ignoring request from peer=%i for old block that isn't in the main chain\n", pfrom->GetId()); + LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); } } } @@ -4394,7 +4394,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, bool ProcessMessages(CNode* pfrom) { //if (fDebug) - // LogPrintf("ProcessMessages(%u messages)\n", pfrom->vRecvMsg.size()); + // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); // // Message format @@ -4422,7 +4422,7 @@ bool ProcessMessages(CNode* pfrom) CNetMessage& msg = *it; //if (fDebug) - // LogPrintf("ProcessMessages(message %u msgsz, %u bytes, complete:%s)\n", + // LogPrintf("%s(message %u msgsz, %u bytes, complete:%s)\n", __func__, // msg.hdr.nMessageSize, msg.vRecv.size(), // msg.complete() ? "Y" : "N"); @@ -4458,7 +4458,7 @@ bool ProcessMessages(CNode* pfrom) unsigned int nChecksum = ReadLE32((unsigned char*)&hash); if (nChecksum != hdr.nChecksum) { - LogPrintf("ProcessMessages(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", + LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", __func__, SanitizeString(strCommand), nMessageSize, nChecksum, hdr.nChecksum); continue; } @@ -4476,12 +4476,12 @@ bool ProcessMessages(CNode* pfrom) if (strstr(e.what(), "end of data")) { // Allow exceptions from under-length message on vRecv - LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", SanitizeString(strCommand), nMessageSize, e.what()); + LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what()); } else if (strstr(e.what(), "size too large")) { // Allow exceptions from over-long size - LogPrintf("ProcessMessages(%s, %u bytes): Exception '%s' caught\n", SanitizeString(strCommand), nMessageSize, e.what()); + LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what()); } else { @@ -4498,7 +4498,7 @@ bool ProcessMessages(CNode* pfrom) } if (!fRet) - LogPrintf("ProcessMessage(%s, %u bytes) FAILED peer=%d\n", SanitizeString(strCommand), nMessageSize, pfrom->id); + LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id); break; } From 52070c87fda663e1f074998fd95fa1dafff667f9 Mon Sep 17 00:00:00 2001 From: Nicolas Benoit Date: Wed, 25 Feb 2015 18:40:32 +0100 Subject: [PATCH 38/81] Removed '()' where used without contents inside This additional patch removes '()' from current function name in LogPrintf output. --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 75738dace..c6a936c5c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2936,7 +2936,7 @@ bool static LoadBlockIndexDB() // Check whether we have a transaction index pblocktree->ReadFlag("txindex", fTxIndex); - LogPrintf("%s(): transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled"); + LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled"); // Load pointer to end of best chain BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); @@ -2946,7 +2946,7 @@ bool static LoadBlockIndexDB() PruneBlockIndexCandidates(); - LogPrintf("%s(): hashBestChain=%s height=%d date=%s progress=%f\n", __func__, + LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__, chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), Checkpoints::GuessVerificationProgress(chainActive.Tip())); From c0692346654e391fa9bafc0a9a32ea7370751e11 Mon Sep 17 00:00:00 2001 From: Michael Ford Date: Wed, 11 Feb 2015 12:24:38 +0800 Subject: [PATCH 39/81] Fix typo in init.cpp interpration/interpretation --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 4d9c233c8..a3c9a8043 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -123,7 +123,7 @@ public: LogPrintf("Error reading from database: %s\n", e.what()); // Starting the shutdown sequence and returning false to the caller would be // interpreted as 'entry not found' (as opposed to unable to read data), and - // could lead to invalid interpration. Just exit immediately, as we can't + // could lead to invalid interpretation. Just exit immediately, as we can't // continue anyway, and all writes should be atomic. abort(); } From 447d37e7d3e4c1a53eaacaae5f5c34bf98739f22 Mon Sep 17 00:00:00 2001 From: Michael Ford Date: Wed, 11 Feb 2015 12:27:21 +0800 Subject: [PATCH 40/81] Use https link to bitcoin.org in Doxygen intro --- src/bitcoind.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index a0a96c2df..2172f4a21 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -21,7 +21,7 @@ * * \section intro_sec Introduction * - * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/), + * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (https://www.bitcoin.org/), * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate * with no central authority: managing transactions and issuing money are carried out collectively by the network. * From abcec3082e4eb3d91ada6144090d7f1ea46b7d3c Mon Sep 17 00:00:00 2001 From: paveljanik Date: Thu, 5 Mar 2015 09:51:52 +0100 Subject: [PATCH 41/81] Update REST URL to match reality --- doc/REST-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/REST-interface.md b/doc/REST-interface.md index 23154ee90..f14aed728 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -36,4 +36,4 @@ Only supports JSON as output format. Risks ------------- -Running a webbrowser on the same node with a REST enabled bitcoind can be a risk. Accessing prepared XSS websites could read out tx/block data of your node by placing links like `