diff --git a/qa/rpc-tests/finalsaplingroot.py b/qa/rpc-tests/finalsaplingroot.py index 59b184f03..4298ec20b 100755 --- a/qa/rpc-tests/finalsaplingroot.py +++ b/qa/rpc-tests/finalsaplingroot.py @@ -9,6 +9,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, connect_nodes_bi, + get_coinbase_address, initialize_chain_clean, start_nodes, wait_and_assert_operationid_status, @@ -56,7 +57,7 @@ class FinalSaplingRootTest(BitcoinTestFramework): assert_equal(blk["finalsaplingroot"], SAPLING_TREE_EMPTY_ROOT) # Node 0 shields some funds - taddr0 = self.nodes[0].getnewaddress() + taddr0 = get_coinbase_address(self.nodes[0]) saplingAddr0 = self.nodes[0].z_getnewaddress('sapling') recipients = [] recipients.append({"address": saplingAddr0, "amount": Decimal('20')}) diff --git a/qa/rpc-tests/mempool_nu_activation.py b/qa/rpc-tests/mempool_nu_activation.py index cb54cb7e8..ed55dcfc0 100755 --- a/qa/rpc-tests/mempool_nu_activation.py +++ b/qa/rpc-tests/mempool_nu_activation.py @@ -7,7 +7,8 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes, wait_and_assert_operationid_status + start_node, connect_nodes, wait_and_assert_operationid_status, \ + get_coinbase_address from test_framework.authproxy import JSONRPCException from decimal import Decimal @@ -43,7 +44,7 @@ class MempoolUpgradeActivationTest(BitcoinTestFramework): self.sync_all() # Shield some ZEC - node1_taddr = self.nodes[1].getnewaddress() + node1_taddr = get_coinbase_address(self.nodes[1]) node0_zaddr = self.nodes[0].z_getnewaddress('sprout') recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] myopid = self.nodes[1].z_sendmany(node1_taddr, recipients, 1, Decimal('0')) diff --git a/qa/rpc-tests/mempool_tx_input_limit.py b/qa/rpc-tests/mempool_tx_input_limit.py index 34896a756..dc1ab125e 100755 --- a/qa/rpc-tests/mempool_tx_input_limit.py +++ b/qa/rpc-tests/mempool_tx_input_limit.py @@ -8,7 +8,8 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes, wait_and_assert_operationid_status + start_node, connect_nodes, wait_and_assert_operationid_status, \ + get_coinbase_address from decimal import Decimal @@ -50,7 +51,7 @@ class MempoolTxInputLimitTest(BitcoinTestFramework): node0_zaddr = self.nodes[0].z_getnewaddress('sprout') # Send three inputs from node 0 taddr to zaddr to get out of coinbase - node0_taddr = self.nodes[0].getnewaddress() + node0_taddr = get_coinbase_address(self.nodes[0]) recipients = [] recipients.append({"address":node0_zaddr, "amount":Decimal('30.0')-Decimal('0.0001')}) # utxo amount less fee myopid = self.nodes[0].z_sendmany(node0_taddr, recipients) diff --git a/qa/rpc-tests/paymentdisclosure.py b/qa/rpc-tests/paymentdisclosure.py index ca73fcb6b..f483baa6a 100755 --- a/qa/rpc-tests/paymentdisclosure.py +++ b/qa/rpc-tests/paymentdisclosure.py @@ -8,7 +8,8 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes_bi, wait_and_assert_operationid_status + start_node, connect_nodes_bi, wait_and_assert_operationid_status, \ + get_coinbase_address from decimal import Decimal @@ -48,7 +49,7 @@ class PaymentDisclosureTest (BitcoinTestFramework): assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 30) - mytaddr = self.nodes[0].getnewaddress() + mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # Check that Node 2 has payment disclosure disabled. diff --git a/qa/rpc-tests/signrawtransaction_offline.py b/qa/rpc-tests/signrawtransaction_offline.py index 34e29aa25..a4478c3c4 100755 --- a/qa/rpc-tests/signrawtransaction_offline.py +++ b/qa/rpc-tests/signrawtransaction_offline.py @@ -27,12 +27,12 @@ class SignOfflineTest (BitcoinTestFramework): assert_equal(0, len(offline_node.getpeerinfo())) # make sure node 1 has no peers - privkeys = [self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress())] taddr = self.nodes[0].getnewaddress() tx = self.nodes[0].listunspent()[0] txid = tx['txid'] scriptpubkey = tx['scriptPubKey'] + privkeys = [self.nodes[0].dumpprivkey(tx['address'])] create_inputs = [{'txid': txid, 'vout': 0}] sign_inputs = [{'txid': txid, 'vout': 0, 'scriptPubKey': scriptpubkey, 'amount': 10}] diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 0a57e6ddf..77abec55d 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -419,3 +419,19 @@ def wait_and_assert_operationid_status(node, myopid, in_status='success', in_err return result # if there was an error return the result else: return txid # otherwise return the txid + +# Find a coinbase address on the node, filtering by the number of UTXOs it has. +# If no filter is provided, returns the coinbase address on the node containing +# the greatest number of spendable UTXOs. +# The default cached chain has one address per coinbase output. +def get_coinbase_address(node, expected_utxos=None): + addrs = [utxo['address'] for utxo in node.listunspent() if utxo['generated']] + assert(len(set(addrs)) > 0) + + if expected_utxos is None: + addrs = [(addrs.count(a), a) for a in set(addrs)] + return sorted(addrs, reverse=True)[0][1] + + addrs = [a for a in set(addrs) if addrs.count(a) == expected_utxos] + assert(len(addrs) > 0) + return addrs[0] diff --git a/qa/rpc-tests/wallet_1941.py b/qa/rpc-tests/wallet_1941.py index 01bfb8cbb..7a0c482a7 100755 --- a/qa/rpc-tests/wallet_1941.py +++ b/qa/rpc-tests/wallet_1941.py @@ -10,7 +10,8 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ initialize_datadir, start_nodes, start_node, connect_nodes_bi, \ - bitcoind_processes, wait_and_assert_operationid_status + bitcoind_processes, wait_and_assert_operationid_status, \ + get_coinbase_address from decimal import Decimal @@ -48,7 +49,7 @@ class Wallet1941RegressionTest (BitcoinTestFramework): self.nodes[0].setmocktime(starttime) self.nodes[0].generate(101) - mytaddr = self.nodes[0].getnewaddress() # where coins were mined + mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # Send 10 coins to our zaddr. diff --git a/qa/rpc-tests/wallet_anchorfork.py b/qa/rpc-tests/wallet_anchorfork.py index 3dfd3c46a..f136498b1 100755 --- a/qa/rpc-tests/wallet_anchorfork.py +++ b/qa/rpc-tests/wallet_anchorfork.py @@ -8,7 +8,7 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ start_nodes, stop_nodes, connect_nodes_bi, \ - wait_and_assert_operationid_status, wait_bitcoinds + wait_and_assert_operationid_status, wait_bitcoinds, get_coinbase_address from decimal import Decimal class WalletAnchorForkTest (BitcoinTestFramework): @@ -45,7 +45,7 @@ class WalletAnchorForkTest (BitcoinTestFramework): # At this point in time, commitment tree is the empty root # Node 0 creates a joinsplit transaction - mytaddr0 = self.nodes[0].getnewaddress() + mytaddr0 = get_coinbase_address(self.nodes[0]) myzaddr0 = self.nodes[0].z_getnewaddress('sprout') recipients = [] recipients.append({"address":myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001')}) diff --git a/qa/rpc-tests/wallet_listnotes.py b/qa/rpc-tests/wallet_listnotes.py index 5e5974e5a..ad2d56e1f 100755 --- a/qa/rpc-tests/wallet_listnotes.py +++ b/qa/rpc-tests/wallet_listnotes.py @@ -6,7 +6,12 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x." from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, start_nodes, wait_and_assert_operationid_status +from test_framework.util import ( + assert_equal, + get_coinbase_address, + start_nodes, + wait_and_assert_operationid_status, +) from decimal import Decimal @@ -35,12 +40,10 @@ class WalletListNotes(BitcoinTestFramework): self.sync_all() assert_equal(201, self.nodes[0].getblockcount()) - mining_addr = self.nodes[0].listunspent()[0]['address'] - # Shield coinbase funds (must be a multiple of 10, no change allowed pre-sapling) receive_amount_10 = Decimal('10.0') - Decimal('0.0001') recipients = [{"address":sproutzaddr, "amount":receive_amount_10}] - myopid = self.nodes[0].z_sendmany(mining_addr, recipients) + myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients) txid_1 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() @@ -119,7 +122,7 @@ class WalletListNotes(BitcoinTestFramework): # so send from coin base) receive_amount_2 = Decimal('2.0') - Decimal('0.0001') recipients = [{"address": saplingzaddr, "amount":receive_amount_2}] - myopid = self.nodes[0].z_sendmany(mining_addr, recipients) + myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients) txid_3 = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() unspent_tx = self.nodes[0].z_listunspent(0) diff --git a/qa/rpc-tests/wallet_nullifiers.py b/qa/rpc-tests/wallet_nullifiers.py index bbf9e64f3..a02a7591b 100755 --- a/qa/rpc-tests/wallet_nullifiers.py +++ b/qa/rpc-tests/wallet_nullifiers.py @@ -7,7 +7,8 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_true, bitcoind_processes, \ - connect_nodes_bi, start_node, start_nodes, wait_and_assert_operationid_status + connect_nodes_bi, start_node, start_nodes, wait_and_assert_operationid_status, \ + get_coinbase_address from decimal import Decimal @@ -22,7 +23,8 @@ class WalletNullifiersTest (BitcoinTestFramework): myzaddr0 = self.nodes[0].z_getnewaddress('sprout') # send node 0 taddr to zaddr to get out of coinbase - mytaddr = self.nodes[0].getnewaddress() + # Tests using the default cached chain have one address per coinbase output + mytaddr = get_coinbase_address(self.nodes[0]) recipients = [] recipients.append({"address":myzaddr0, "amount":Decimal('10.0')-Decimal('0.0001')}) # utxo amount less fee diff --git a/qa/rpc-tests/wallet_overwintertx.py b/qa/rpc-tests/wallet_overwintertx.py index 21dc58a81..c24145aba 100755 --- a/qa/rpc-tests/wallet_overwintertx.py +++ b/qa/rpc-tests/wallet_overwintertx.py @@ -7,7 +7,8 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ - start_nodes, connect_nodes_bi, wait_and_assert_operationid_status, assert_greater_than + start_nodes, connect_nodes_bi, wait_and_assert_operationid_status, \ + assert_greater_than, get_coinbase_address from test_framework.authproxy import JSONRPCException from decimal import Decimal @@ -34,7 +35,7 @@ class WalletOverwinterTxTest (BitcoinTestFramework): self.sync_all() # Node 0 has reward from blocks 1 to 98 which are spendable. - taddr0 = self.nodes[0].getnewaddress() + taddr0 = get_coinbase_address(self.nodes[0]) taddr1 = self.nodes[1].getnewaddress() taddr2 = self.nodes[2].getnewaddress() zaddr2 = self.nodes[2].z_getnewaddress('sprout') diff --git a/qa/rpc-tests/wallet_persistence.py b/qa/rpc-tests/wallet_persistence.py index cdc4af3f7..72db7c48b 100755 --- a/qa/rpc-tests/wallet_persistence.py +++ b/qa/rpc-tests/wallet_persistence.py @@ -8,6 +8,7 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_true, + get_coinbase_address, start_nodes, stop_nodes, initialize_chain_clean, connect_nodes_bi, wait_bitcoinds, wait_and_assert_operationid_status @@ -58,7 +59,7 @@ class WalletPersistenceTest (BitcoinTestFramework): self.sync_all() # Node 0 shields funds to Sapling address - taddr0 = self.nodes[0].getnewaddress() + taddr0 = get_coinbase_address(self.nodes[0]) recipients = [] recipients.append({"address": sapling_addr, "amount": Decimal('20')}) myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index 54fc6c580..851099311 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -9,7 +9,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.mininode import COIN from test_framework.util import assert_equal, initialize_chain_clean, \ - start_nodes, connect_nodes_bi, wait_and_assert_operationid_status + start_nodes, connect_nodes_bi, wait_and_assert_operationid_status, \ + get_coinbase_address import sys import timeit @@ -75,7 +76,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework): assert_equal("Coinbase funds can only be sent to a zaddr" in errorString, True) # Prepare to send taddr->zaddr - mytaddr = self.nodes[0].getnewaddress() + mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # Node 3 will test that watch only address utxos are not selected diff --git a/qa/rpc-tests/wallet_sapling.py b/qa/rpc-tests/wallet_sapling.py index 134e83e53..6fe11e5ec 100755 --- a/qa/rpc-tests/wallet_sapling.py +++ b/qa/rpc-tests/wallet_sapling.py @@ -9,6 +9,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import ( assert_equal, + get_coinbase_address, start_nodes, wait_and_assert_operationid_status, ) @@ -34,18 +35,18 @@ class WalletSaplingTest(BitcoinTestFramework): self.sync_all() # Verify RPCs disallow Sapling value transfer if Sapling is not active - tmp_taddr = self.nodes[3].getnewaddress() + tmp_taddr = get_coinbase_address(self.nodes[3]) tmp_zaddr = self.nodes[3].z_getnewaddress('sapling') try: recipients = [] - recipients.append({"address": tmp_zaddr, "amount": Decimal('20')}) + recipients.append({"address": tmp_zaddr, "amount": Decimal('10')}) self.nodes[3].z_sendmany(tmp_taddr, recipients, 1, 0) raise AssertionError("Should have thrown an exception") except JSONRPCException as e: assert_equal("Invalid parameter, Sapling has not activated", e.error['message']) try: recipients = [] - recipients.append({"address": tmp_taddr, "amount": Decimal('20')}) + recipients.append({"address": tmp_taddr, "amount": Decimal('10')}) self.nodes[3].z_sendmany(tmp_zaddr, recipients, 1, 0) raise AssertionError("Should have thrown an exception") except JSONRPCException as e: @@ -75,9 +76,6 @@ class WalletSaplingTest(BitcoinTestFramework): self.nodes[2].generate(2) self.sync_all() - taddr0 = self.nodes[0].getnewaddress() - # Skip over the address containing node 1's coinbase - self.nodes[1].getnewaddress() taddr1 = self.nodes[1].getnewaddress() saplingAddr0 = self.nodes[0].z_getnewaddress('sapling') saplingAddr1 = self.nodes[1].z_getnewaddress('sapling') @@ -95,10 +93,9 @@ class WalletSaplingTest(BitcoinTestFramework): # Node 0 shields some funds # taddr -> Sapling - # -> taddr (change) recipients = [] - recipients.append({"address": saplingAddr0, "amount": Decimal('20')}) - myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) + recipients.append({"address": saplingAddr0, "amount": Decimal('10')}) + myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() @@ -107,6 +104,11 @@ class WalletSaplingTest(BitcoinTestFramework): mempool = self.nodes[0].getrawmempool(True) assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16')) + # Shield another coinbase UTXO + myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() self.nodes[2].generate(1) self.sync_all() diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index 232d772c5..6aa08b32a 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -9,7 +9,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ start_node, connect_nodes_bi, sync_blocks, sync_mempools, \ - wait_and_assert_operationid_status + wait_and_assert_operationid_status, get_coinbase_address from decimal import Decimal @@ -46,17 +46,13 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): print "Mining blocks..." self.nodes[0].generate(1) - do_not_shield_taddr = self.nodes[0].getnewaddress() - self.nodes[0].generate(4) walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) self.sync_all() self.nodes[2].generate(1) - self.nodes[2].getnewaddress() self.nodes[2].generate(1) - self.nodes[2].getnewaddress() self.nodes[2].generate(1) self.sync_all() self.nodes[1].generate(101) @@ -65,8 +61,10 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): assert_equal(self.nodes[1].getbalance(), 10) assert_equal(self.nodes[2].getbalance(), 30) + do_not_shield_taddr = get_coinbase_address(self.nodes[0], 1) + # Prepare to send taddr->zaddr - mytaddr = self.nodes[0].getnewaddress() + mytaddr = get_coinbase_address(self.nodes[0], 4) myzaddr = self.nodes[0].z_getnewaddress(self.addr_type) # Shielding will fail when trying to spend from watch-only address @@ -145,7 +143,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): self.sync_all() self.nodes[1].generate(100) self.sync_all() - mytaddr = self.nodes[0].getnewaddress() + mytaddr = get_coinbase_address(self.nodes[0], 800) def verify_locking(first, second, limit): result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, limit) @@ -186,7 +184,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): if self.addr_type == 'sprout': # Verify maximum number of utxos which node 2 can shield is limited by option -mempooltxinputlimit # This option is used when the limit parameter is set to 0. - mytaddr = self.nodes[2].getnewaddress() + mytaddr = get_coinbase_address(self.nodes[2], 20) result = self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 0) assert_equal(result["shieldingUTXOs"], Decimal('7')) assert_equal(result["remainingUTXOs"], Decimal('13')) @@ -198,7 +196,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): # Verify maximum number of utxos which node 0 can shield is set by default limit parameter of 50 self.nodes[0].generate(200) self.sync_all() - mytaddr = self.nodes[0].getnewaddress() + mytaddr = get_coinbase_address(self.nodes[0], 100) result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001')) assert_equal(result["shieldingUTXOs"], Decimal('50')) assert_equal(result["remainingUTXOs"], Decimal('50')) diff --git a/qa/rpc-tests/wallet_treestate.py b/qa/rpc-tests/wallet_treestate.py index eca42eb69..7f782a87d 100755 --- a/qa/rpc-tests/wallet_treestate.py +++ b/qa/rpc-tests/wallet_treestate.py @@ -7,7 +7,8 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Py from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ - start_nodes, connect_nodes_bi, wait_and_assert_operationid_status + start_nodes, connect_nodes_bi, wait_and_assert_operationid_status, \ + get_coinbase_address import time from decimal import Decimal @@ -35,7 +36,7 @@ class WalletTreeStateTest (BitcoinTestFramework): self.nodes[1].generate(101) self.sync_all() - mytaddr = self.nodes[0].getnewaddress() # where coins were mined + mytaddr = get_coinbase_address(self.nodes[0]) myzaddr = self.nodes[0].z_getnewaddress('sprout') # Spend coinbase utxos to create three notes of 9.99990000 each diff --git a/src/Makefile.am b/src/Makefile.am index e36cea3d6..5733549ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -167,8 +167,6 @@ BITCOIN_CORE_H = \ net.h \ netbase.h \ noui.h \ - paymentdisclosure.h \ - paymentdisclosuredb.h \ policy/fees.h \ pow.h \ prevector.h \ @@ -211,6 +209,7 @@ BITCOIN_CORE_H = \ util.h \ utilmoneystr.h \ utilstrencodings.h \ + utiltest.h \ utiltime.h \ validationinterface.h \ version.h \ @@ -219,6 +218,8 @@ BITCOIN_CORE_H = \ wallet/asyncrpcoperation_shieldcoinbase.h \ wallet/crypter.h \ wallet/db.h \ + wallet/paymentdisclosure.h \ + wallet/paymentdisclosuredb.h \ wallet/rpcwallet.h \ wallet/wallet.h \ wallet/wallet_ismine.h \ @@ -259,8 +260,6 @@ libbitcoin_server_a_SOURCES = \ miner.cpp \ net.cpp \ noui.cpp \ - paymentdisclosure.cpp \ - paymentdisclosuredb.cpp \ policy/fees.cpp \ pow.cpp \ rest.cpp \ @@ -301,8 +300,6 @@ endif libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ - utiltest.cpp \ - utiltest.h \ zcbenchmarks.cpp \ zcbenchmarks.h \ wallet/asyncrpcoperation_mergetoaddress.cpp \ @@ -310,8 +307,8 @@ libbitcoin_wallet_a_SOURCES = \ wallet/asyncrpcoperation_shieldcoinbase.cpp \ wallet/crypter.cpp \ wallet/db.cpp \ - paymentdisclosure.cpp \ - paymentdisclosuredb.cpp \ + wallet/paymentdisclosure.cpp \ + wallet/paymentdisclosuredb.cpp \ wallet/rpcdisclosure.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ @@ -384,6 +381,7 @@ libbitcoin_common_a_SOURCES = \ script/sign.cpp \ script/standard.cpp \ transaction_builder.cpp \ + utiltest.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) diff --git a/src/Makefile.gtest.include b/src/Makefile.gtest.include index 6b52eff36..26d57b54f 100644 --- a/src/Makefile.gtest.include +++ b/src/Makefile.gtest.include @@ -42,12 +42,12 @@ zcash_gtest_SOURCES += \ gtest/test_txid.cpp \ gtest/test_libzcash_utils.cpp \ gtest/test_proofs.cpp \ - gtest/test_paymentdisclosure.cpp \ gtest/test_pedersen_hash.cpp \ gtest/test_checkblock.cpp \ gtest/test_zip32.cpp if ENABLE_WALLET zcash_gtest_SOURCES += \ + wallet/gtest/test_paymentdisclosure.cpp \ wallet/gtest/test_wallet.cpp endif diff --git a/src/gtest/test_miner.cpp b/src/gtest/test_miner.cpp index c232af842..695f991b3 100644 --- a/src/gtest/test_miner.cpp +++ b/src/gtest/test_miner.cpp @@ -5,99 +5,70 @@ #include "key.h" #include "miner.h" #include "util.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif -#include -using ::testing::Return; - -#ifdef ENABLE_WALLET -class MockReserveKey : public CReserveKey { -public: - MockReserveKey() : CReserveKey(nullptr) { } - - MOCK_METHOD1(GetReservedKey, bool(CPubKey &pubkey)); -}; -#endif - -TEST(Miner, GetMinerScriptPubKey) { +TEST(Miner, GetScriptForMinerAddress) { SelectParams(CBaseChainParams::MAIN); - boost::optional scriptPubKey; -#ifdef ENABLE_WALLET - MockReserveKey reservekey; - EXPECT_CALL(reservekey, GetReservedKey(::testing::_)) - .WillRepeatedly(Return(false)); -#endif - // No miner address set -#ifdef ENABLE_WALLET - scriptPubKey = GetMinerScriptPubKey(reservekey); -#else - scriptPubKey = GetMinerScriptPubKey(); -#endif - EXPECT_FALSE((bool) scriptPubKey); + { + boost::shared_ptr coinbaseScript; + GetScriptForMinerAddress(coinbaseScript); + EXPECT_FALSE((bool) coinbaseScript); + } mapArgs["-mineraddress"] = "notAnAddress"; -#ifdef ENABLE_WALLET - scriptPubKey = GetMinerScriptPubKey(reservekey); -#else - scriptPubKey = GetMinerScriptPubKey(); -#endif - EXPECT_FALSE((bool) scriptPubKey); + { + boost::shared_ptr coinbaseScript; + GetScriptForMinerAddress(coinbaseScript); + EXPECT_FALSE((bool) coinbaseScript); + } // Partial address mapArgs["-mineraddress"] = "t1T8yaLVhNqxA5KJcmiqq"; -#ifdef ENABLE_WALLET - scriptPubKey = GetMinerScriptPubKey(reservekey); -#else - scriptPubKey = GetMinerScriptPubKey(); -#endif - EXPECT_FALSE((bool) scriptPubKey); + { + boost::shared_ptr coinbaseScript; + GetScriptForMinerAddress(coinbaseScript); + EXPECT_FALSE((bool) coinbaseScript); + } // Typo in address mapArgs["-mineraddress"] = "t1TByaLVhNqxA5KJcmiqqFN88e8DNp2PBfF"; -#ifdef ENABLE_WALLET - scriptPubKey = GetMinerScriptPubKey(reservekey); -#else - scriptPubKey = GetMinerScriptPubKey(); -#endif - EXPECT_FALSE((bool) scriptPubKey); + { + boost::shared_ptr coinbaseScript; + GetScriptForMinerAddress(coinbaseScript); + EXPECT_FALSE((bool) coinbaseScript); + } // Set up expected scriptPubKey for t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF CKeyID keyID; keyID.SetHex("eb88f1c65b39a823479ac9c7db2f4a865960a165"); - CScript expectedScriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; + CScript expectedCoinbaseScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; // Valid address mapArgs["-mineraddress"] = "t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF"; -#ifdef ENABLE_WALLET - scriptPubKey = GetMinerScriptPubKey(reservekey); -#else - scriptPubKey = GetMinerScriptPubKey(); -#endif - EXPECT_TRUE((bool) scriptPubKey); - EXPECT_EQ(expectedScriptPubKey, *scriptPubKey); + { + boost::shared_ptr coinbaseScript; + GetScriptForMinerAddress(coinbaseScript); + EXPECT_TRUE((bool) coinbaseScript); + EXPECT_EQ(expectedCoinbaseScript, coinbaseScript->reserveScript); + } // Valid address with leading whitespace mapArgs["-mineraddress"] = " t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF"; -#ifdef ENABLE_WALLET - scriptPubKey = GetMinerScriptPubKey(reservekey); -#else - scriptPubKey = GetMinerScriptPubKey(); -#endif - EXPECT_TRUE((bool) scriptPubKey); - EXPECT_EQ(expectedScriptPubKey, *scriptPubKey); + { + boost::shared_ptr coinbaseScript; + GetScriptForMinerAddress(coinbaseScript); + EXPECT_TRUE((bool) coinbaseScript); + EXPECT_EQ(expectedCoinbaseScript, coinbaseScript->reserveScript); + } // Valid address with trailing whitespace mapArgs["-mineraddress"] = "t1T8yaLVhNqxA5KJcmiqqFN88e8DNp2PBfF "; -#ifdef ENABLE_WALLET - scriptPubKey = GetMinerScriptPubKey(reservekey); -#else - scriptPubKey = GetMinerScriptPubKey(); -#endif - EXPECT_TRUE((bool) scriptPubKey); - EXPECT_EQ(expectedScriptPubKey, *scriptPubKey); + { + boost::shared_ptr coinbaseScript; + GetScriptForMinerAddress(coinbaseScript); + EXPECT_TRUE((bool) coinbaseScript); + EXPECT_EQ(expectedCoinbaseScript, coinbaseScript->reserveScript); + } } diff --git a/src/init.cpp b/src/init.cpp index 4748897ad..f9da81e87 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -204,11 +204,7 @@ void Shutdown() pwalletMain->Flush(false); #endif #ifdef ENABLE_MINING - #ifdef ENABLE_WALLET - GenerateBitcoins(false, NULL, 0); - #else - GenerateBitcoins(false, 0); - #endif + GenerateBitcoins(false, 0, Params()); #endif StopNode(); StopTorControl(); @@ -1741,7 +1737,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #ifdef ENABLE_WALLET bool minerAddressInLocalWallet = false; if (pwalletMain) { - // Address has alreday been validated + // Address has already been validated CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]); CKeyID keyID = boost::get(addr); minerAddressInLocalWallet = pwalletMain->HaveKey(keyID); @@ -1750,6 +1746,22 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(_("-mineraddress is not in the local wallet. Either use a local address, or set -minetolocalwallet=0")); } #endif // ENABLE_WALLET + + // This is leveraging the fact that boost::signals2 executes connected + // handlers in-order. Further up, the wallet is connected to this signal + // if the wallet is enabled. The wallet's ScriptForMining handler does + // nothing if -mineraddress is set, and GetScriptForMinerAddress() does + // nothing if -mineraddress is not set (or set to an invalid address). + // + // The upshot is that when ScriptForMining(script) is called: + // - If -mineraddress is set (whether or not the wallet is enabled), the + // CScript argument is set to -mineraddress. + // - If the wallet is enabled and -mineraddress is not set, the CScript + // argument is set to a wallet address. + // - If the wallet is disabled and -mineraddress is not set, the CScript + // argument is not modified; in practice this means it is empty, and + // GenerateBitcoins() returns an error. + GetMainSignals().ScriptForMining.connect(GetScriptForMinerAddress); } #endif // ENABLE_MINING @@ -1820,12 +1832,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #ifdef ENABLE_MINING // Generate coins in the background - #ifdef ENABLE_WALLET - if (pwalletMain || !GetArg("-mineraddress", "").empty()) - GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1)); - #else - GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1)); - #endif + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params()); #endif // ********************************************************* Step 11: finished diff --git a/src/miner.cpp b/src/miner.cpp index 2143c9636..5699e4ba5 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -28,9 +28,7 @@ #include "ui_interface.h" #include "util.h" #include "utilmoneystr.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif +#include "validationinterface.h" #include "sodium.h" @@ -400,48 +398,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) return pblocktemplate.release(); } -#ifdef ENABLE_WALLET -boost::optional GetMinerScriptPubKey(CReserveKey& reservekey) -#else -boost::optional GetMinerScriptPubKey() -#endif -{ - CKeyID keyID; - CTxDestination addr = DecodeDestination(GetArg("-mineraddress", "")); - if (IsValidDestination(addr)) { - keyID = boost::get(addr); - } else { -#ifdef ENABLE_WALLET - CPubKey pubkey; - if (!reservekey.GetReservedKey(pubkey)) { - return boost::optional(); - } - keyID = pubkey.GetID(); -#else - return boost::optional(); -#endif - } - - CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; - return scriptPubKey; -} - -#ifdef ENABLE_WALLET -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) -{ - boost::optional scriptPubKey = GetMinerScriptPubKey(reservekey); -#else -CBlockTemplate* CreateNewBlockWithKey() -{ - boost::optional scriptPubKey = GetMinerScriptPubKey(); -#endif - - if (!scriptPubKey) { - return NULL; - } - return CreateNewBlock(*scriptPubKey); -} - ////////////////////////////////////////////////////////////////////////////// // // Internal miner @@ -449,6 +405,30 @@ CBlockTemplate* CreateNewBlockWithKey() #ifdef ENABLE_MINING +class MinerAddressScript : public CReserveScript +{ + // CReserveScript requires implementing this function, so that if an + // internal (not-visible) wallet address is used, the wallet can mark it as + // important when a block is mined (so it then appears to the user). + // If -mineraddress is set, the user already knows about and is managing the + // address, so we don't need to do anything here. + void KeepScript() {} +}; + +void GetScriptForMinerAddress(boost::shared_ptr &script) +{ + CTxDestination addr = DecodeDestination(GetArg("-mineraddress", "")); + if (!IsValidDestination(addr)) { + return; + } + + boost::shared_ptr mAddr(new MinerAddressScript()); + CKeyID keyID = boost::get(addr); + + script = mAddr; + script->reserveScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; +} + void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) { // Update nExtraNonce @@ -468,11 +448,7 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& pblock->hashMerkleRoot = pblock->BuildMerkleTree(); } -#ifdef ENABLE_WALLET -static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) -#else -static bool ProcessBlockFound(CBlock* pblock) -#endif // ENABLE_WALLET +static bool ProcessBlockFound(CBlock* pblock, const CChainParams& chainparams) { LogPrintf("%s\n", pblock->ToString()); LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); @@ -484,18 +460,8 @@ static bool ProcessBlockFound(CBlock* pblock) return error("ZcashMiner: generated block is stale"); } -#ifdef ENABLE_WALLET - if (GetArg("-mineraddress", "").empty()) { - // Remove key from key pool - reservekey.KeepKey(); - } - - // Track how many getdata requests this block gets - { - LOCK(wallet.cs_wallet); - wallet.mapRequestCount[pblock->GetHash()] = 0; - } -#endif + // Inform about the new block + GetMainSignals().BlockFound(pblock->GetHash()); // Process this block the same as if we had received it from another node CValidationState state; @@ -507,25 +473,18 @@ static bool ProcessBlockFound(CBlock* pblock) return true; } -#ifdef ENABLE_WALLET -void static BitcoinMiner(CWallet *pwallet) -#else -void static BitcoinMiner() -#endif +void static BitcoinMiner(const CChainParams& chainparams) { LogPrintf("ZcashMiner started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("zcash-miner"); - const CChainParams& chainparams = Params(); - -#ifdef ENABLE_WALLET - // Each thread has its own key - CReserveKey reservekey(pwallet); -#endif // Each thread has its own counter unsigned int nExtraNonce = 0; + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + unsigned int n = chainparams.EquihashN(); unsigned int k = chainparams.EquihashK(); @@ -544,6 +503,10 @@ void static BitcoinMiner() miningTimer.start(); try { + //throw an error if no script was provided + if (!coinbaseScript->reserveScript.size()) + throw std::runtime_error("No coinbase script available (mining requires a wallet or -mineraddress)"); + while (true) { if (chainparams.MiningRequiresPeers()) { // Busy-wait for the network to come online so we don't waste time mining @@ -568,11 +531,7 @@ void static BitcoinMiner() unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); -#ifdef ENABLE_WALLET - unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); -#else - unique_ptr pblocktemplate(CreateNewBlockWithKey()); -#endif + unique_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) { if (GetArg("-mineraddress", "").empty()) { @@ -620,11 +579,7 @@ void static BitcoinMiner() solver, pblock->nNonce.ToString()); std::function)> validBlock = -#ifdef ENABLE_WALLET - [&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams] -#else - [&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams] -#endif + [&pblock, &hashTarget, &chainparams, &m_cs, &cancelSolver, &coinbaseScript] (std::vector soln) { // Write the solution to the hash and compute the result. LogPrint("pow", "- Checking solution against target\n"); @@ -639,17 +594,13 @@ void static BitcoinMiner() SetThreadPriority(THREAD_PRIORITY_NORMAL); LogPrintf("ZcashMiner:\n"); LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex()); -#ifdef ENABLE_WALLET - if (ProcessBlockFound(pblock, *pwallet, reservekey)) -#else - if (ProcessBlockFound(pblock)) -#endif - { + if (ProcessBlockFound(pblock, chainparams)) { // Ignore chain updates caused by us std::lock_guard lock{m_cs}; cancelSolver = false; } SetThreadPriority(THREAD_PRIORITY_LOWEST); + coinbaseScript->KeepScript(); // In regression test mode, stop mining after a block is found. if (chainparams.MineBlocksOnDemand()) { @@ -754,11 +705,7 @@ void static BitcoinMiner() c.disconnect(); } -#ifdef ENABLE_WALLET -void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) -#else -void GenerateBitcoins(bool fGenerate, int nThreads) -#endif +void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams) { static boost::thread_group* minerThreads = NULL; @@ -778,11 +725,7 @@ void GenerateBitcoins(bool fGenerate, int nThreads) minerThreads = new boost::thread_group(); for (int i = 0; i < nThreads; i++) { -#ifdef ENABLE_WALLET - minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); -#else - minerThreads->create_thread(&BitcoinMiner); -#endif + minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams))); } } diff --git a/src/miner.h b/src/miner.h index bf1a088f0..070989054 100644 --- a/src/miner.h +++ b/src/miner.h @@ -12,11 +12,8 @@ #include class CBlockIndex; +class CChainParams; class CScript; -#ifdef ENABLE_WALLET -class CReserveKey; -class CWallet; -#endif namespace Consensus { struct Params; }; struct CBlockTemplate @@ -28,23 +25,14 @@ struct CBlockTemplate /** Generate a new block, without valid proof-of-work */ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); -#ifdef ENABLE_WALLET -boost::optional GetMinerScriptPubKey(CReserveKey& reservekey); -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); -#else -boost::optional GetMinerScriptPubKey(); -CBlockTemplate* CreateNewBlockWithKey(); -#endif #ifdef ENABLE_MINING +/** Get script for -mineraddress */ +void GetScriptForMinerAddress(boost::shared_ptr &script); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); /** Run the miner threads */ - #ifdef ENABLE_WALLET -void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); - #else -void GenerateBitcoins(bool fGenerate, int nThreads); - #endif +void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams); #endif void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index a6467d5b2..73963da19 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -21,13 +21,11 @@ #include "txmempool.h" #include "util.h" #include "validationinterface.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif #include #include +#include #include @@ -174,15 +172,6 @@ UniValue generate(const UniValue& params, bool fHelp) + HelpExampleCli("generate", "11") ); - if (GetArg("-mineraddress", "").empty()) { -#ifdef ENABLE_WALLET - if (!pwalletMain) { - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Wallet disabled and -mineraddress not set"); - } -#else - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "zcashd compiled without wallet and -mineraddress not set"); -#endif - } if (!Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); @@ -190,9 +179,13 @@ UniValue generate(const UniValue& params, bool fHelp) int nHeightEnd = 0; int nHeight = 0; int nGenerate = params[0].get_int(); -#ifdef ENABLE_WALLET - CReserveKey reservekey(pwalletMain); -#endif + + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + //throw an error if no script was provided + if (!coinbaseScript->reserveScript.size()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet or -mineraddress)"); { // Don't keep cs_main locked LOCK(cs_main); @@ -206,13 +199,9 @@ UniValue generate(const UniValue& params, bool fHelp) unsigned int k = Params().EquihashK(); while (nHeight < nHeightEnd) { -#ifdef ENABLE_WALLET - std::unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); -#else - std::unique_ptr pblocktemplate(CreateNewBlockWithKey()); -#endif + std::unique_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); + throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); @@ -262,11 +251,13 @@ endloop: throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); + + //mark script as important because it was used at least for one coinbase output + coinbaseScript->KeepScript(); } return blockHashes; } - UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) @@ -289,15 +280,6 @@ UniValue setgenerate(const UniValue& params, bool fHelp) + HelpExampleRpc("setgenerate", "true, 1") ); - if (GetArg("-mineraddress", "").empty()) { -#ifdef ENABLE_WALLET - if (!pwalletMain) { - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Wallet disabled and -mineraddress not set"); - } -#else - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "zcashd compiled without wallet and -mineraddress not set"); -#endif - } if (Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); @@ -315,17 +297,12 @@ UniValue setgenerate(const UniValue& params, bool fHelp) mapArgs["-gen"] = (fGenerate ? "1" : "0"); mapArgs ["-genproclimit"] = itostr(nGenProcLimit); -#ifdef ENABLE_WALLET - GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); -#else - GenerateBitcoins(fGenerate, nGenProcLimit); -#endif + GenerateBitcoins(fGenerate, nGenProcLimit, Params()); return NullUniValue; } #endif - UniValue getmininginfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -629,16 +606,22 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) delete pblocktemplate; pblocktemplate = NULL; } -#ifdef ENABLE_WALLET - CReserveKey reservekey(pwalletMain); - pblocktemplate = CreateNewBlockWithKey(reservekey); -#else - pblocktemplate = CreateNewBlockWithKey(); -#endif + + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + // Throw an error if no script was provided + if (!coinbaseScript->reserveScript.size()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet or -mineraddress)"); + + pblocktemplate = CreateNewBlock(coinbaseScript->reserveScript); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); - // Need to update only after we know CreateNewBlockWithKey succeeded + // Mark script as important because it was used at least for one coinbase output + coinbaseScript->KeepScript(); + + // Need to update only after we know CreateNewBlock succeeded pindexPrev = pindexPrevNew; } CBlock* pblock = &pblocktemplate->block; // pointer for convenience diff --git a/src/script/script.h b/src/script/script.h index 781a09773..541ece1f5 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -587,4 +587,13 @@ public: } }; +class CReserveScript +{ +public: + CScript reserveScript; + virtual void KeepScript() {} + CReserveScript() {} + virtual ~CReserveScript() {} +}; + #endif // BITCOIN_SCRIPT_SCRIPT_H diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index ae1e322c2..1dc3351ab 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -22,9 +22,13 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); + g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); + g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { + g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); + g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); @@ -37,6 +41,8 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { } void UnregisterAllValidationInterfaces() { + g_signals.BlockFound.disconnect_all_slots(); + g_signals.ScriptForMining.disconnect_all_slots(); g_signals.BlockChecked.disconnect_all_slots(); g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); diff --git a/src/validationinterface.h b/src/validationinterface.h index c87a85930..7b02bd9da 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -7,12 +7,14 @@ #define BITCOIN_VALIDATIONINTERFACE_H #include +#include #include "zcash/IncrementalMerkleTree.hpp" class CBlock; class CBlockIndex; struct CBlockLocator; +class CReserveScript; class CTransaction; class CValidationInterface; class CValidationState; @@ -40,6 +42,8 @@ protected: virtual void Inventory(const uint256 &hash) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} + virtual void GetScriptForMining(boost::shared_ptr&) {}; + virtual void ResetRequestCount(const uint256 &hash) {}; friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); @@ -64,6 +68,10 @@ struct CMainSignals { boost::signals2::signal Broadcast; /** Notifies listeners of a block validation result */ boost::signals2::signal BlockChecked; + /** Notifies listeners that a key for mining is required (coinbase) */ + boost::signals2::signal&)> ScriptForMining; + /** Notifies listeners that a block has been successfully mined */ + boost::signals2::signal BlockFound; }; CMainSignals& GetMainSignals(); diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index ebadbef81..a0b414614 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -23,6 +23,7 @@ #include "utiltime.h" #include "wallet.h" #include "walletdb.h" +#include "wallet/paymentdisclosuredb.h" #include "zcash/IncrementalMerkleTree.hpp" #include @@ -30,8 +31,6 @@ #include #include -#include "paymentdisclosuredb.h" - using namespace libzcash; extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); @@ -139,11 +138,7 @@ void AsyncRPCOperation_mergetoaddress::main() bool success = false; #ifdef ENABLE_MINING -#ifdef ENABLE_WALLET - GenerateBitcoins(false, NULL, 0); -#else - GenerateBitcoins(false, 0); -#endif + GenerateBitcoins(false, 0, Params()); #endif try { @@ -168,11 +163,7 @@ void AsyncRPCOperation_mergetoaddress::main() } #ifdef ENABLE_MINING -#ifdef ENABLE_WALLET - GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1)); -#else - GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1)); -#endif + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params()); #endif stop_execution_clock(); diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.h b/src/wallet/asyncrpcoperation_mergetoaddress.h index 09ac53b79..774695cf2 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.h +++ b/src/wallet/asyncrpcoperation_mergetoaddress.h @@ -7,10 +7,10 @@ #include "amount.h" #include "asyncrpcoperation.h" -#include "paymentdisclosure.h" #include "primitives/transaction.h" #include "transaction_builder.h" #include "wallet.h" +#include "wallet/paymentdisclosure.h" #include "zcash/Address.hpp" #include "zcash/JoinSplit.hpp" diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 41e423a37..e33440a4d 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -24,6 +24,7 @@ #include "zcash/IncrementalMerkleTree.hpp" #include "sodium.h" #include "miner.h" +#include "wallet/paymentdisclosuredb.h" #include #include @@ -31,8 +32,6 @@ #include #include -#include "paymentdisclosuredb.h" - using namespace libzcash; extern UniValue signrawtransaction(const UniValue& params, bool fHelp); @@ -135,11 +134,7 @@ void AsyncRPCOperation_sendmany::main() { bool success = false; #ifdef ENABLE_MINING - #ifdef ENABLE_WALLET - GenerateBitcoins(false, NULL, 0); - #else - GenerateBitcoins(false, 0); - #endif + GenerateBitcoins(false, 0, Params()); #endif try { @@ -164,11 +159,7 @@ void AsyncRPCOperation_sendmany::main() { } #ifdef ENABLE_MINING - #ifdef ENABLE_WALLET - GenerateBitcoins(GetBoolArg("-gen",false), pwalletMain, GetArg("-genproclimit", 1)); - #else - GenerateBitcoins(GetBoolArg("-gen",false), GetArg("-genproclimit", 1)); - #endif + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params()); #endif stop_execution_clock(); diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index 862ae02a2..fcb95227a 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -12,7 +12,7 @@ #include "zcash/JoinSplit.hpp" #include "zcash/Address.hpp" #include "wallet.h" -#include "paymentdisclosure.h" +#include "wallet/paymentdisclosure.h" #include #include diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index d2a68b57d..4280ac2f1 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -23,6 +23,7 @@ #include "zcash/IncrementalMerkleTree.hpp" #include "sodium.h" #include "miner.h" +#include "wallet/paymentdisclosuredb.h" #include #include @@ -32,9 +33,6 @@ #include "asyncrpcoperation_shieldcoinbase.h" -#include "paymentdisclosure.h" -#include "paymentdisclosuredb.h" - using namespace libzcash; static int find_output(UniValue obj, int n) { @@ -110,11 +108,7 @@ void AsyncRPCOperation_shieldcoinbase::main() { bool success = false; #ifdef ENABLE_MINING - #ifdef ENABLE_WALLET - GenerateBitcoins(false, NULL, 0); - #else - GenerateBitcoins(false, 0); - #endif + GenerateBitcoins(false, 0, Params()); #endif try { @@ -139,11 +133,7 @@ void AsyncRPCOperation_shieldcoinbase::main() { } #ifdef ENABLE_MINING - #ifdef ENABLE_WALLET - GenerateBitcoins(GetBoolArg("-gen",false), pwalletMain, GetArg("-genproclimit", 1)); - #else - GenerateBitcoins(GetBoolArg("-gen",false), GetArg("-genproclimit", 1)); - #endif + GenerateBitcoins(GetBoolArg("-gen",false), GetArg("-genproclimit", 1), Params()); #endif stop_execution_clock(); diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.h b/src/wallet/asyncrpcoperation_shieldcoinbase.h index e9ee44fcd..4311d84b3 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.h +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.h @@ -12,14 +12,13 @@ #include "zcash/JoinSplit.hpp" #include "zcash/Address.hpp" #include "wallet.h" +#include "wallet/paymentdisclosure.h" #include #include #include -#include "paymentdisclosure.h" - // Default transaction fee if caller does not specify one. #define SHIELD_COINBASE_DEFAULT_MINERS_FEE 10000 diff --git a/src/gtest/test_paymentdisclosure.cpp b/src/wallet/gtest/test_paymentdisclosure.cpp similarity index 98% rename from src/gtest/test_paymentdisclosure.cpp rename to src/wallet/gtest/test_paymentdisclosure.cpp index c166cdbe1..59eff76e9 100644 --- a/src/gtest/test_paymentdisclosure.cpp +++ b/src/wallet/gtest/test_paymentdisclosure.cpp @@ -17,8 +17,8 @@ #include #include "util.h" -#include "paymentdisclosure.h" -#include "paymentdisclosuredb.h" +#include "wallet/paymentdisclosure.h" +#include "wallet/paymentdisclosuredb.h" #include "sodium.h" diff --git a/src/paymentdisclosure.cpp b/src/wallet/paymentdisclosure.cpp similarity index 98% rename from src/paymentdisclosure.cpp rename to src/wallet/paymentdisclosure.cpp index eb55a0536..5dd1e3d1b 100644 --- a/src/paymentdisclosure.cpp +++ b/src/wallet/paymentdisclosure.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "paymentdisclosure.h" +#include "wallet/paymentdisclosure.h" #include "key_io.h" #include "util.h" diff --git a/src/paymentdisclosure.h b/src/wallet/paymentdisclosure.h similarity index 100% rename from src/paymentdisclosure.h rename to src/wallet/paymentdisclosure.h diff --git a/src/paymentdisclosuredb.cpp b/src/wallet/paymentdisclosuredb.cpp similarity index 98% rename from src/paymentdisclosuredb.cpp rename to src/wallet/paymentdisclosuredb.cpp index 8840dcda0..db7924fbb 100644 --- a/src/paymentdisclosuredb.cpp +++ b/src/wallet/paymentdisclosuredb.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "paymentdisclosuredb.h" +#include "wallet/paymentdisclosuredb.h" #include "util.h" #include "dbwrapper.h" diff --git a/src/paymentdisclosuredb.h b/src/wallet/paymentdisclosuredb.h similarity index 96% rename from src/paymentdisclosuredb.h rename to src/wallet/paymentdisclosuredb.h index 9352cac8f..2ec5ad5e4 100644 --- a/src/paymentdisclosuredb.h +++ b/src/wallet/paymentdisclosuredb.h @@ -5,7 +5,7 @@ #ifndef ZCASH_PAYMENTDISCLOSUREDB_H #define ZCASH_PAYMENTDISCLOSUREDB_H -#include "paymentdisclosure.h" +#include #include #include diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp index dd3acab7e..df35bb6dd 100644 --- a/src/wallet/rpcdisclosure.cpp +++ b/src/wallet/rpcdisclosure.cpp @@ -12,6 +12,8 @@ #include "util.h" #include "utiltime.h" #include "wallet.h" +#include "wallet/paymentdisclosure.h" +#include "wallet/paymentdisclosuredb.h" #include #include @@ -21,9 +23,6 @@ #include -#include "paymentdisclosure.h" -#include "paymentdisclosuredb.h" - #include "zcash/Note.hpp" #include "zcash/NoteEncryption.hpp" diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index eaecd63f0..89aabad69 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4039,6 +4039,21 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) } } +void CWallet::GetScriptForMining(boost::shared_ptr &script) +{ + if (!GetArg("-mineraddress", "").empty()) { + return; + } + + boost::shared_ptr rKey(new CReserveKey(this)); + CPubKey pubkey; + if (!rKey->GetReservedKey(pubkey)) + return; + + script = rKey; + script->reserveScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; +} + void CWallet::LockCoin(COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b24e76b19..3f43e434e 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -35,6 +35,8 @@ #include #include +#include + /** * Settings */ @@ -1206,6 +1208,13 @@ public: } } + void GetScriptForMining(boost::shared_ptr &script); + void ResetRequestCount(const uint256 &hash) + { + LOCK(cs_wallet); + mapRequestCount[hash] = 0; + }; + unsigned int GetKeyPoolSize() { AssertLockHeld(cs_wallet); // setKeyPool @@ -1301,7 +1310,7 @@ public: }; /** A key allocated from the key pool. */ -class CReserveKey +class CReserveKey : public CReserveScript { protected: CWallet* pwallet; @@ -1322,6 +1331,7 @@ public: void ReturnKey(); virtual bool GetReservedKey(CPubKey &pubkey); void KeepKey(); + void KeepScript() { KeepKey(); } }; diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index f7a266e09..5283d5097 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -44,7 +44,7 @@ void pre_wallet_load() if (pwalletMain) pwalletMain->Flush(false); #ifdef ENABLE_MINING - GenerateBitcoins(false, NULL, 0); + GenerateBitcoins(false, 0, Params()); #endif UnregisterNodeSignals(GetNodeSignals()); if (pwalletMain) @@ -63,7 +63,7 @@ void post_wallet_load(){ #ifdef ENABLE_MINING // Generate coins in the background if (pwalletMain || !GetArg("-mineraddress", "").empty()) - GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1)); + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params()); #endif }