diff --git a/.gitignore b/.gitignore index 0e9974538..7d6eeab2c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,7 @@ src/hush-gtest src/hush-tx src/test/test_bitcoin -# Zcash utilities -src/zcash/GenerateParams -src/zcash/CreateJoinSplit +# Hush utilities src/hush/GenerateParams src/hush/CreateJoinSplit diff --git a/Makefile.am b/Makefile.am index 428afda62..549b63c9e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,33 +15,13 @@ endif BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT) BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT) WALLET_UTILITY_BIN=$(top_builddir)/src/wallet-utility$(EXEEXT) -BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) - -##OSX_APP=Bitcoin-Qt.app -##OSX_DMG=Bitcoin-Core.dmg -##OSX_BACKGROUND_IMAGE=background.tiff -##OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus -##OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist -##OSX_BASE_LPROJ_DIR=$(top_srcdir)/contrib/macdeploy/Base.lproj/InfoPlist.strings -##OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns -##OSX_PLIST=$(top_srcdir)/share/qt/Info.plist #not installed -##OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW + DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ $(top_srcdir)/contrib/devtools/security-check.py -WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ - $(top_srcdir)/share/pixmaps/nsis-header.bmp \ - $(top_srcdir)/share/pixmaps/nsis-wizard.bmp - -##OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) $(OSX_BASE_LPROJ_DIR) \ -## $(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \ -## $(top_srcdir)/contrib/macdeploy/DS_Store \ -## $(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \ -## $(top_srcdir)/contrib/macdeploy/detached-sig-create.sh - COVERAGE_INFO = baseline_filtered_combined.info baseline.info \ leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \ baseline_filtered.info \ @@ -61,85 +41,9 @@ distcheck-hook: distcleancheck: @: -$(BITCOIN_WIN_INSTALLER): all-recursive - $(MKDIR_P) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIND_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release - STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(WALLET_UTILITY_BIN) $(top_builddir)/release - @test -f $(MAKENSIS) && $(MAKENSIS) -V2 $(top_builddir)/share/setup.nsi || \ - echo error: could not build $@ - @echo built $@ - $(if $(findstring src/,$(MAKECMDGOALS)),$(MAKECMDGOALS), none): FORCE $(MAKE) -C src $(patsubst src/%,%,$@) -##$(OSX_APP)/Contents/PkgInfo: -## $(MKDIR_P) $(@D) -## @echo "APPL????" > $@ -## -##$(OSX_APP)/Contents/Resources/empty.lproj: -## $(MKDIR_P) $(@D) -## @touch $@ -## -##$(OSX_APP)/Contents/Info.plist: $(OSX_PLIST) -## $(MKDIR_P) $(@D) -## $(INSTALL_DATA) $< $@ -## -##$(OSX_APP)/Contents/Resources/bitcoin.icns: $(OSX_INSTALLER_ICONS) -## $(MKDIR_P) $(@D) -## $(INSTALL_DATA) $< $@ -## -##$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(BITCOIN_QT_BIN) -## $(MKDIR_P) $(@D) -## STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@ -## -##$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(OSX_BASE_LPROJ_DIR) -## $(MKDIR_P) $(@D) -## $(INSTALL_DATA) $< $@ -## -##OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \ -## $(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \ -## $(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings -## -##if BUILD_DARWIN -##$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) -## $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -## -##deploydir: $(OSX_DMG) -##else -##APP_DIST_DIR=$(top_builddir)/dist -##APP_DIST_EXTRAS=$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE) $(APP_DIST_DIR)/.DS_Store $(APP_DIST_DIR)/Applications -## -##$(APP_DIST_DIR)/Applications: -## @rm -f $@ -## @cd $(@D); $(LN_S) /Applications $(@F) -## -##$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt -## -##$(OSX_DMG): $(APP_DIST_EXTRAS) -## $(GENISOIMAGE) -no-cache-inodes -D -l -probe -V "Bitcoin-Core" -no-pad -r -apple -o $@ dist -## -##$(APP_DIST_DIR)/.background/$(OSX_BACKGROUND_IMAGE): contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) -## $(MKDIR_P) $(@D) -## $(INSTALL) $< $@ -##$(APP_DIST_DIR)/.DS_Store: contrib/macdeploy/DS_Store -## $(INSTALL) $< $@ -## -##$(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(OSX_APP_BUILT) $(OSX_PACKAGING) -## INSTALLNAMETOOL=$(INSTALLNAMETOOL) OTOOL=$(OTOOL) STRIP=$(STRIP) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -translations-dir=$(QT_TRANSLATION_DIR) -add-qt-tr $(OSX_QT_TRANSLATIONS) -verbose 2 -## -##deploydir: $(APP_DIST_EXTRAS) -##endif -## -##if TARGET_DARWIN -##appbundle: $(OSX_APP_BUILT) -##deploy: $(OSX_DMG) -##endif - -if TARGET_WINDOWS -deploy: $(BITCOIN_WIN_INSTALLER) -endif - $(BITCOIND_BIN): FORCE $(MAKE) -C src $(@F) @@ -255,11 +159,10 @@ EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.sh qa/pull install-exec-hook: mv $(DESTDIR)$(bindir)/fetch-params.sh $(DESTDIR)$(bindir)/hush-fetch-params -CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) .INTERMEDIATE: $(COVERAGE_INFO) DISTCHECK_CONFIGURE_FLAGS = --enable-man clean-local: - rm -rf test_bitcoin.coverage/ zcash-gtest.coverage/ total.coverage/ $(OSX_APP) + rm -rf test_bitcoin.coverage/ zcash-gtest.coverage/ total.coverage/ diff --git a/README.md b/README.md index 9dd93225f..50c8a990d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# HUSH 1.0.14 +# HUSH 1.0.15 ## What is HUSH? diff --git a/configure.ac b/configure.ac index 6a26a3ed8..c35edde4b 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 14) +define(_CLIENT_VERSION_REVISION, 15) define(_CLIENT_VERSION_BUILD, 50) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) @@ -876,7 +876,7 @@ AC_SUBST(GMPXX_LIBS) AC_SUBST(LIBSNARK_DEPINST) AC_SUBST(LIBZCASH_LIBS) AC_SUBST(PROTON_LIBS) -AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi src/test/buildenv.py]) +AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests-config.sh],[chmod +x qa/pull-tester/tests-config.sh]) diff --git a/depends/packages/googlemock.mk b/depends/packages/googlemock.mk deleted file mode 100644 index 229dc3587..000000000 --- a/depends/packages/googlemock.mk +++ /dev/null @@ -1,20 +0,0 @@ -# url=https://github.com/google/googlemock/archive/release-1.7.0.tar.gz - -package=googlemock -$(package)_version=1.7.0 -$(package)_dependencies=googletest - -$(package)_download_path=https://github.com/google/$(package)/archive/ -$(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_download_file=release-$($(package)_version).tar.gz -$(package)_sha256_hash=3f20b6acb37e5a98e8c4518165711e3e35d47deb6cdb5a4dd4566563b5efd232 - -define $(package)_build_cmds - $(MAKE) -C make GTEST_DIR='$(host_prefix)' CXXFLAGS='-fPIC' gmock-all.o -endef - - -define $(package)_stage_cmds - install -D ./make/gmock-all.o $($(package)_staging_dir)$(host_prefix)/lib/libgmock.a && \ - cp -a ./include $($(package)_staging_dir)$(host_prefix)/include -endef diff --git a/depends/packages/libsodium.mk b/depends/packages/libsodium.mk index d7717bbfc..8135e83d6 100644 --- a/depends/packages/libsodium.mk +++ b/depends/packages/libsodium.mk @@ -1,8 +1,8 @@ package=libsodium -$(package)_version=1.0.11 +$(package)_version=1.0.15 $(package)_download_path=https://download.libsodium.org/libsodium/releases/ -$(package)_file_name=libsodium-1.0.11.tar.gz -$(package)_sha256_hash=a14549db3c49f6ae2170cbbf4664bd48ace50681045e8dbea7c8d9fb96f9c765 +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4 $(package)_dependencies= $(package)_config_opts= diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index b9a15ba00..4be7ae5bf 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -16,7 +16,9 @@ testScripts=( 'wallet_treestate.py' 'wallet_protectcoinbase.py' 'wallet_shieldcoinbase.py' + 'wallet_mergetoaddress.py' 'wallet.py' + 'wallet_overwintertx.py' 'wallet_nullifiers.py' 'wallet_1941.py' 'listtransactions.py' @@ -27,8 +29,10 @@ testScripts=( 'rawtransactions.py' 'rest.py' 'mempool_spendcoinbase.py' - 'mempool_coinbase_spends.py' + 'mempool_reorg.py' 'mempool_tx_input_limit.py' + 'mempool_nu_activation.py' + 'mempool_tx_expiry.py' 'httpbasics.py' 'zapwallettxes.py' 'proxy_test.py' @@ -47,9 +51,11 @@ testScripts=( 'zcjoinsplit.py' 'zcjoinsplitdoublespend.py' 'zkey_import_export.py' + 'reorg_limit.py' 'getblocktemplate.py' 'bip65-cltv-p2p.py' 'bipdersig-p2p.py' + 'overwinter_peer_management.py' ); testScriptsExt=( 'getblocktemplate_longpoll.py' diff --git a/qa/rpc-tests/mempool_coinbase_spends.py b/qa/rpc-tests/mempool_coinbase_spends.py deleted file mode 100755 index 041de831b..000000000 --- a/qa/rpc-tests/mempool_coinbase_spends.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/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 re-org scenarios with a mempool that contains transactions -# that spend (directly or indirectly) coinbase transactions. -# - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, start_node, connect_nodes - - -# Create one-input, one-output, no-fee transaction: -class MempoolCoinbaseTest(BitcoinTestFramework): - - alert_filename = None # Set by setup_network - - def setup_network(self): - args = ["-checkmempool", "-debug=mempool"] - self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, args)) - self.nodes.append(start_node(1, self.options.tmpdir, args)) - connect_nodes(self.nodes[1], 0) - self.is_network_split = False - self.sync_all - - def create_tx(self, from_txid, to_address, amount): - inputs = [{ "txid" : from_txid, "vout" : 0}] - outputs = { to_address : amount } - rawtx = self.nodes[0].createrawtransaction(inputs, outputs) - signresult = self.nodes[0].signrawtransaction(rawtx) - assert_equal(signresult["complete"], True) - return signresult["hex"] - - def run_test(self): - # Mine three blocks. After this, nodes[0] blocks - # 101, 102, and 103 are spend-able. - new_blocks = self.nodes[1].generate(4) - self.sync_all() - - node0_address = self.nodes[0].getnewaddress() - node1_address = self.nodes[1].getnewaddress() - - # Three scenarios for re-orging coinbase spends in the memory pool: - # 1. Direct coinbase spend : spend_101 - # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1 - # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1 - # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase), - # and make sure the mempool code behaves correctly. - b = [ self.nodes[0].getblockhash(n) for n in range(102, 105) ] - coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] - spend_101_raw = self.create_tx(coinbase_txids[0], node1_address, 10) - spend_102_raw = self.create_tx(coinbase_txids[1], node0_address, 10) - spend_103_raw = self.create_tx(coinbase_txids[2], node0_address, 10) - - # 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].generate(1) - - # Create 102_1 and 103_1: - spend_102_1_raw = self.create_tx(spend_102_id, node1_address, 10) - spend_103_1_raw = self.create_tx(spend_103_id, node1_address, 10) - - # Broadcast and mine 103_1: - spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) - [spend_103_1_id] # hush pyflakes - 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) - spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw) - - self.sync_all() - - assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_101_id, spend_102_1_id ])) - - # Use invalidateblock to re-org back and make all those coinbase spends - # immature/invalid: - for node in self.nodes: - node.invalidateblock(new_blocks[0]) - - self.sync_all() - - # mempool should be empty. - assert_equal(set(self.nodes[0].getrawmempool()), set()) - -if __name__ == '__main__': - MempoolCoinbaseTest().main() diff --git a/qa/rpc-tests/mempool_nu_activation.py b/qa/rpc-tests/mempool_nu_activation.py new file mode 100644 index 000000000..f54095660 --- /dev/null +++ b/qa/rpc-tests/mempool_nu_activation.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +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 + +from decimal import Decimal + +# Test mempool behaviour around network upgrade activation +class MempoolUpgradeActivationTest(BitcoinTestFramework): + + alert_filename = None # Set by setup_network + + def setup_network(self): + args = ["-checkmempool", "-debug=mempool", "-blockmaxsize=4000", "-nuparams=5ba81b19:200"] + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, args)) + self.nodes.append(start_node(1, self.options.tmpdir, args)) + connect_nodes(self.nodes[1], 0) + self.is_network_split = False + self.sync_all + + def setup_chain(self): + print "Initializing test directory "+self.options.tmpdir + initialize_chain_clean(self.options.tmpdir, 2) + + def run_test(self): + self.nodes[1].generate(100) + self.sync_all() + + # Mine 97 blocks. After this, nodes[1] blocks + # 1 to 97 are spend-able. + self.nodes[0].generate(97) + self.sync_all() + + # Shield some ZEC + node1_taddr = self.nodes[1].getnewaddress() + node0_zaddr = self.nodes[0].z_getnewaddress() + recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] + myopid = self.nodes[1].z_sendmany(node1_taddr, recipients, 1, Decimal('0')) + print wait_and_assert_operationid_status(self.nodes[1], myopid) + self.sync_all() + + # Mine block 198. After this, the mempool expects + # block 199, which is the last Sprout block. + self.nodes[0].generate(1) + self.sync_all() + + # Mempool should be empty. + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + # Check node 0 shielded balance + assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) + + # Fill the mempool with twice as many transactions as can fit into blocks + node0_taddr = self.nodes[0].getnewaddress() + sprout_txids = [] + while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000: + sprout_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001'))) + self.sync_all() + + # Spends should be in the mempool + sprout_mempool = set(self.nodes[0].getrawmempool()) + assert_equal(sprout_mempool, set(sprout_txids)) + + # Mine block 199. After this, the mempool expects + # block 200, which is the first Overwinter block. + self.nodes[0].generate(1) + self.sync_all() + + # mempool should be empty. + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + # Block 199 should contain a subset of the original mempool + # (with all other transactions having been dropped) + block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx'] + assert(len(block_txids) < len(sprout_txids)) + for txid in block_txids[1:]: # Exclude coinbase + assert(txid in sprout_txids) + + # Create some transparent Overwinter transactions + overwinter_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)] + self.sync_all() + + # Create a shielded Overwinter transaction + recipients = [{'address': node0_taddr, 'amount': Decimal('10')}] + myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0')) + shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) + assert(shielded != None) + overwinter_txids.append(shielded) + self.sync_all() + + # Spends should be in the mempool + assert_equal(set(self.nodes[0].getrawmempool()), set(overwinter_txids)) + + # Node 0 note should be unspendable + assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0')) + + # Invalidate block 199. + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) + + # BUG: Ideally, the mempool should now only contain the transactions + # that were in block 199, the Overwinter transactions having been dropped. + # However, because chainActive is not updated until after the transactions + # in the disconnected block have been re-added to the mempool, the height + # seen by AcceptToMemoryPool is one greater than it should be. This causes + # the block 199 transactions to be validated against the Overwinter rules, + # and rejected because they (obviously) fail. + #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:])) + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + # Node 0 note should be spendable again + assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) + +if __name__ == '__main__': + MempoolUpgradeActivationTest().main() diff --git a/qa/rpc-tests/mempool_tx_expiry.py b/qa/rpc-tests/mempool_tx_expiry.py new file mode 100644 index 000000000..b78af986c --- /dev/null +++ b/qa/rpc-tests/mempool_tx_expiry.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test proper expiry for transactions >= version 3 +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.authproxy import JSONRPCException +from test_framework.util import assert_equal, connect_nodes, \ + connect_nodes_bi, sync_blocks, start_nodes, sync_blocks, sync_mempools, \ + wait_and_assert_operationid_status + +from decimal import Decimal +import time + +class MempoolTxExpiryTest(BitcoinTestFramework): + + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, [["-nuparams=5ba81b19:205", "-txexpirydelta=4"]] * 4) + + # Test before, at, and after expiry block + # TODO: Test case of dependent txs in reorgs + # chain is at block height 199 when run_test executes + def run_test(self): + alice = self.nodes[0].getnewaddress() + z_alice = self.nodes[0].z_getnewaddress() + bob = self.nodes[2].getnewaddress() + z_bob = self.nodes[2].z_getnewaddress() + + # When Overwinter not yet activated, no expiryheight in tx + sapling_tx = self.nodes[0].sendtoaddress(bob, 0.01) + rawtx = self.nodes[0].getrawtransaction(sapling_tx, 1) + assert_equal(rawtx["overwintered"], False) + assert("expiryheight" not in rawtx) + + self.nodes[0].generate(6) + self.sync_all() + + ## Shield one of Alice's coinbase funds to her zaddr + res = self.nodes[0].z_shieldcoinbase("*", z_alice, 0.0001, 1) + wait_and_assert_operationid_status(self.nodes[0], res['opid']) + self.nodes[0].generate(1) + self.sync_all() + + # Get balance on node 0 + bal = self.nodes[0].z_gettotalbalance() + print "Balance before zsend, after shielding 10: ", bal + assert_equal(Decimal(bal["private"]), Decimal("9.9999")) + + print "Splitting network..." + self.split_network() + + # Create transactions + zsendamount = Decimal('1.0') - Decimal('0.0001') + recipients = [] + recipients.append({"address": z_bob, "amount": zsendamount}) + myopid = self.nodes[0].z_sendmany(z_alice, recipients) + persist_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) + persist_transparent = self.nodes[0].sendtoaddress(bob, 0.01) + # Verify transparent transaction is version 3 intended for Overwinter branch + rawtx = self.nodes[0].getrawtransaction(persist_transparent, 1) + assert_equal(rawtx["version"], 3) + assert_equal(rawtx["overwintered"], True) + assert_equal(rawtx["expiryheight"], 212) + print "Blockheight at persist_transparent & persist_shielded creation:", self.nodes[0].getblockchaininfo()['blocks'] + print "Expiryheight of persist_transparent:", rawtx['expiryheight'] + # Verify shielded transaction is version 3 intended for Overwinter branch + rawtx = self.nodes[0].getrawtransaction(persist_shielded, 1) + print "Expiryheight of persist_shielded", rawtx['expiryheight'] + assert_equal(rawtx["version"], 3) + assert_equal(rawtx["overwintered"], True) + assert_equal(rawtx["expiryheight"], 212) + + print "\n Blockheight advances to less than expiry block height. After reorg, txs should persist in mempool" + assert(persist_transparent in self.nodes[0].getrawmempool()) + assert(persist_shielded in self.nodes[0].getrawmempool()) + assert_equal(set(self.nodes[2].getrawmempool()), set()) + print "mempool node 0:", self.nodes[0].getrawmempool() + print "mempool node 2:", self.nodes[2].getrawmempool() + bal = self.nodes[0].z_gettotalbalance() + print "Printing balance before persist_shielded & persist_transparent are initially mined from mempool", bal + # Txs are mined on node 0; will later be rolled back + self.nodes[0].generate(1) + print "Node 0 generated 1 block" + print "Node 0 height:", self.nodes[0].getblockchaininfo()['blocks'] + print "Node 2 height:", self.nodes[2].getblockchaininfo()['blocks'] + bal = self.nodes[0].z_gettotalbalance() + print "Printing balance after persist_shielded & persist_transparent are mined:", bal + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + print "Mine 2 competing blocks on Node 2..." + blocks = self.nodes[2].generate(2) + for block in blocks: + blk = self.nodes[2].getblock(block) + print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"]) + print "Connect nodes to force a reorg" + connect_nodes_bi(self.nodes,0,2) + self.is_network_split = False + + print "Syncing blocks" + sync_blocks(self.nodes) + + print "Ensure that txs are back in mempool of node 0" + print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks'] + print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks'] + print "mempool node 0: ", self.nodes[0].getrawmempool() + print "mempool node 2: ", self.nodes[2].getrawmempool() + assert(persist_transparent in self.nodes[0].getrawmempool()) + assert(persist_shielded in self.nodes[0].getrawmempool()) + bal = self.nodes[0].z_gettotalbalance() + # Mine txs to get them out of the way of mempool sync in split_network() + print "Generating another block on node 0 to clear txs from mempool" + self.nodes[0].generate(1) + assert_equal(set(self.nodes[0].getrawmempool()), set()) + sync_blocks(self.nodes) + + print "Splitting network..." + self.split_network() + + print "\n Blockheight advances to equal expiry block height. After reorg, txs should persist in mempool" + myopid = self.nodes[0].z_sendmany(z_alice, recipients) + persist_shielded_2 = wait_and_assert_operationid_status(self.nodes[0], myopid) + persist_transparent_2 = self.nodes[0].sendtoaddress(bob, 0.01) + rawtx_trans = self.nodes[0].getrawtransaction(persist_transparent_2, 1) + rawtx_shield = self.nodes[0].getrawtransaction(persist_shielded_2, 1) + print "Blockheight node 0 at persist_transparent_2 creation:", self.nodes[0].getblockchaininfo()['blocks'] + print "Blockheight node 2 at persist_transparent_2 creation:", self.nodes[2].getblockchaininfo()['blocks'] + print "Expiryheight of persist_transparent_2:", rawtx_trans['expiryheight'] + print "Expiryheight of persist_shielded_2:", rawtx_shield['expiryheight'] + blocks = self.nodes[2].generate(4) + for block in blocks: + blk = self.nodes[2].getblock(block) + print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"]) + print "Connect nodes to force a reorg" + connect_nodes_bi(self.nodes, 0, 2) + self.is_network_split = False + sync_blocks(self.nodes) + print "Ensure that persist_transparent_2 & persist_shielded_2 are in mempool at expiry block height" + print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks'] + print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks'] + print "mempool node 0: ", self.nodes[0].getrawmempool() + print "mempool node 2: ", self.nodes[2].getrawmempool() + assert(persist_transparent_2 in self.nodes[0].getrawmempool()) + assert(persist_shielded_2 in self.nodes[0].getrawmempool()) + # Mine persist txs to get them out of the way of mempool sync in split_network() + self.nodes[0].generate(1) + assert_equal(set(self.nodes[0].getrawmempool()), set()) + sync_blocks(self.nodes) + print "Balance after persist_shielded_2 is mined to remove from mempool: ", self.nodes[0].z_gettotalbalance() + + print "Splitting network..." + self.split_network() + + print "\n Blockheight advances to greater than expiry block height. After reorg, txs should expire from mempool" + print "Balance before expire_shielded is sent: ", self.nodes[0].z_gettotalbalance() + myopid = self.nodes[0].z_sendmany(z_alice, recipients) + expire_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) + expire_transparent = self.nodes[0].sendtoaddress(bob, 0.01) + print "Blockheight node 0 at expire_transparent creation:", self.nodes[0].getblockchaininfo()['blocks'] + print "Blockheight node 2 at expire_shielded creation:", self.nodes[2].getblockchaininfo()['blocks'] + print "Expiryheight of expire_transparent:", self.nodes[0].getrawtransaction(expire_transparent, 1)['expiryheight'] + print "Expiryheight of expire_shielded:", self.nodes[0].getrawtransaction(expire_shielded, 1)['expiryheight'] + assert(expire_transparent in self.nodes[0].getrawmempool()) + assert(expire_shielded in self.nodes[0].getrawmempool()) + blocks = self.nodes[2].generate(6) + for block in blocks: + blk = self.nodes[2].getblock(block) + print "Height: {0}, Mined block txs: {1}".format(blk["height"], blk["tx"]) + print "Connect nodes to force a reorg" + connect_nodes_bi(self.nodes, 0, 2) + self.is_network_split = False + sync_blocks(self.nodes) + print "Ensure that expire_transparent & expire_shielded are in mempool at expiry block height" + print "mempool node 0: ", self.nodes[0].getrawmempool() + print "mempool node 2: ", self.nodes[2].getrawmempool() + assert_equal(set(self.nodes[0].getrawmempool()), set()) + print "Ensure balance of node 0 is correct" + bal = self.nodes[0].z_gettotalbalance() + print "Balance after expire_shielded has expired: ", bal + assert_equal(Decimal(bal["private"]), Decimal("7.9999")) + + +if __name__ == '__main__': + MempoolTxExpiryTest().main() diff --git a/qa/rpc-tests/overwinter_peer_management.py b/qa/rpc-tests/overwinter_peer_management.py new file mode 100644 index 000000000..a7a71e52d --- /dev/null +++ b/qa/rpc-tests/overwinter_peer_management.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.mininode import NodeConn, NodeConnCB, NetworkThread, \ + EarlyDisconnectError, msg_inv, mininode_lock, msg_ping, \ + MY_VERSION, OVERWINTER_PROTO_VERSION +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import initialize_chain_clean, start_nodes, \ + p2p_port, assert_equal + +import time + +# +# In this test we connect Sprout and Overwinter mininodes to a Zcashd node +# which will activate Overwinter at block 10. +# +# We test: +# 1. the mininodes stay connected to Zcash with Sprout consensus rules +# 2. when Overwinter activates, the Sprout mininodes are dropped +# 3. new Overwinter nodes can connect to Zcash +# 4. new Sprout nodes cannot connect to Zcash +# +# This test *does not* verify that prior to Overwinter activation, the Zcashd +# node will prefer connections with Overwinter nodes, with an eviction process +# that prioritizes Sprout connections. +# + + +class TestManager(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.create_callback_map() + + def on_close(self, conn): + pass + + def on_reject(self, conn, message): + conn.rejectMessage = message + + +class OverwinterPeerManagementTest(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 = start_nodes(1, self.options.tmpdir, + extra_args=[['-nuparams=5ba81b19:10', '-debug', '-whitelist=127.0.0.1']]) + + def run_test(self): + test = TestManager() + + # Launch 10 Sprout and 10 Overwinter mininodes + nodes = [] + for x in xrange(10): + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", False)) + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", True)) + + # Start up network handling in another thread + NetworkThread().start() + + # Sprout consensus rules apply at block height 9 + self.nodes[0].generate(9) + assert_equal(9, self.nodes[0].getblockcount()) + + # Verify mininodes are still connected to zcashd node + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(10, versions.count(MY_VERSION)) + assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION)) + + # Overwinter consensus rules activate at block height 10 + self.nodes[0].generate(1) + assert_equal(10, self.nodes[0].getblockcount()) + + # Mininodes send ping message to zcashd node. + pingCounter = 1 + for node in nodes: + node.send_message(msg_ping(pingCounter)) + pingCounter = pingCounter + 1 + + time.sleep(3) + + # Verify Sprout mininodes have been dropped and Overwinter mininodes are still connected. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(0, versions.count(MY_VERSION)) + assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION)) + + # Extend the Overwinter chain with another block. + self.nodes[0].generate(1) + + # Connect a new Overwinter mininode to the zcashd node, which is accepted. + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", True)) + time.sleep(3) + assert_equal(11, len(self.nodes[0].getpeerinfo())) + + # Try to connect a new Sprout mininode to the zcashd node, which is rejected. + sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", False) + nodes.append(sprout) + time.sleep(3) + assert("Version must be 170003 or greater" in str(sprout.rejectMessage)) + + # Verify that only Overwinter mininodes are connected. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(0, versions.count(MY_VERSION)) + assert_equal(11, versions.count(OVERWINTER_PROTO_VERSION)) + + for node in nodes: + node.disconnect_node() + +if __name__ == '__main__': + OverwinterPeerManagementTest().main() diff --git a/qa/rpc-tests/reorg_limit.py b/qa/rpc-tests/reorg_limit.py new file mode 100644 index 000000000..3857498ee --- /dev/null +++ b/qa/rpc-tests/reorg_limit.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python2 +# Copyright (c) 2017 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test reorg limit +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + check_node, + connect_nodes_bi, + initialize_chain_clean, + start_node, + sync_blocks, +) +from time import sleep + +def check_stopped(i, timeout=10): + stopped = False + for x in xrange(1, timeout): + ret = check_node(i) + if ret is None: + sleep(1) + else: + stopped = True + break + return stopped + +class ReorgLimitTest(BitcoinTestFramework): + + def run_test(self): + assert(self.nodes[0].getblockcount() == 200) + assert(self.nodes[2].getblockcount() == 200) + + self.split_network() + + print "Test the maximum-allowed reorg:" + print "Mine 99 blocks on Node 0" + self.nodes[0].generate(99) + assert(self.nodes[0].getblockcount() == 299) + assert(self.nodes[2].getblockcount() == 200) + + print "Mine competing 100 blocks on Node 2" + self.nodes[2].generate(100) + assert(self.nodes[0].getblockcount() == 299) + assert(self.nodes[2].getblockcount() == 300) + + print "Connect nodes to force a reorg" + connect_nodes_bi(self.nodes, 0, 2) + self.is_network_split = False + sync_blocks(self.nodes) + + print "Check Node 0 is still running and on the correct chain" + assert(self.nodes[0].getblockcount() == 300) + + self.split_network() + + print "Test the minimum-rejected reorg:" + print "Mine 100 blocks on Node 0" + self.nodes[0].generate(100) + assert(self.nodes[0].getblockcount() == 400) + assert(self.nodes[2].getblockcount() == 300) + + print "Mine competing 101 blocks on Node 2" + self.nodes[2].generate(101) + assert(self.nodes[0].getblockcount() == 400) + assert(self.nodes[2].getblockcount() == 401) + + print "Sync nodes to force a reorg" + connect_nodes_bi(self.nodes, 0, 2) + self.is_network_split = False + # sync_blocks uses RPC calls to wait for nodes to be synced, so don't + # call it here, because it will have a non-specific connection error + # when Node 0 stops. Instead, we explicitly check for the process itself + # to stop. + + print "Check Node 0 is no longer running" + assert(check_stopped(0)) + + # Dummy stop to enable the test to tear down + self.nodes[0].stop = lambda: True + +if __name__ == '__main__': + ReorgLimitTest().main() diff --git a/qa/rpc-tests/wallet_overwintertx.py b/qa/rpc-tests/wallet_overwintertx.py new file mode 100644 index 000000000..176e8693e --- /dev/null +++ b/qa/rpc-tests/wallet_overwintertx.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.authproxy import JSONRPCException +from test_framework.util import assert_equal, initialize_chain_clean, \ + start_nodes, connect_nodes_bi, sync_blocks, sync_mempools, \ + wait_and_assert_operationid_status + +from decimal import Decimal + +class WalletOverwinterTxTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self, split=False): + self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[["-nuparams=5ba81b19:200", "-debug=zrpcunsafe", "-txindex"]] * 4 ) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + connect_nodes_bi(self.nodes,0,3) + self.is_network_split=False + self.sync_all() + + def run_test (self): + self.nodes[0].generate(100) + self.sync_all() + self.nodes[1].generate(98) + self.sync_all() + # Node 0 has reward from blocks 1 to 98 which are spendable. + + taddr0 = self.nodes[0].getnewaddress() + taddr1 = self.nodes[1].getnewaddress() + taddr2 = self.nodes[2].getnewaddress() + zaddr2 = self.nodes[2].z_getnewaddress() + taddr3 = self.nodes[3].getnewaddress() + zaddr3 = self.nodes[3].z_getnewaddress() + + # + # Currently at block 198. The next block to be mined 199 is a Sprout block + # + bci = self.nodes[0].getblockchaininfo() + assert_equal(bci['consensus']['chaintip'], '00000000') + assert_equal(bci['consensus']['nextblock'], '00000000') + assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending') + + # Node 0 sends transparent funds to Node 2 + tsendamount = Decimal('1.0') + txid_transparent = self.nodes[0].sendtoaddress(taddr2, tsendamount) + self.sync_all() + + # Node 2 sends the zero-confirmation transparent funds to Node 1 using z_sendmany + recipients = [] + recipients.append({"address":taddr1, "amount": Decimal('0.5')}) + myopid = self.nodes[2].z_sendmany(taddr2, recipients, 0) + txid_zsendmany = wait_and_assert_operationid_status(self.nodes[2], myopid) + + # Node 0 shields to Node 2, a coinbase utxo of value 10.0 less fee 0.00010000 + zsendamount = Decimal('10.0') - Decimal('0.0001') + recipients = [] + recipients.append({"address":zaddr2, "amount": zsendamount}) + myopid = self.nodes[0].z_sendmany(taddr0, recipients) + txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + # Verify balance + assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0.5')) + assert_equal(self.nodes[2].getbalance(), Decimal('0.4999')) + assert_equal(self.nodes[2].z_getbalance(zaddr2), zsendamount) + + # Verify transaction versions are 1 or 2 (intended for Sprout) + result = self.nodes[0].getrawtransaction(txid_transparent, 1) + assert_equal(result["version"], 1) + assert_equal(result["overwintered"], False) + result = self.nodes[0].getrawtransaction(txid_zsendmany, 1) + assert_equal(result["version"], 1) + assert_equal(result["overwintered"], False) + result = self.nodes[0].getrawtransaction(txid_shielded, 1) + assert_equal(result["version"], 2) + assert_equal(result["overwintered"], False) + + # + # Currently at block 199. The next block to be mined 200 is an Overwinter block + # + bci = self.nodes[0].getblockchaininfo() + assert_equal(bci['consensus']['chaintip'], '00000000') + assert_equal(bci['consensus']['nextblock'], '5ba81b19') + assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending') + + # Node 0 sends transparent funds to Node 3 + tsendamount = Decimal('1.0') + txid_transparent = self.nodes[0].sendtoaddress(taddr3, tsendamount) + self.sync_all() + + # Node 3 sends the zero-confirmation transparent funds to Node 1 using z_sendmany + recipients = [] + recipients.append({"address":taddr1, "amount": Decimal('0.5')}) + myopid = self.nodes[3].z_sendmany(taddr3, recipients, 0) + txid_zsendmany = wait_and_assert_operationid_status(self.nodes[3], myopid) + + # Node 0 shields to Node 3, a coinbase utxo of value 10.0 less fee 0.00010000 + zsendamount = Decimal('10.0') - Decimal('0.0001') + recipients = [] + recipients.append({"address":zaddr3, "amount": zsendamount}) + myopid = self.nodes[0].z_sendmany(taddr0, recipients) + txid_shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) + + # Mine the first Overwinter block + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + bci = self.nodes[0].getblockchaininfo() + assert_equal(bci['consensus']['chaintip'], '5ba81b19') + assert_equal(bci['consensus']['nextblock'], '5ba81b19') + assert_equal(bci['upgrades']['5ba81b19']['status'], 'active') + + # Verify balance + assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('1.0')) + assert_equal(self.nodes[3].getbalance(), Decimal('0.4999')) + assert_equal(self.nodes[3].z_getbalance(zaddr3), zsendamount) + + # Verify transaction version is 3 (intended for Overwinter) + result = self.nodes[0].getrawtransaction(txid_transparent, 1) + assert_equal(result["version"], 3) + assert_equal(result["overwintered"], True) + assert_equal(result["versiongroupid"], "03c48270") + result = self.nodes[0].getrawtransaction(txid_zsendmany, 1) + assert_equal(result["version"], 3) + assert_equal(result["overwintered"], True) + assert_equal(result["versiongroupid"], "03c48270") + result = self.nodes[0].getrawtransaction(txid_shielded, 1) + assert_equal(result["version"], 3) + assert_equal(result["overwintered"], True) + assert_equal(result["versiongroupid"], "03c48270") + +if __name__ == '__main__': + WalletOverwinterTxTest().main() diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index b0159ccd7..ee2513971 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -6,6 +6,7 @@ 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, stop_node, wait_and_assert_operationid_status @@ -22,6 +23,7 @@ def check_value_pool(node, name, total): found = True assert_equal(pool['monitored'], True) assert_equal(pool['chainValue'], total) + assert_equal(pool['chainValueZat'], total * COIN) assert(found) class WalletProtectCoinbaseTest (BitcoinTestFramework): diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index 31048e163..b77fedcf0 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -1,4 +1,3 @@ - #!/usr/bin/env python2 # Copyright (c) 2017 The Zcash developers # Distributed under the MIT software license, see the accompanying diff --git a/share/certs/BitcoinFoundation_Apple_Cert.pem b/share/certs/BitcoinFoundation_Apple_Cert.pem deleted file mode 100644 index beb0d7073..000000000 --- a/share/certs/BitcoinFoundation_Apple_Cert.pem +++ /dev/null @@ -1,37 +0,0 @@ -Bag Attributes - friendlyName: Developer ID Application: BITCOIN FOUNDATION, INC., THE - localKeyID: 6B 9C 6C A8 A5 73 70 70 E2 57 A3 49 D8 62 FB 97 C7 A5 5D 5E -subject=/UID=PBV4GLS9J4/CN=Developer ID Application: BITCOIN FOUNDATION, INC., THE/OU=PBV4GLS9J4/O=BITCOIN FOUNDATION, INC., THE/C=US -issuer=/CN=Developer ID Certification Authority/OU=Apple Certification Authority/O=Apple Inc./C=US ------BEGIN CERTIFICATE----- -MIIFhzCCBG+gAwIBAgIIJ0r1rumyfZAwDQYJKoZIhvcNAQELBQAweTEtMCsGA1UE -AwwkRGV2ZWxvcGVyIElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQL -DB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUg -SW5jLjELMAkGA1UEBhMCVVMwHhcNMTMwMTEwMjIzOTAxWhcNMTgwMTExMjIzOTAx -WjCBqDEaMBgGCgmSJomT8ixkAQEMClBCVjRHTFM5SjQxQDA+BgNVBAMMN0RldmVs -b3BlciBJRCBBcHBsaWNhdGlvbjogQklUQ09JTiBGT1VOREFUSU9OLCBJTkMuLCBU -SEUxEzARBgNVBAsMClBCVjRHTFM5SjQxJjAkBgNVBAoMHUJJVENPSU4gRk9VTkRB -VElPTiwgSU5DLiwgVEhFMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBALTd5zURuZVoJviusr119aktXksenb9IN9vq6kBbq38vxEk7 -9wkKMES2XfBRh0HxcEizGzhMNy5OCXuTLMaNMihYdfwYSoBoR2foEU+6kjPUnyJ4 -dQBFLJZJr5/QeQmALmYHEgZ6lwXFD2lU8t92340zeJ4y5LZw5pcEHtH9IummYDut -OGCkCGXDcjL+5nHhNScJiXHhswM+62o6XXsQiP6EWbM1CsgrGTNLtaa0U/UvVDwE -79YKklSC5Bog2LD0jBcTuveI66mFzqu++L9X9u+ZArtebwCl7BPNQ+uboYy5uV2d -zf8lpNNZLfXCFjoLe9bLICKfZ7ub9V5aC8+GhckCAwEAAaOCAeEwggHdMD4GCCsG -AQUFBwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuYXBwbGUuY29tL29j -c3AtZGV2aWQwMTAdBgNVHQ4EFgQUa5xsqKVzcHDiV6NJ2GL7l8elXV4wDAYDVR0T -AQH/BAIwADAfBgNVHSMEGDAWgBRXF+2iz9x8mKEQ4Py+hy0s8uMXVDCCAQ4GA1Ud -IASCAQUwggEBMIH+BgkqhkiG92NkBQEwgfAwKAYIKwYBBQUHAgEWHGh0dHA6Ly93 -d3cuYXBwbGUuY29tL2FwcGxlY2EwgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ug -b24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRh -bmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNv -bmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmlj -YXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wDgYDVR0PAQH/BAQDAgeAMBYGA1Ud -JQEB/wQMMAoGCCsGAQUFBwMDMBMGCiqGSIb3Y2QGAQ0BAf8EAgUAMA0GCSqGSIb3 -DQEBCwUAA4IBAQAfJ0BjID/1dS2aEeVyhAzPzCBjG8vm0gDf+/qfwRn3+yWeL9vS -nMdbilwM48IyQWTagjGGcojbsAd/vE4N7NhQyHInoCllNoeor1I5xx+blTaGRBK+ -dDhJbbdlGCjsLnH/BczGZi5fyEJds9lUIrp1hJidRcUKO76qb/9gc6qNZpl1vH5k -lDUuJYt7YhAs+L6rTXDyqcK9maeQr0gaOPsRRAQLLwiQCorPeMTUNsbVMdMwZYJs -R+PxiAnk+nyi7rfiFvPoASAYUuI6OzYL/Fa6QU4/gYyPgic944QYVkaQBnc0vEP1 -nXq6LGKwgVGcqJnkr/E2kui5gJoV5C3qll3e ------END CERTIFICATE----- diff --git a/share/certs/BitcoinFoundation_Comodo_Cert.pem b/share/certs/BitcoinFoundation_Comodo_Cert.pem deleted file mode 100644 index dc752d455..000000000 --- a/share/certs/BitcoinFoundation_Comodo_Cert.pem +++ /dev/null @@ -1,37 +0,0 @@ -Bag Attributes - friendlyName: The Bitcoin Foundation, Inc.'s COMODO CA Limited ID - localKeyID: 8C 94 64 E3 B5 B0 41 89 5B 89 B0 57 CC 74 B9 44 E5 B2 92 66 -subject=/C=US/postalCode=98104-1444/ST=WA/L=Seattle/street=Suite 300/street=71 Columbia St/O=The Bitcoin Foundation, Inc./CN=The Bitcoin Foundation, Inc. -issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Code Signing CA 2 ------BEGIN CERTIFICATE----- -MIIFeDCCBGCgAwIBAgIRAJVYMd+waOER7lUqtiz3M2IwDQYJKoZIhvcNAQEFBQAw -ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxITAfBgNV -BAMTGENPTU9ETyBDb2RlIFNpZ25pbmcgQ0EgMjAeFw0xMzAxMTYwMDAwMDBaFw0x -NDAxMTYyMzU5NTlaMIG8MQswCQYDVQQGEwJVUzETMBEGA1UEEQwKOTgxMDQtMTQ0 -NDELMAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEjAQBgNVBAkMCVN1aXRl -IDMwMDEXMBUGA1UECQwONzEgQ29sdW1iaWEgU3QxJTAjBgNVBAoMHFRoZSBCaXRj -b2luIEZvdW5kYXRpb24sIEluYy4xJTAjBgNVBAMMHFRoZSBCaXRjb2luIEZvdW5k -YXRpb24sIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChUwLD -u/hu5aFZ/n11B27awONaaDrmHm0pamiWHb01yL4JmTBtaLCrSftF8RhCscQ8jpI0 -UG1Cchmay0e3zH5o5XRs0H9C3x+SM5ozms0TWDmAYiB8aQEghsGovDk0D2nyTQeK -Q0xqyCh0m8ZPOnMnYrakHEmF6WvhLdJvI6Od4KIwbKxgN17cPFIfLVsZ7GrzmmbU -Gdi4wSQCHy5rxzvBxho8Qq/SfBl93uOMUrqOHjOUAPhNuTJG3t/MdhU8Zp24s29M -abHtYkT9W86hMjIiI8RTAR+WHKVglx9SB0cjDabXN8SZ3gME0+H++LyzlySHT8sI -ykepojZ7UBRgp9w3AgMBAAGjggGzMIIBrzAfBgNVHSMEGDAWgBQexbEsfYfaAmh8 -JbwMB4Q/ts/e8TAdBgNVHQ4EFgQUfPf+ZyDWl/4LH0Y5BuJTelkRd/EwDgYDVR0P -AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYJ -YIZIAYb4QgEBBAQDAgQQMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQMCMCswKQYI -KwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5uZXQvQ1BTMEEGA1UdHwQ6 -MDgwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWdu -aW5nQ0EyLmNybDByBggrBgEFBQcBAQRmMGQwPAYIKwYBBQUHMAKGMGh0dHA6Ly9j -cnQuY29tb2RvY2EuY29tL0NPTU9ET0NvZGVTaWduaW5nQ0EyLmNydDAkBggrBgEF -BQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMCgGA1UdEQQhMB+BHWxpbmRz -YXlAYml0Y29pbmZvdW5kYXRpb24ub3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAqibjo -D4HG5XSIIMCmYE5RgQBSEAJfI+EZERk1G9F83ZUWr0yNRZCw4O+RaM7xQhvJhEoD -G2kpk/q2bNOc71/VyZ6SrE1JRVUON41/Flhz4M6cP0BclTicXvh+efVwqZhIz+ws -UxF2hvC/1Xx6rqI7NYAlOYXk2MSUq3HREo+gWUPKM8em4MZZV/7XCH4QbsfxOl1J -xS6EOQmV8hfUN4KRXI5WfGUmedBxq7dM0RSJOSQl8fq2f+JjRLfjQwQucy7LDY+y -pRTsL2TdQV/DuDuI3s0NHRGznQNddoX5jqpXhSQFAAdgrhN1gGkWaaTPzr9IF2TG -qgr6PEp9tIYC+MbM ------END CERTIFICATE----- diff --git a/share/certs/PrivateKeyNotes.md b/share/certs/PrivateKeyNotes.md deleted file mode 100644 index da299d168..000000000 --- a/share/certs/PrivateKeyNotes.md +++ /dev/null @@ -1,46 +0,0 @@ -Code-signing private key notes -== - -The private keys for these certificates were generated on Gavin's main work machine, -following the certificate authoritys' recommendations for generating certificate -signing requests. - -For OSX, the private key was generated by Keychain.app on Gavin's main work machine. -The key and certificate is in a separate, passphrase-protected keychain file that is -unlocked to sign the Bitcoin-Qt.app bundle. - -For Windows, the private key was generated by Firefox running on Gavin's main work machine. -The key and certificate were exported into a separate, passphrase-protected PKCS#12 file, and -then deleted from Firefox's keystore. The exported file is used to sign the Windows setup.exe. - -Threat analysis --- - -Gavin is a single point of failure. He could be coerced to divulge the secret signing keys, -allowing somebody to distribute a Bitcoin-Qt.app or bitcoin-qt-setup.exe with a valid -signature but containing a malicious binary. - -Or the machine Gavin uses to sign the binaries could be compromised, either remotely or -by breaking in to his office, allowing the attacker to get the private key files and then -install a keylogger to get the passphrase that protects them. - -Threat Mitigation --- - -"Air gapping" the machine used to do the signing will not work, because the signing -process needs to access a timestamp server over the network. And it would not -prevent the "rubber hose cryptography" threat (coercing Gavin to sign a bad binary -or divulge the private keys). - -Windows binaries are reproducibly 'gitian-built', and the setup.exe file created -by the NSIS installer system is a 7zip archive, so you could check to make sure -that the bitcoin-qt.exe file inside the installer had not been tampered with. -However, an attacker could modify the installer's code, so when the setup.exe -was run it compromised users' systems. A volunteer to write an auditing tool -that checks the setup.exe for tampering, and checks the files in it against -the list of gitian signatures, is needed. - -The long-term solution is something like the 'gitian downloader' system, which -uses signatures from multiple developers to determine whether or not a binary -should be trusted. However, that just pushes the problem to "how will -non-technical users securely get the gitian downloader code to start?" diff --git a/share/pixmaps/addressbook16.bmp b/share/pixmaps/addressbook16.bmp deleted file mode 100644 index c5576910b..000000000 Binary files a/share/pixmaps/addressbook16.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook16mask.bmp b/share/pixmaps/addressbook16mask.bmp deleted file mode 100644 index d3a478d1a..000000000 Binary files a/share/pixmaps/addressbook16mask.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook20.bmp b/share/pixmaps/addressbook20.bmp deleted file mode 100644 index 2b33b228a..000000000 Binary files a/share/pixmaps/addressbook20.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook20mask.bmp b/share/pixmaps/addressbook20mask.bmp deleted file mode 100644 index 56ce6125d..000000000 Binary files a/share/pixmaps/addressbook20mask.bmp and /dev/null differ diff --git a/share/pixmaps/bitcoin-bc.ico b/share/pixmaps/bitcoin-bc.ico deleted file mode 100644 index 88cc240e2..000000000 Binary files a/share/pixmaps/bitcoin-bc.ico and /dev/null differ diff --git a/share/pixmaps/bitcoin.ico b/share/pixmaps/bitcoin.ico deleted file mode 100644 index f5480f416..000000000 Binary files a/share/pixmaps/bitcoin.ico and /dev/null differ diff --git a/share/pixmaps/bitcoin128.png b/share/pixmaps/bitcoin128.png deleted file mode 100644 index 55039b1c9..000000000 Binary files a/share/pixmaps/bitcoin128.png and /dev/null differ diff --git a/share/pixmaps/bitcoin128.xpm b/share/pixmaps/bitcoin128.xpm deleted file mode 100644 index d8e41e9ea..000000000 --- a/share/pixmaps/bitcoin128.xpm +++ /dev/null @@ -1,384 +0,0 @@ -/* XPM */ -static char *bitcoin___[] = { -/* columns rows colors chars-per-pixel */ -"128 128 250 2", -" c #845415", -". c #895616", -"X c #84581E", -"o c #8D5C18", -"O c #925A15", -"+ c #925E1C", -"@ c #98621C", -"# c #9E711C", -"$ c #A36E1A", -"% c #A96F1B", -"& c #A6711C", -"* c #AC741C", -"= c #B2741E", -"- c #B37C1E", -"; c #BB7C1E", -": c #835B21", -"> c #8F6125", -", c #956727", -"< c #916B2E", -"1 c #996B2C", -"2 c #B47B23", -"3 c #BD7C20", -"4 c #A17330", -"5 c #AB7D3B", -"6 c #C17F20", -"7 c #B9831F", -"8 c #BB842B", -"9 c #BD8533", -"0 c #B68F3D", -"q c #BE8C3B", -"w c #C4801F", -"e c #FE8C03", -"r c #F38A0F", -"t c #FD8E0A", -"y c #FF910C", -"u c #F78F13", -"i c #F98F10", -"p c #F79016", -"a c #FE9314", -"s c #F6931E", -"d c #FD961B", -"f c #FE991E", -"g c #C58421", -"h c #CD8621", -"j c #C78B21", -"k c #CC8B23", -"l c #C2852B", -"z c #C08B2D", -"x c #D28722", -"c c #D38B25", -"v c #DB8E22", -"b c #D28E2C", -"n c #D49323", -"m c #DC9224", -"M c #DC9B25", -"N c #D4922D", -"B c #DF972A", -"V c #DF982E", -"C c #C18D33", -"Z c #C58E38", -"A c #CB9332", -"S c #C2933C", -"D c #CD9339", -"F c #CC9938", -"G c #D19733", -"H c #DA9230", -"J c #D59935", -"K c #DC9C33", -"L c #DC9E3B", -"P c #E49124", -"I c #EA9426", -"U c #E09D26", -"Y c #EC972B", -"T c #F79625", -"R c #F99524", -"E c #F69A26", -"W c #F89825", -"Q c #F2972B", -"! c #F59A2C", -"~ c #F89B2B", -"^ c #E79D33", -"/ c #EF9D31", -"( c #E19F3A", -") c #EF9D3A", -"_ c #F49C33", -"` c #F99E32", -"' c #F49F39", -"] c #D6A13E", -"[ c #DAA33B", -"{ c #E3A127", -"} c #E7A328", -"| c #EDA32C", -" . c #EDA829", -".. c #FFA325", -"X. c #FFAB25", -"o. c #F3A42B", -"O. c #FFA429", -"+. c #F4A929", -"@. c #FFAC2A", -"#. c #FFB227", -"$. c #FFB32C", -"%. c #FFBA2D", -"&. c #EEA830", -"*. c #F7A334", -"=. c #FAA036", -"-. c #FCAB34", -";. c #F4A13C", -":. c #F9A33B", -">. c #F4A83B", -",. c #FFA83F", -"<. c #FDB432", -"1. c #FFBB33", -"2. c #FFB73A", -"3. c #FDB93E", -"4. c #FFC12F", -"5. c #FFC432", -"6. c #FFC338", -"7. c #D2A043", -"8. c #D8A140", -"9. c #EEA144", -"0. c #E2A840", -"q. c #EDA34B", -"w. c #F4A444", -"e. c #F9A642", -"r. c #FBA945", -"t. c #F3A64B", -"y. c #F4A84E", -"u. c #FBAB4B", -"i. c #EEB041", -"p. c #FABA44", -"a. c #ECA653", -"s. c #EEAC5D", -"d. c #F3AA53", -"f. c #FAAE53", -"g. c #F2AD5A", -"h. c #FBB056", -"j. c #F6B15E", -"k. c #FBB25B", -"l. c #DDAF79", -"z. c #E3A962", -"x. c #EBAE63", -"c. c #E4AC68", -"v. c #EAAF69", -"b. c #EEB065", -"n. c #E7B06C", -"m. c #EEB36B", -"M. c #F5B263", -"N. c #FBB461", -"B. c #E6B274", -"V. c #ECB574", -"C. c #E7B57B", -"Z. c #EAB77C", -"A. c #ECB97C", -"S. c #F2B770", -"D. c #F0BB7A", -"F. c #DBB485", -"G. c #DFB888", -"H. c #E4B984", -"J. c #EDBD82", -"K. c #E5BC8B", -"L. c #EABE8A", -"P. c #F0BE82", -"I. c #E0BF96", -"U. c #EDC089", -"Y. c #F0C28B", -"T. c #E5C194", -"R. c #E9C191", -"E. c #E4C39C", -"W. c #EBC699", -"Q. c #EBC99F", -"!. c #DFC3A0", -"~. c #DDCAAF", -"^. c #CFC7BD", -"/. c #D2CBB6", -"(. c #DBC8B1", -"). c #DBCDBB", -"_. c #E2C6A4", -"`. c #E6C8A5", -"'. c #EACBA5", -"]. c #E1C7A8", -"[. c #E3CBAD", -"{. c #EACCAA", -"}. c #EED1AC", -"|. c #E1CDB3", -" X c #E3CFB8", -".X c #E6D1B6", -"XX c #EBD2B3", -"oX c #E3D1BB", -"OX c #EAD6BB", -"+X c #EBD8BF", -"@X c #D3CDC2", -"#X c #D8CDC2", -"$X c #D0CECA", -"%X c #DDD3C4", -"&X c #D3D2CC", -"*X c #DDD5CB", -"=X c #CCD3D5", -"-X c #C9D7DF", -";X c #D2D4D6", -":X c #DEDAD4", -">X c #DDDCDB", -",X c #E2D4C2", -".N b b b b N >.( C > HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX4 L _ *.@.<.$.X.X...X.X.X.X.X.X...X.@.$.<.@.*./ G , HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX< L -.@.$.X...R R R T T T T W W W W W W T T T T R R W ..X.$.@.*.J HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD -.%.X.W R T T W W W W W W W W W W W W W W W W W W W W W W T T R W X.%.+.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS -.$.X.R T T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T T R X.$.-.C HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXF <.@.f R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R W #.<.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX[ <.X.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W T R X.$.K HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0.$...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W W W W W W W T R ..%.G HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXS 1...R T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ E W W W W W W W W W T R X.1.A HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.d T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ E W W W W W W W W W W T R @.2.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX7.5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W T W %.z HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3.X.s T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W T R $.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1...R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W R ..1.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX0 5.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T W 5.8 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX8.$.s W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W T R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.#.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R $.&.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXp.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W R @.<.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXi.X.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ E ~ W R ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W R @.| HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX] #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ! s e t d ~ ` ` ` ` ` ` =.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R %.N HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXq %.R W W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E W E ~ ~ ~ ~ y l.=XI.x.) p a =.` ` =.=.=.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %.2 HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5 5.d W W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t (.jXVXNXuX@XF.W ` =.:.` W =.:.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX1.f T W W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ R Q eXDXSXSXDXgX#Xa ` =.=.;.q.W a a R ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX3...T W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ` a a.NXSXGXGXAXNXV.a :.:.f c.tX*XE.n.9.R ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T @.@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXD #.R W W W W W W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t H.VXSXGXGXDXmXy.f :.:.a I.hXBXCXNXiX^.' W ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.g HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX5.d W W W W W W W W W W W W W W W W W W W W W W W W W E ~ W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` i |.CXGXGXGXCX3X~ ` :.:.R %XCXSXGXAXNX>XW ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W R 5.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX2.W T W W W W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ s t e a W ~ ` ` ` ` ` ` W ! eXFXGXGXSXVX[.d :.:.~ w.uXFXGXGXSXVXW.a ` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T ..@.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX9 $.R W W W W W W W W W W W W W W W W W W W W W W E W ~ ~ ~ y F./.B.9.T t t a ~ =.` =.a a.hXDXGXGXSXNXA.d :.e.R v.NXSXGXGXSXNXm.a =.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W R %.= HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX6.d W W W W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ W i &XjXNXfX:X].B.q.T t a d e K.VXSXGXGXDXaXd.W e.e.d E.VXSXGXGXDXvXw.W =.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W W %.HXHXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHXK X.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ a ) uXDXSXFXFXCXNXfX:X_.B.q.r .XFXGXGXGXCX3X=.=.e.,.~ %XCXGXGXGXCX1XW ` =.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W T $.m HXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHXHX5.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ~ ~ t x.NXSXGXGXGXSXSXDXFXCXNXmX8XcXSXGXGXGXCXW.e :.e.=.t.uXFXGXGXSXVXE.d :.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHX^ X.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ` t T.VXSXGXGXGXGXGXGXGXSXSXFXGXGXGXGXGXGXFX}.9.' W e v.VXSXGXGXSXNXm.d :.=.=.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W W T @.P HXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ s ;XNXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXNX>X|.V.XXFXGXGXGXFXbXy.~ :.:.=.=.` ` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHXH X.T W W W W W W W W W W W W W W E E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` R ' $XsXNXVXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXCXCXFXSXGXGXGXCXOXa :.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W W T $.c HXHXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXHX1.R W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` ~ t.V.`.5XVXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXSXCX{.e.P.'.2XvXNXBXDXSXGXGXGXGXGXGXGXGXGXSXDXjX~.y W =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX: 1.R W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.~ s.fXDXGXGXGXGXGXGXGXSXNXD.f =.=.,.M.L.oXaXVXDXSXGXGXGXGXGXGXGXGXGXAXVX(.t ~ ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W R %. HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXl #.T W W W E ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.:.:.:.:.:.:.:.:.:.e.e.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXzXg.r.f.f.f.r.=.=.g.`.fXBXAXGXGXGXGXGXGXGXGXGXAXjXH.t =.` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W T $.6 HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX~ ..W W W W E ~ ~ ~ ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX1X,.f.f.f.f.h.h.f.,.~ d.3XVXAXGXGXGXGXGXGXGXGXGXDXsX' f ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W ..~ HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX$.R W W W W W E ~ ~ ~ ~ ~ ` ` ` ` ` ` =.=.=.=.=.=.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.,.w.>XFXGXGXGXGXGXGXGXSXNX`.=.f.h.h.h.h.f.f.f.f.=.~ ,XVXSXGXGXGXGXGXGXGXGXSXVXT.y ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W R $.HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXX %.T W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.e.r.r.r.u.=.x.fXDXGXGXGXGXGXGXGXSXmXA.,.h.h.h.k.k.h.f.f.f.f.:.~ 5XFXGXGXGXGXGXGXGXGXGXCX:XW ~ ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W W T $.. HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX8 $.T W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.:.:.:.e.e.e.e.e.r.r.r.r.r.u.u.~ K.NXSXGXGXGXGXGXGXGXDXzXj.r.k.k.k.k.k.h.f.f.f.f.f.W V.VXSXGXGXGXGXGXGXGXGXDXuXw.f ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W T $.3 HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXY ..W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.:.e.e.e.e.e.e.r.r.r.r.u.u.u.u.~ |.CXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.f.f.f.f.,.d.bXFXGXGXGXGXGXGXGXGXDXfXd.d =.` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W O.P HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXO.W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.e.r.r.r.r.r.r.u.u.u.u.r.w.>XFXGXGXGXGXGXGXGXSXNX'.,.k.k.k.k.k.k.k.h.h.f.f.f.e.y.kXFXGXGXGXGXGXGXGXGXDXfXg.d =.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W W W W W O.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX$.R W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.=.:.:.:.:.e.e.r.r.r.r.u.u.u.u.u.u.f.=.b.fXDXGXGXGXGXGXGXGXSXmXJ.r.k.k.k.k.k.k.k.h.h.f.f.f.:.s.mXFXGXGXGXGXGXGXGXGXDXpXy.R =.` ` ` ~ ~ ~ ~ ~ E E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX1.R W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXFXxXM.u.k.k.k.k.k.k.k.k.h.f.f.k.~ K.VXSXGXGXGXGXGXGXGXGXCX5X=.~ =.=.` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX+ $.T W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.f.f.=.|.CXGXGXGXGXGXGXGXGXFXXFXGXGXGXGXGXGXGXGXFX9XA.b.u.r.r.u.u.h.h.h.u.r.O.w.:XCXSXGXGXGXGXGXGXGXGXSXhXL.a :.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.* HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXV X.T W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.u.u.f.,.b.fXFXGXGXGXGXGXGXGXGXSXFXVXpX*X[.R.V.M.g.d.d.g.b.T.pXCXSXGXGXGXGXGXGXGXGXGXDXpXe.~ :.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W W T $.; HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX| O.T W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.u.u.u.u.f.=.K.NXSXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXmXuX>X3X3XyXmXVXFXSXGXGXGXGXGXGXGXGXGXAXhXE.d :.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.:.:.:.:.:.e.e.e.r.r.u.u.u.u.=.|.BXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXSXFXFXFXFXFXSXSXGXGXGXGXGXGXGXGXGXGXAXNX>X~ =.e.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.e.e.e.r.r.r.u.u.r.w.>XFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXZXNXeXe.~ e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.r.u.u.=.x.fXFXGXGXGXGXGXGXGXGXGXFXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFXCXfXoX:.~ r.e.:.:.:.:.:.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXc @.T W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.:.e.e.r.r.r.u.~ K.NXSXGXGXGXGXGXGXGXSXZX6XkXmXNXBXDXAXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGX0X'.S.~ =.u.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W W W @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.e.e.r.r.u.~ |.CXGXGXGXGXGXGXGXGXFX4X,.k.D.Q.,XkXmXNXDXSXSXGXGXGXGXGXGXGXGXGXGXGXXFXGXGXGXGXGXGXGXSXVX{.,.f.u.r.u.N.J.{.5XNXBXAXSXGXGXGXGXGXGXGXGXGXFXMXH.W r.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W W T @.h HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXo.O.T W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.e.r.O.s.fXFXGXGXGXGXGXGXGXSXmXJ.r.N.N.N.N.h.r.r.f.J.1XhXBXAXGXGXGXGXGXGXGXGXSXDXjX!.W e.u.r.e.e.e.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W W W W T @.g HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXB X.T W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` ` =.=.:.:.:.:.:.e.e.r.W H.NXSXGXGXGXGXGXGXGXDXuXM.u.k.k.N.N.N.N.N.h.,.e.D.>XNXSXGXGXGXGXGXGXGXGXSXZXjXE.W r.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W W T $.- HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXl @.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` =.=.=.:.:.:.:.e.e.r.W |.CXGXGXGXGXGXGXGXGXBX2Xr.h.k.k.k.k.k.k.k.k.k.h.,.,.|.NXZXGXGXGXGXGXGXGXGXGXZXgXV.~ u.e.e.e.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.% HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHX@ $.T W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.:.' >XFXGXGXGXGXGXGXGXSXNX{.,.k.k.k.k.k.k.k.k.k.k.k.k.u.~ `.NXSXGXGXGXGXGXGXGXGXSXCX>X=.e.r.r.e.e.:.:.:.:.:.=.=.` ` ` ~ ~ ~ ~ ~ ~ W W W W W W W W W T $.. HXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ` ` ` ` =.=.:.:.:.:.e.~ s.fXFXGXGXGXGXGXGXGXSXNXJ.,.k.k.k.k.k.k.k.k.k.k.h.h.k.u.O.2XCXGXGXGXGXGXGXGXGXGXAXhXV.~ u.r.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ W W W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W E ~ ~ ~ ~ ~ ~ ` ` ` ` ~ :.:.:.:.e.f Z.VXSXGXGXGXGXGXGXGXDXzXM.r.k.k.k.k.k.k.k.h.h.h.h.f.f.k.=.V.NXSXGXGXGXGXGXGXGXGXSXVX`.W r.e.e.e.e.:.:.:.:.=.=.=.` ` ` ~ ~ ~ ~ ~ ~ E W W W W W W W W $.HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXO.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` ` =.~ Q a a W =.=.t XCXGXGXGXGXGXGXGXGXBX2Xr.f.k.k.k.k.k.k.h.h.h.h.f.f.f.f.r.y.kXFXGXGXGXGXGXGXGXGXGXBX,X~ :.e.e.e.:.:.:.:.:.:.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W W ~ ..HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXI O.W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ` a z.-X_.B.q.! u C.NXSXGXGXGXGXGXGXGXSXNX'.=.h.h.k.k.k.h.h.f.f.f.f.f.f.f.f.r.w.5XFXGXGXGXGXGXGXGXGXGXCX2X=.:.e.:.:.:.:.:.:.:.:.=.=.=.` ` ` ` ~ ~ ~ ~ ~ E W W W W W W O.P HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXk @.T W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ~ ~ t ).jXVXNXaX2X1XBXDXSXGXGXGXGXGXGXGXSXmXA.:.h.h.h.h.h.f.f.f.f.f.f.f.f.f.f.,.d.vXFXGXGXGXGXGXGXGXGXGXCX1X` =.:.:.:.:.:.:.=.=.=.=.=.=.` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W T $.; HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXo %.T W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ` y q.fXZXSXSXFXFXFXSXSXGXGXGXGXGXGXGXGXFXxXj.r.f.h.h.h.f.f.f.f.f.f.f.f.u.u.f.W B.NXSXGXGXGXGXGXGXGXGXSXBXoXW :.:.:.:.:.:.=.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ W W W W W W %. HXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX$.R W W W W W W W W W W W W W W W W W W W E ~ ~ ~ ` e !.CXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX+Xd ,.f.h.h.h.f.f.f.f.f.f.u.u.u.f.,.T :XFXGXGXGXGXGXGXGXGXGXSXNXE.f :.:.:.:.:.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W R $.HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX~ ..W W W W W W W W W W W W W W W W W W W W E ~ ~ a _ aXFXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXFX7XV.s.:.=.:.,.u.f.f.f.f.u.u.u.r.~ s ~.VXSXGXGXGXGXGXGXGXGXGXAXhXV.d :.:.=.=.=.=.=.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W O.E HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXg $.T W W W W W W W W W W W W W W W W W W W E ~ ~ e G.hXAXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXVXpX*X_.Z.x.t.:.` ~ ~ ~ ~ ~ ' x.*XVXSXGXGXGXGXGXGXGXGXGXGXDXuXw.W :.=.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W T $.; HXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHX %.R W W W W W W W W W W W W W W W W W W W W ~ d T qXgXBXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXFXFXBXNXaX>X,X[._.T.T.E.|.:XNXCXSXGXGXGXGXGXGXGXGXGXGXSXVX Xd =.=.=.=.` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W R %.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHX@.W W W W W W W W W W W W W W W W W W W W W ~ R ` s.H.oXkXNXNXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXSXDXFXCXCXBXVXVXBXCXFXSXSXGXGXGXGXGXGXGXGXGXGXGXAXhXm.a :.` =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ W W W W W W W W W W @.HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXx @.T W W W W W W W W W W W W W W W W W W W W ~ ~ y t a _ g.L.oXkXhXVXCXFXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXGXSXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXSXBX:Xf ~ ` ` ` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ E W W W W W W W W W T $.h HXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHX%.R W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ d a t a ' s.R.oXnXDXSXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXGXZXhXg.y =.` ` ` ` ` ~ ~ ~ ~ ~ ~ ~ ~ ~ E ~ E W W W W W W W W W W R %.HXHXHXHXHXHXHXHXHXHXHX", -"HXHXHXHXHXHXHXHXHXHXHXO.~ W W W W W W W W W W W W W W W W W W W W W ~ ~ ~ ~ ~ ` ` ~ W a a d ! c #DF943B", -", c #D8913C", -"< c #D8923E", -"1 c #DF953E", -"2 c #E28B23", -"3 c #E38B23", -"4 c #EA9023", -"5 c #EB9023", -"6 c #ED9122", -"7 c #ED9123", -"8 c #EE9123", -"9 c #EE9223", -"0 c #F39421", -"q c #F19423", -"w c #F39523", -"e c #F79521", -"r c #F59422", -"t c #F49623", -"y c #F69622", -"u c #F79623", -"i c #F09324", -"p c #F19424", -"a c #F19525", -"s c #F49624", -"d c #F59625", -"f c #F49725", -"g c #F79624", -"h c #F79724", -"j c #F69725", -"k c #F79725", -"l c #F69726", -"z c #F79726", -"x c #F89621", -"c c #F89722", -"v c #F89723", -"b c #F89724", -"n c #F89824", -"m c #F89825", -"M c #F99825", -"N c #F89925", -"B c #F89926", -"V c #F89927", -"C c #F99927", -"Z c #F0972E", -"A c #F7992A", -"S c #F79A2B", -"D c #F79B2C", -"F c #F69A2D", -"G c #F79D2F", -"H c #F89929", -"J c #F89A28", -"K c #F89A29", -"L c #F99A29", -"P c #F99B29", -"I c #F89A2A", -"U c #F89A2B", -"Y c #F99B2B", -"T c #F89B2C", -"R c #F89C2C", -"E c #F99C2D", -"W c #F99C2E", -"Q c #F89D2E", -"! c #F99D2F", -"~ c #E29335", -"^ c #E49639", -"/ c #E2983F", -"( c #F79F35", -") c #F99E31", -"_ c #F89E32", -"` c #F99E32", -"' c #F9A033", -"] c #F9A035", -"[ c #F9A135", -"{ c #F9A036", -"} c #F9A136", -"| c #F9A137", -" . c #F3A03F", -".. c #F7A43F", -"X. c #F8A139", -"o. c #F9A23A", -"O. c #FAA33B", -"+. c #FAA43E", -"@. c #FAA43F", -"#. c #EF9F41", -"$. c #EEA244", -"%. c #ECA34B", -"&. c #F8A440", -"*. c #F9A541", -"=. c #F9A644", -"-. c #F9A947", -";. c #F0A349", -":. c #F5A648", -">. c #F1A74E", -",. c #F7AA4F", -"<. c #E4A458", -"1. c #E4A55B", -"2. c #E8A95E", -"3. c #F2A950", -"4. c #F4AA52", -"5. c #FBAF55", -"6. c #E4A860", -"7. c #EAAC63", -"8. c #EBAF68", -"9. c #F2AF61", -"0. c #EBB16C", -"q. c #F6B568", -"w. c #E3AF71", -"e. c #EBBE89", -"r. c #E0BC93", -"t. c #E3C199", -"y. c #E6C59D", -"u. c #EAC89E", -"i. c #E7C8A2", -"p. c #EACBA6", -"a. c #EBCFAF", -"s. c #F1CCA0", -"d. c #E7CEB1", -"f. c #ECD1B0", -"g. c #E5D2BB", -"h. c #E8D2B8", -"j. c #DFDFDF", -"k. c #E7D5C1", -"l. c #E7D7C4", -"z. c #E5D7C7", -"x. c #E7DACB", -"c. c #EADAC8", -"v. c #E9DCCC", -"b. c #EDDFCE", -"n. c #E5DDD3", -"m. c #E4DFD9", -"M. c #ECE0D1", -"N. c #E4E1DD", -"B. c #EDE3D8", -"V. c #EAE4DD", -"C. c #ECE5DC", -"Z. c #E2E2E2", -"A. c #E5E2E0", -"S. c #E4E4E4", -"D. c #E7E7E7", -"F. c #EAEAE9", -"G. c gray92", -"H. c #EEEEEE", -"J. c None", -/* pixels */ -"J.J.J.J.J.J.J.1 > J.J.J.J.J.J.J.", -"J.J.J.J.J./ ..| ' ( ~ J.J.J.J.J.", -"J.J.J.< *.{ V $ r U W _ - J.J.J.", -"J.J., o.J 0 # <.w.$.F N H % J.J.", -"J.J.o.T e 1.r.k.x.t.S z B u J.J.", -"J.^ [ Y ! #.z.H.M.n.0.d n m 2 J.", -"J.X.) | =. .h.B.5.f.j.;.v B d J.", -": Q M ` &.>.A.V.p.c.l.4.E n d = ", -"; I b A Z 2.D.s.u.F.a.-.} C w & ", -"J.l g y 6.m.G.q.3.b.Z.,.] D 8 J.", -"J.3 k c %.d.C.v.N.S.y.@.L a * J.", -"J.J.j z x 8.i.g.e.9.+.W t 6 J.J.", -"J.J.+ s h G :.7.O.R B s 7 . J.J.", -"J.J.J.O i f P L K d p 5 J.J.J.", -"J.J.J.J.J.@ 9 q i 4 + J.J.J.J.J.", -"J.J.J.J.J.J.J.X o J.J.J.J.J.J.J." -}; diff --git a/share/pixmaps/bitcoin256.png b/share/pixmaps/bitcoin256.png deleted file mode 100644 index 1d42116ef..000000000 Binary files a/share/pixmaps/bitcoin256.png and /dev/null differ diff --git a/share/pixmaps/bitcoin256.xpm b/share/pixmaps/bitcoin256.xpm deleted file mode 100644 index 87bb35cda..000000000 --- a/share/pixmaps/bitcoin256.xpm +++ /dev/null @@ -1,465 +0,0 @@ -/* XPM */ -static char *bitcoin___[] = { -/* columns rows colors chars-per-pixel */ -"256 256 203 2", -" c #BE741B", -". c #C1761B", -"X c #C6791C", -"o c #CC7C1D", -"O c #D07F1D", -"+ c #C67B21", -"@ c #CC7E21", -"# c #D4821E", -"$ c #D9841F", -"% c #ED8E1D", -"& c #EF911F", -"* c #CF8022", -"= c #D48323", -"- c #DB8621", -"; c #DD8922", -": c #D58729", -"> c #D6882B", -", c #DE8C2A", -"< c #CE8C3C", -"1 c #D28934", -"2 c #D98E32", -"3 c #D28E3C", -"4 c #DF9132", -"5 c #D6903E", -"6 c #DD933B", -"7 c #E58C22", -"8 c #E98F23", -"9 c #E38F2B", -"0 c #E88F28", -"q c #ED9124", -"w c #E6922D", -"e c #EB942B", -"r c #EF982F", -"t c #F59624", -"y c #F89723", -"u c #F79826", -"i c #F89825", -"p c #F1972A", -"a c #F59A2C", -"s c #F89B2B", -"d c #E59534", -"f c #EA9632", -"g c #EE9933", -"h c #E3963B", -"j c #E6993D", -"k c #EC9C3B", -"l c #F49C33", -"z c #F99E32", -"x c #F29E3A", -"c c #F7A037", -"v c #F9A036", -"b c #F5A13C", -"n c #F9A33B", -"m c #CE9147", -"M c #D29245", -"N c #DC9641", -"B c #DD9846", -"V c #D2954B", -"C c #DC9A4B", -"Z c #E59C44", -"A c #EA9E43", -"S c #E39E4B", -"D c #E89F49", -"F c #F09F40", -"G c #EDA145", -"H c #E6A14D", -"J c #EBA34B", -"K c #F4A443", -"L c #F9A642", -"P c #F7A847", -"I c #FAA846", -"U c #F3A64A", -"Y c #F8A748", -"T c #F5A94D", -"R c #FAAA4B", -"E c #E6A454", -"W c #EBA552", -"Q c #EDA856", -"! c #E4A55B", -"~ c #E8A75B", -"^ c #E7A95E", -"/ c #EBA95B", -"( c #F0A751", -") c #F4AB53", -"_ c #FAAE53", -"` c #F4AE5A", -"' c #F8AF59", -"] c #FAB057", -"[ c #F6B15E", -"{ c #FAB25B", -"} c #DFAD6F", -"| c #DCAE77", -" . c #DFB27D", -".. c #E5AA64", -"X. c #E8AB61", -"o. c #E5AE6C", -"O. c #E6B06F", -"+. c #ECB16C", -"@. c #F5B365", -"#. c #FBB562", -"$. c #FBB867", -"%. c #F5B66B", -"&. c #FAB768", -"*. c #F4B86F", -"=. c #FBB96A", -"-. c #E1AE71", -";. c #E5B174", -":. c #EBB573", -">. c #EFB977", -",. c #E5B47A", -"<. c #EEBA7B", -"1. c #F3B770", -"2. c #F3B974", -"3. c #FBBC72", -"4. c #F3BC7B", -"5. c #F8BF7A", -"6. c #FAC079", -"7. c #DCB382", -"8. c #DFBB8F", -"9. c #DABB96", -"0. c #DBBD99", -"q. c #E2B682", -"w. c #E4B985", -"e. c #ECBD84", -"r. c #E3BB8B", -"t. c #EABF8C", -"y. c #F1BE83", -"u. c #E2BE92", -"i. c #D3BDA2", -"p. c #DEC09C", -"a. c #EEC28D", -"s. c #F4C286", -"d. c #F8C282", -"f. c #F3C48B", -"g. c #E7C297", -"h. c #ECC393", -"j. c #E2C29D", -"k. c #EAC69B", -"l. c #ECC89F", -"z. c #F1C694", -"x. c #F2C897", -"c. c #F1CA9B", -"v. c #DBC2A3", -"b. c #D6C2AB", -"n. c #DDC7AD", -"m. c #DEC9AF", -"M. c #D3C4B3", -"N. c #DDCAB3", -"B. c #D2C7B9", -"V. c #D6C9BA", -"C. c #DDCEBB", -"Z. c #DFD0BE", -"A. c #E2C5A2", -"S. c #E8C7A0", -"D. c #E6C9A5", -"F. c #EBCBA4", -"G. c #E2C7A8", -"H. c #E3CAAC", -"J. c #EBCDA9", -"K. c #EFD2AF", -"L. c #F3D1A7", -"P. c #F1D1A9", -"I. c #E4CEB3", -"U. c #E8CFB1", -"Y. c #E1CFBA", -"T. c #E6D0B6", -"R. c #E9D1B4", -"E. c #E4D2BC", -"W. c #EAD4BA", -"Q. c #F4D5B0", -"!. c #F4D9B9", -"~. c #CDCDCD", -"^. c #D5CCC3", -"/. c #D4CFCA", -"(. c #DED2C3", -"). c #D3D1CE", -"_. c #DED6CC", -"`. c #D5D5D5", -"'. c #DBD7D1", -"]. c #DEDAD4", -"[. c #DDDDDC", -"{. c #E3D5C3", -"}. c #E9D7C1", -"|. c #EBD9C4", -" X c #E1D6CA", -".X c #E3D9CD", -"XX c #EADDCD", -"oX c #E1DBD4", -"OX c #E8DFD4", -"+X c #E1DEDB", -"@X c #EDE3D7", -"#X c #E3E1DE", -"$X c #E8E3DC", -"%X c #F6E5D2", -"&X c #F4EBDF", -"*X c #E4E4E4", -"=X c #ECE7E2", -"-X c #EDE9E4", -";X c #ECECEC", -":X c #F0EBE7", -">X c #F4F4F4", -",X c #FEFEFE", -"X>X>X>X;X;X*X[.`.r.n n z v v v v c x l p l x x c c v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X>X>X>X>X>X;X*X[.`.@.n n v v v v v c g E | S k f r l l l z z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i e X>X,X,X,X,X>X>X;X*X_.R n v v v v v v x e 0.`.`.V.p.;.H f e e p l l z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y , X>X,X,X,X,X>X>X;X*XI.L n v v v v n n x g V.`.[.[.[.[.[.(.p.;.S f r l z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u u y X,X,X,X,X,X>X>X;X*Xa.n n v v v n n n l A `.[.*X*X-X-X*X*X*X[.`.V.9.K z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X,X,X,X,X,X>X>X-X[.%.n n n n n n n b p o.[.*X;X;X;X>X;X;X*X*X[.`.~.T z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y 0 X>X,X,X,X,X,X>X;X*XoXR L n n n n n n b g u.*X-X;X>X>X>X>X>X;X*X*X[.N.L n z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y X>X,X,X,X,X>X>X;X*XI.L L n n n n n n b g C.*X;X>X>X,X,X,X>X>X;X*X[.g.L n z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X,X,X,X,X,X>X>X;X*Xh.L L n n n n n n l G [.*X;X>X,X,X,X,X>X>X;X*X[.2.n n z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y w X,X,X,X,X,X>X>X-X[.%.L n n n n n n b l o.*X;X>X>X,X,X,X,X,X>X;X*X]._ n v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y X>X,X,X,X,X,X>X;X*XoXR L n n n n n n b g j.*X;X>X>X,X,X,X,X,X>X;X*XE.I n v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y t X>X,X,X,X,X>X>X;X*XT.I L n n n n n n b k Z.*X;X>X,X,X,X,X,X>X>X;X*Xl.L n v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y ; X,X,X,X,X,X>X>X;X*Xh.L L n n n n L L x G [.*X;X>X,X,X,X,X,X>X>X;X*X4.n n v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u i u X>X,X,X,X,X,X>X>X-X[.%.L L n n n L L L l ;.*X;X>X>X,X,X,X,X,X>X;X*X[._ L n v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y q X>X>X>X;X;X;X;X*X*X*X*X].N.q.! d e e r p q ,.-X;X>X>X,X,X,X,X,X>X;X*XoX_ I L n L L L L K g j.*X;X>X>X,X,X,X,X,X>X;X*XE.Y L n v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X>X>X>X>X>X>X;X;X;X;X*X*X*X*X_.I.r.o.Z w D.;X>X>X,X,X,X,X,X,X>X;X*XW.R I L L L L L L K k Y.*X;X>X,X,X,X,X,X>X>X;X*Xl.L L n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y q X>X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X*X*X*X*X$X}.=X>X>X>X,X,X,X,X,X,X>X;X*Xx.I I L L L L L L x J [.*X;X>X,X,X,X,X,X>X>X;X*X4.L n n v v v v v z z z z z z s s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X>X>X;X&.L L L L L L L L x ;.*X;X>X>X,X,X,X,X,X>X;X*X[.' L n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u y t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X>X>X@Xb l x x K L L L L k j.*X;X>X>X,X,X,X,X,X>X;X*XE.R L n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X:XW.g.;.H k k k b F k {.;X>X>X,X,X,X,X,X>X>X;X*XS.I L n n n n v v v v v z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X+XE.j.,.~ j A =X;X>X>X,X,X,X,X,X>X>X;X*X4.I L n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X;X*X*X*X*XXX}.;X>X>X,X,X,X,X,X,X>X>X;X#X{ I n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X;X>X>X>X,X,X,X,X,X,X,X>X>X;X|.R I n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X>X>X;XF.L L n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X,X,X,X,X,X,X,X,X,X,X,X>X>X;X@.a x b b n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.e.G g l c b n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X+XG...k g l b n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X*X(.w.A g l c c v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X*X'.u.A r l x c v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X*X].u.k r l c v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X*X_.q.g p l z v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X[.C.W p l c v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X*X*X[.w.r a l z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X-X-X-X*X*X-X;X;X;X;X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X[.H.g a z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xf.3.x.R..X+X*X*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*X(.k p z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i y t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X$.{ { { $.3.f.F.{.[.*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X_.W p z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t @ X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X|.{ ] _ ] { { { { $.3.h.R..X*X*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X'.k p z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 0 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ._ ] _ _ _ _ ] { { { #.$.$.f.T.oX*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X_.l a z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs._ _ _ _ _ _ _ _ _ ] { { { { { =.l..X*X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XH.t z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X+X&.] _ _ _ _ _ _ _ _ _ _ _ _ ] { { { #.k.oX*X-X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.:.t z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.{ { _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ] _ { J.*X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X'.l s z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XF.{ { _ _ _ _ _ _ _ _ ] _ _ _ _ _ _ _ _ _ _ _ y.oX*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.t.u z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ ] _ _ _ _ _ ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ ' .X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X'.z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X].&.{ ] _ _ _ ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ R R oX*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.:.u z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ _ _ _ _ ] ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ I @.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.s z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XF.{ { _ ' ] ] ] ] ] { { { ] ] ] _ _ _ _ _ _ _ _ R R _ n k.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_.n z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ { ] ] ] ] { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R R I T +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.T z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ { ] ] ] { { { { { { { ] ] ] _ _ _ _ _ _ _ _ _ R R R K D.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.%.z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ ] ] { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R R K e.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.<.v v z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ _ R R K +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X<.n v v z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.#.{ { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ _ R U / *X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xe.n n v v z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t t X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.#.{ { { { { { { { { { { { { { ] ] ] ' _ _ _ _ _ _ _ _ R K +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X<.n n v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ T K ,.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.>.n n v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t @ X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { { { { { { { { { { { { ] ] ] ] _ _ _ _ _ _ _ T G j.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.%.n n v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.{ { { { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ _ _ T J X-X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X]._ L n v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X#X3.#.{ { { { { { { { { { { { { { { { { { ] ] ] _ _ _ _ _ ) G ..*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X{.R L n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.=.#.{ { { { { { { { { { { { { { { { { { { ] ] ' _ _ _ _ T k E.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XH.L L n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xc.] { { { { { { { { #.{ { { { { { { { { { { ] ] ] _ _ _ ( A w.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.a.L n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xx.( Q ( ) ` [ [ { #.#.#.{ { { { { { { { { { { ] ] _ ) T D o.*X;X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.[ L n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XOXI.u.O./ Q Q ` ` [ [ [ { { { { { { { { { ] ' ) ( J H r.*X-X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.R I n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X*X_.H.r.;.X./ Q Q ) ) ` ` ` ` ` ) ) ( J H W ,.{.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.y.I L n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X*X*X*X*X].(.H.u.q.;.^ ^ ~ ~ E E ~ o.r.G. X*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_._ Y L n n n n n v v v z z z z z z z s s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i u t @ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X;X;X*X*X*X*X*X*X[.]..X X XoX+X*X*X*X-X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.f.R I n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X;X;X-X-X*X*X*X-X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X;X*X X_ R L n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X;X;X;X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.%.R I L n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i t - X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X[.k.R R L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X*X[.l.] _ I L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X[.l.{ _ Y L L L n n n n n n n n v v v v v v z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*X].h.{ _ R L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X;X*X[.T.3.{ ] R I L L L L L n n n n n n n n n v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X;X;X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*XW.s.#.{ _ R I I L L L L L L n n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X-XQ.|.OX*X*X*X*X*X;X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X&X!.L.d.#.{ ] R R I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XXX3.3.3.s.c.R..X[.*X*X*X-X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X%X{ L R _ _ R R R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-XK.&.=.=.&.=.3.3.d.c.R..X[.*X*X*X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;XJ.J K Y R R Y I I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.$.#.#.#.#.&.&.=.=.3.3.f.F.}.+X*X*X*X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;XOX:.K U R R I I I I I L L L L L L n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i i i i t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X+X3.$.#.{ { #.#.#.#.$.$.&.=.=.3.6.c.W.+X*X*X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*Xj.K K R R I I I I I L L L L L n n n n n n n n v v v v v v z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i i i i i i i i i i i i u t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.&.#.{ { { { #.#.#.#.#.#.#.#.$.$.=.=.5.J..X*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XH.K K R R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i i i i i i i u t = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { #.#.#.#.#.#.#.#.{ #.#.$.$.$.=.z.{.*X*X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X*X*XC.U K R I I I I I L L L L L L n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i i u q * s u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u u u u s s s s s s s s s s s z z z z z z z v v v v v n n n n n n n n L L L L L L I I K A Z.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.#.{ { { { { #.#.#.#.{ { { { { { { #.#.#.#.$.z.{.*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X*XC.b K Y I I I I L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i u q + X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.3.#.{ { { { { { #.#.#.{ { { { { { { { { { { #.#.#.$.F.+X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.H.b P I I I I I L L L L L n n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { { { { { { { { { #.{ 2.{.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.e.b Y I I I I L L L L L L n n n n n n n n v v v v z z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.#.#.{ { { { { { { { { { { { { { { { { { { { { { { { { { { U.*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X].T L Y I I I I L L L L L L n n n n n n n n v v v v v z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.#.{ { { { { { { { { { { { { { { { { { { { { { { { { ] { { _ R.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X*XD.L R I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.#.{ { { { { { { { { { { { { { { { { { { { { { ] ] ] ] ] { ' R T.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.` L I I I I I L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.$.#.{ { { { { { { { { { { { { { { { { { { { ] ] ] ] ] ] ] _ ] _ R oX*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.g.n I Y I I I I L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { { { { { { { { { { { { { { { { { { { { ] ] ] ] ] _ _ _ _ _ ] Y <.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X(.I I I I I I L L L L L L L n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i u t ; X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.{ { { { { { { { { { { { { { { { { { { ] ] ] ] ] ] _ _ _ _ _ _ _ _ T .X-X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.[ L I I I L L L L L L L L n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s u u u u u i i i i i i i i i i i i i i u q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ { ] { { { { { { { { { { { { { { ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ P g.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.e.n I L L L L L L L L L L n n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ ] ] { { { { { { { { { { { ] ] ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ Y +.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xg.L I L L L L L L L L L n n n n n n n n n n n v v v v z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { ] ] ] { { { { { { { { { ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ T Q #X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.I I L L L L L L L n n n n n n n n n n n n n v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xf.{ { ] ] ] ] { { { { { { { ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Y W +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XI.I I L L L L L n n n n n n n n n n n n n n n v v v v v v z z z z z z z s s s s s s s s s s u u u u u i i i i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.=.{ ] ] ] ] ] { { { { { ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R T W +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.I L L L L n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z s s s s s s s s s s s u u u u i i i i i i i i i i i u q ; X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X{.#.{ _ _ ] ] ] ] { ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R K X.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XE.I L n n n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z s s s s s s s s s s s s u u u i i i i i i i i i i i t q @ X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.{ { _ _ _ ] ] ] ] ] ] ] ] ' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R x q.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XD.R L n n n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i t q X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xs.{ ] _ _ _ ] ] ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R T k G.*X;X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XS.I L n n n n n n n n n n n n n v v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s u u u u i i i i i i i i i t q X>X>X,X,X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X#X&.{ _ _ _ _ _ ] ] ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R K A oX;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*Xh.L L n n n n n n n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s u u u i i i i i i i i i t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X|.{ ] _ _ _ _ _ ] ] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R U k u.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-X[.2.L L n n n n n n n n n v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s u u u u i i i i i i i u q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xc.R _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R R T k D +X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.' L n n n n n n n n v v v v v v v z v v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s u u u u i i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;Xf.K G G U ) ) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ R R R R R R R R R R R U A j {.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X{.R L n n n n n n v v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u i i i i i i t q X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X-XXXH.w.X.J J J T ) ) ) _ _ _ _ _ _ _ _ R R R R R R R R R R R Y K k D Y.*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XJ.L L n n n n v v v v v v v v z z z z z z z z z z z z z s z s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i u t 7 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X#X(.A.q...H J J U U T T T T R R R R R R R R R Y Y U K k A ;..X*X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X[.4.L n n n v v v v v v v v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i t q * X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X;X;X*X*X*X[.(.H.u.,.^ J D G A J K K U U U U K k k k A E w.Y.*X*X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X]._ L n v v v v v v v v v v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i t q X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X;X;X;X-X*X*X*X*X[._.N.A.u.;.;...E E E E ..;.q.j.I.+X*X*X;X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*XH.I L n v v v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i t 8 X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X;X;X;X;X-X*X*X*X*X*X*X*X+X+X+X+X*X*X*X*X*X;X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.1.L n v v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i u q ; X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X XR L n v v v v v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i t q X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X-X[.a.L n v v v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i t 8 X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X]._ L n v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i u q ; X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X;X*X[.a.L n v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X_.R L n z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.2.L n z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u s u u u u u u u u i i i i i i i i i i i i i i i i i i t q = X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X*X[.D.L L v z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X XR L n z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X,X,X,X>X>X>X>X;X;X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X;X-X*X'._ I n z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u i u u i i i i i i i i i i i i i i i i i i i i i i t q o X>X,X,X,X,X,X,X>X>X>X=X;X-X-X-X;X;X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X;X-X*X].%.L L z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X,X>X>X;X=X=.5.c.W.oX*X*X-X;X>X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X*X*X_.%.I L z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X,X,X,X,X,X>X>X;X|._ _ _ { #.4.l.}.$X;X>X>X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X;X;X*X[.E.{ I L v z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i u i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X>X;X*XF.R R R R _ _ { { { 4.-X>X>X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X>X>X>X>X,X,X,X,X,X,X,X,X,X,X,X>X>X>X>X>X>X>X;X;X*X*X[.k._ I n z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X,X,X,X,X,X>X>X;X*X4.R I I I I R R R b U -X>X>X,X,X,X,X,X,X,X,X>X>X>X>X>X;X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X;X;X;X-X*X*X[.T.*.R L n z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q X>X,X,X,X,X,X>X;X*X+X] R I L I I I I P x t.;X>X>X,X,X,X,X,X,X,X>X>X;X;X;X;X-X-X-X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X;X*X*X*X[.].U.4.R I L v z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X>X>X;X*XE.R Y L L I I I I K k I.-X;X>X,X,X,X,X,X,X>X>X;X|.f.J.W..X[.[.*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X[._.I.h.#.R L L n z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q . X,X,X,X,X,X>X>X;X*Xl.I I L L L I I P K A oX-X>X>X,X,X,X,X,X>X>X;X;Xs.R _ _ { #.4.y.S.l.T.{.{. XoXoXoXoX].oX{.{.E.k.a.2.{ _ I L n v z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X,X,X,X,X,X>X>X;X[.2.I I L L L L I L x ^ *X;X>X>X,X,X,X,X,X>X>X;X*X#.I I I I Y I R I _ R _ ] { { [ { { { { ] _ R R I I L n n v z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q . X>X,X,X,X,X,X>X;X*X]._ Y L L L L L I L k r.*X;X>X>X,X,X,X,X,X>X;X-X.XR L n n n n n n L L L L L L L n L n n n L n n n c v z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 7 X>X,X,X,X,X>X>X;X*XT.R I L L L L L L K k H.*X;X>X>X,X,X,X,X>X>X;X*XJ.L L n n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X>X;X*Xk.I I n L L L L L b k ].*X;X>X,X,X,X,X,X>X>X;X*Xy.L n n n n v v v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X,X,X,X,X,X>X>X-X[.2.L L n L L L L L l ^ [.-X>X>X,X,X,X,X,X>X;X*X[.[ L n n n v v v v v v v z z v z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X,X,X,X,X,X>X;X*X]._ L L n L L L L K g r.*X;X>X>X,X,X,X,X,X>X;X*X{.R L n v v v v v v v z z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X,X,X,X,X>X>X;X*XE.I L n n n L L L b g H.*X;X>X>X,X,X,X,X>X>X;X*XF.L L v v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i u q 8 X>X>X,X>X>X>X;X*Xk.L L n n n n L L x k _.*X;X>X,X,X,X,X,X>X>X;X*Xy.n n v v v v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q # X>X>X>X>X;X*X[.2.L L n n n n n b l ~ [.-X>X>X,X,X,X,X,X>X;X*X[.' L n v v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s s u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 X>X,X,X,X,X,X>X;X*X{.I n c v v z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X,X,X,X,X>X>X;X*XF.L n v z z z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X,X,X,X,X>X>X;X*X4.n n z z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 .L n n n n n n b l E [.*X;X>X>X,X,X,X>X>X;X*X[.' n v z z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t 8 X>X>X>X>X>X;X*X{.I n z z z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q - X>X>X;X;X*X[.S.n n z z z z z z z z s s s s s s s s s s s s s s s s s s s s s u u u u u u u u i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i t q 7 c #F79827", -", c #F89825", -"< c #F0962B", -"1 c #F59A2D", -"2 c #F99B2B", -"3 c #EC9732", -"4 c #EC9A37", -"5 c #E2963B", -"6 c #E6983A", -"7 c #EC9C3B", -"8 c #F69D33", -"9 c #F99E32", -"0 c #F49E3A", -"q c #F9A036", -"w c #F6A13C", -"e c #F9A33B", -"r c #D79341", -"t c #DC9641", -"y c #E39A43", -"u c #EA9D42", -"i c #EFA041", -"p c #EDA34B", -"a c #F5A443", -"s c #F9A643", -"d c #FAA846", -"f c #F2A64C", -"g c #F9AA4B", -"h c #E5A251", -"j c #ECA756", -"k c #EBA758", -"l c #FAAF57", -"z c #FBB057", -"x c #FBB25B", -"c c #DFB179", -"v c #E4AA65", -"b c #EBAE64", -"n c #E9AF69", -"m c #FBB665", -"M c #F1B46A", -"N c #F8B96D", -"B c #E5B071", -"V c #EBB777", -"C c #EEB877", -"Z c #E7B478", -"A c #EBB97D", -"S c #F0B671", -"D c #F2B871", -"F c #EFBC80", -"G c #E6BD8D", -"H c #EDBF88", -"J c #E6BF90", -"K c #F1C187", -"L c #F1C288", -"P c #E5C093", -"I c #EEC493", -"U c #E1C19B", -"Y c #E9C69C", -"T c #ECC89D", -"R c #F1C897", -"E c #DFC5A4", -"W c #DBCBB8", -"Q c #E2C7A7", -"! c #EBCBA6", -"~ c #E6CBAB", -"^ c #E9D2B7", -"/ c #E5D1B9", -"( c #EBD6BD", -") c #EFD9BE", -"_ c #DDD0C2", -"` c #DCD7D2", -"' c #DEDEDE", -"] c #ECDAC5", -"[ c #EDDECB", -"{ c #E9E0D5", -"} c #E7E0D9", -"| c #E9E2DB", -" . c #EFE8DF", -".. c #E5E5E5", -"X. c #EBE7E2", -"o. c #EFEAE6", -"O. c #ECECEC", -"+. c #F2ECE6", -"@. c #F1F0EE", -"#. c #F4F4F4", -"$. c #FBFBFB", -"%. c None", -/* pixels */ -"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%.%.%.%.t 5 5 $ %.%.%.%.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%.r u w q 9 9 9 8 4 # %.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.y s e 9 2 , , , : > 2 9 q 5 %.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.s q 2 , , , , : , > 2 2 > > 2 9 %.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.t e 1 , , , , : : ; > 2 9 9 2 , , > 2 + %.%.%.%.%.%.", -"%.%.%.%.%.$ e 2 , , , , , , ; u u 8 1 1 2 > , , > > + %.%.%.%.%.", -"%.%.%.%.%.e 2 , , : > ; ; > < ` ` 0 c n 1 2 , , , > , %.%.%.%.%.", -"%.%.%.%.e 1 , , , , ; h v - 3 ..! w ' _ 9 2 > , , , > : %.%.%.%.", -"%.%.%.6 q , : , > 2 > W ..| [ #.H V ..D 9 9 2 , , , , , % %.%.%.", -"%.%.%.e 2 , > 2 2 2 9 b ! #.$.$.#.#.#.Y i 1 2 > , , , > ; %.%.%.", -"%.%.@ q > 2 2 2 9 q e q 0 o.$.+.) { #.#.| b 2 2 , , , , : X %.%.", -"%.%.4 9 2 2 9 q e e s w b O.#.( m x I @.$...f > > , , , : & %.%.", -"%.%.8 > 2 2 9 e s d g a P #.#.L x l a [ $.#.A 2 2 , : , , ; %.%.", -"%.+ 1 , , 2 2 q e d g f / $.#.T n k Z o.$.O.M 9 2 > , , , ; X %.", -"%.* 2 , , , 2 9 q e s f X.$.#.O.O.O.#.$.+.Y g e 9 2 , , , ; o %.", -"%.* 2 , , , 2 2 q e w n O.$.[ R ( O.$.$.[ d s e 9 2 2 , , ; o %.", -"%.+ 2 , , , > 2 8 8 1 G #.#.T m m N ] #.#.~ s e e 9 2 > : ; X %.", -"%.%.> , , , , 2 < v B [ $.O.m z z s b #.$...g e e q 9 2 ; = %.%.", -"%.%.= : , , , : 7 ' O.#.$.@.C j p u ~ #.$.} g q 9 9 2 2 ; % %.%.", -"%.%.o , , , , : 0 G ^ .$.#.O.X.{ X.#.$.#.Y e 9 2 2 > , ; %.%.", -"%.%.%., : , , , 2 2 2 M O.) ] #.#.#.#.O./ d 9 2 > , , ; = %.%.%.", -"%.%.%.& ; , , , , 2 ; Q ..g F O.K A H S s 9 2 > , : , ; o %.%.%.", -"%.%.%.%.; ; , , , , 2 E _ d ' ..d q q 9 2 > , : , , ; = %.%.%.%.", -"%.%.%.%.%.; : , , , 2 q d g U J e 2 2 > , , , , , ; = %.%.%.%.%.", -"%.%.%.%.%.o ; : , , , 2 9 q 9 q 9 > , : , , , , ; = . %.%.%.%.%.", -"%.%.%.%.%.%.. ; ; , , > 2 2 2 > , , , , , , , ; = %.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.= ; : > 2 2 , , : , , , , ; ; & %.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.. = ; > : , , , , ; ; = = X %.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%. % = ; ; ; ; & O %.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%.%.%.%. X X %.%.%.%.%.%.%.%.%.%.%.%.%.%.", -"%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%." -}; diff --git a/share/pixmaps/bitcoin64.png b/share/pixmaps/bitcoin64.png deleted file mode 100644 index 08c676ae4..000000000 Binary files a/share/pixmaps/bitcoin64.png and /dev/null differ diff --git a/share/pixmaps/bitcoin64.xpm b/share/pixmaps/bitcoin64.xpm deleted file mode 100644 index 851829d41..000000000 --- a/share/pixmaps/bitcoin64.xpm +++ /dev/null @@ -1,242 +0,0 @@ -/* XPM */ -static char *bitcoin__[] = { -/* columns rows colors chars-per-pixel */ -"64 64 172 2", -" c #8F6319", -". c #8F6A1A", -"X c #90651A", -"o c #916C1A", -"O c #AF7C1E", -"+ c #B1781E", -"@ c #9A7026", -"# c #AC801F", -"$ c #B1811F", -"% c #A9812B", -"& c #B08320", -"* c #BB8621", -"= c #BD8E22", -"- c #A58132", -"; c #FC8400", -": c #FD8A03", -"> c #FD8E0C", -", c #FF910E", -"< c #F98F14", -"1 c #F79117", -"2 c #FD9314", -"3 c #FC951B", -"4 c #FE9A1D", -"5 c #CA8E22", -"6 c #CC8E2A", -"7 c #D48D23", -"8 c #C39223", -"9 c #CE9925", -"0 c #D19C25", -"q c #D19329", -"w c #D5992B", -"e c #DD9D33", -"r c #D69F3C", -"t c #E29425", -"y c #E79925", -"u c #EA9926", -"i c #E69A2C", -"p c #F79625", -"a c #F99524", -"s c #F79825", -"d c #F89825", -"f c #F3962A", -"g c #F69B2C", -"h c #F89B2B", -"j c #E19F30", -"k c #EE9B34", -"l c #F49D33", -"z c #F99E32", -"x c #F39F3B", -"c c #DFA731", -"v c #D7A43D", -"b c #DCA63C", -"n c #EEA328", -"m c #FFA225", -"M c #FFAB26", -"N c #F3A529", -"B c #FEA429", -"V c #F4AB2A", -"C c #FFAC2A", -"Z c #FFB325", -"A c #FFB42C", -"S c #FFBB2D", -"D c #E3A335", -"F c #E5A438", -"G c #EDA03D", -"H c #F7A037", -"J c #FAA135", -"K c #F3AB31", -"L c #FEAB31", -"P c #F4A13C", -"I c #F9A33B", -"U c #FDB432", -"Y c #FFBF37", -"T c #FFC12F", -"R c #FFC230", -"E c #FFC03E", -"W c #DFAF41", -"Q c #ECA34D", -"! c #EDA84E", -"~ c #F2A343", -"^ c #FAA642", -"/ c #FAA846", -"( c #F1A74C", -") c #F6A94F", -"_ c #FAAA4A", -"` c #E7A451", -"' c #ECA754", -"] c #EFAA56", -"[ c #ECAC5B", -"{ c #F3AA52", -"} c #FCAE52", -"| c #FBB056", -" . c #FBB25C", -".. c #E7AB61", -"X. c #ECB067", -"o. c #E7B36D", -"O. c #EBB36C", -"+. c #F2B163", -"@. c #FCB460", -"#. c #F0B56B", -"$. c #E3B274", -"%. c #EDB672", -"&. c #EDB877", -"*. c #E2B57C", -"=. c #ECB97B", -"-. c #E4BA83", -";. c #EBBD83", -":. c #E7BF8D", -">. c #EBBD88", -",. c #E9C08C", -"<. c #E7C496", -"1. c #EBC393", -"2. c #EBC997", -"3. c #E7C49A", -"4. c #E9C69A", -"5. c #E3CA9D", -"6. c #E9C89E", -"7. c #DCC9AE", -"8. c #DDCBB2", -"9. c #E3C7A2", -"0. c #E5CAA3", -"q. c #E9CBA3", -"w. c #E5CEAB", -"e. c #E8CEAA", -"r. c #E4D4AC", -"t. c #EBD2AF", -"y. c #E7CFB2", -"u. c #E1D4B4", -"i. c #E8D5B6", -"p. c #E5D7BB", -"a. c #E9D6BB", -"s. c #E5D8B9", -"d. c #EAD8BE", -"f. c #F0D6B4", -"g. c #DFDFC6", -"h. c #E3D6C1", -"j. c #E9D7C0", -"k. c #E6DAC5", -"l. c #EBDCC7", -"z. c #E5DCCA", -"x. c #EADEC9", -"c. c #E8DFD0", -"v. c #D7E2D9", -"b. c #E3E0C9", -"n. c #EEE2CB", -"m. c #E6E1D4", -"M. c #E9E2D3", -"N. c #E4E4DC", -"B. c #E9E5DE", -"V. c #F4EDDE", -"C. c #DFE8E6", -"Z. c #DEEEE8", -"A. c #DFF2F3", -"S. c #DDFFFF", -"D. c #E1E6E0", -"F. c #E8E6E2", -"G. c #E8E9E5", -"H. c #E5EFEC", -"J. c #E8E9EA", -"K. c #EAF3EE", -"L. c #F3F3EB", -"P. c #E7EDF2", -"I. c #E8EEF3", -"U. c #E7F4F7", -"Y. c #E9F0F7", -"T. c #EBF5FD", -"R. c #E4FEFF", -"E. c #ECFCFF", -"W. c #F4F5F4", -"Q. c #F4FFFF", -"!. c #FEFFFF", -"~. c None", -/* pixels */ -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.F L h C C A A A A C C h L e ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.D N C m d d a a p a a p a a d m m C N j ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.- K M m a p s d d d d d d d d d d d d s p d m M V % ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.Y M d a d d d d d d d d d d d d d d d d h h d s a d M U ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.E m 4 a d d d d d d d d d d d d d d d d d d h h h d d d a d M U ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.C 4 a d d d d d d d d d d d d d d d d d h h h h h h d d d d d a m C ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.W S a p d d d d d d d d d d d d d d d d h h h h g g h h h d d d d d p a S c ~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.v M a s d d d d d d d d d d d d d d d h h h h h g z z g h h d d d d d d s a C w ~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.r Z a d d d d d d d d d d d d d d d g 4 : 2 h z z z z z h h h h d d d d d d d a S q ~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.b Z a d d d d d d d d d d d d d d h h 4 x $.l a z H h h H z h h h d d d d d d d d a A w ~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.T a s d d d d d d d d d d d d h h h g : $.R.T.7.a B x f > a H h h d d d d d d d d s a R ~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.U a s d d d d d d d d d d d d h h h h z : e.!.!.p.2 3 8.D.5.' a h h h d d d d d d d d p d A ~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.U M p d d d d d d d d d d h h 1 : : 2 h h p B.!.Q.%., l J.!.R.-.> z h h h d d d d d d d d p C N ~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.S a d d d d d d d d d d h d 3 7.r.O.G p ; k E.!.T.( , [ E.!.T.~ 4 z h h h d d d d d d d d d a S ~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.V d s d d d d d d d d h h h 2 l E.!.Q.T.m.:.q.!.!.l.: : -.Q.!.c.a z z z g h h d d d d d d d d s m A ~.~.~.~.~.~.~.", -"~.~.~.~.~.~.@ S a d d d d d d d h h h h z : *.R.!.!.!.!.Q.!.!.!.V.,.Q d.!.Q.1.2 I z z h h h d d d d d d d d d a S X ~.~.~.~.~.~.", -"~.~.~.~.~.~.U d s d d d d d h h h h h g z a [ 5.M.Q.!.!.!.!.!.!.!.Q.E.!.!.Q.&.; 3 J H z h h h d d d d d d d d s h C ~.~.~.~.~.~.", -"~.~.~.~.~.~.S a d d d d h h h h h h z z z I d > < %.W.!.!.!.!.!.!.!.!.!.!.!.W.s.[ > 4 H g h h d d d d d d d d d a S ~.~.~.~.~.~.", -"~.~.~.~.~.i M p d d d h h h h g z z z z J H I I J > x.!.!.!.!.Q.T.E.Q.!.!.!.!.!.E.u.f 2 H h h h d d d d d d d d p C 7 ~.~.~.~.~.", -"~.~.~.~.~.C a d h h h h h g g z z z J J I I I I J P J.!.!.!.!.d.P =.e.G.E.!.!.!.!.Q.Z.f 2 z h h d d d d d d d d d d A ~.~.~.~.~.", -"~.~.~.~.~.A a h h h h h g z z z J H I I I I ^ / d X.E.!.!.!.Q.1.4 I J I ;.U.!.!.!.!.!.N.1 h g h h d d d d d d d d a S ~.~.~.~.~.", -"~.~.~.~.6 C p d h h h z z J J J I I I I ^ ^ ^ _ a 3.Q.!.!.!.E.#.I . ._ 3 ] K.!.!.!.!.E.O., z h h h d d d d d d d p A + ~.~.~.~.", -"~.~.~.~.i B d d h h h g z J I I I I ^ ^ ^ / / _ h k.!.!.!.!.J.) } . .| .3 6.Q.!.!.!.Q.q.> z g h h d d d d d d d d B t ~.~.~.~.", -"~.~.~.~.B d d d d h h h z z J I I ^ / / / _ _ ^ ( I.!.!.!.Q.d.I . . .| .d 1.Q.!.!.!.Q.q.2 z h h h d d d d d d d d d B ~.~.~.~.", -"~.~.~.~.C a d d d d h h g z J H I ^ ^ / _ _ } J %.E.!.!.!.Q.;.4 _ } | } J f m.!.!.!.!.Q.;.2 J z g h h d d d d d d d a A ~.~.~.~.", -"~.~.~.~.C a d d d d h h h z z J I I ^ ^ / _ } z 6.Q.!.!.!.!.n.<.&.+.{ ) ] h.Q.!.!.!.!.R.~ d H z z h h h d d d d d d a A ~.~.~.~.", -"~.~.~.~.A a d d d d d h h g z z H I I ^ / _ _ z k.!.!.!.!.!.!.Q.E.I.F.F.T.Q.!.!.!.!.E.9.2 I J z z h h h d d d d d d d A ~.~.~.~.", -"~.~.~.~.S a d d d d d h h h z z J I I ^ ^ / I ( P.!.!.!.!.Q.Q.!.!.!.!.!.!.!.!.!.!.E.w.d J I I J z h h h d d d d d d d A ~.~.~.~.", -"~.~.~.~.A a d d d d d d h h h z J J I I ^ / h O.E.!.!.!.Q.f.1.z.Y.E.!.!.!.!.!.!.L.! , ^ / I I H z z h h h d d d d d d A ~.~.~.~.", -"~.~.~.~.S p d d d d d d h h h z z J I I ^ / d <.Q.!.!.!.E.+.d _ +.>.k.E.!.!.!.!.Q.s.P J _ ^ I I J z z h h h d d d d d A ~.~.~.~.", -"~.~.~.~.C a d d d d d d d h h g z z H I I ^ d k.!.!.!.!.J.{ | @.} I I O.H.!.!.!.!.Q.C.l I ^ I I H J z g h h d d d d a A ~.~.~.~.", -"~.~.~.~.B a d d d d d d d h h h h z z J I J x P.!.!.!.Q.j.I . . . . .B { K.!.!.!.!.Q.0.a / ^ I I J z z h h h d d d a A ~.~.~.~.", -"~.~.~.~.B d d d d d d d d d h h h J h f 2 ; [ E.!.!.!.Q.1.I . . .| | .d 4.Q.!.!.!.!.m.z I ^ I I I J z h h h h d d d B ~.~.~.~.", -"~.~.~.~.u B d d d d d d d d h h z , ' v.q.X.M.!.!.!.!.E.#.^ . .| } } } d >.Q.!.!.!.!.F.x J I I I J J z z h h h d d C t ~.~.~.~.", -"~.~.~.~.7 C p d d d d d d d d h h : y.Q.Q.Q.!.!.!.!.!.B.d B / _ } } } J 1 k.!.!.!.!.!.c.s J I H J J z z z h h h h s A + ~.~.~.~.", -"~.~.~.~.~.A a d d d d d d d d h > ` R.!.!.!.!.!.!.!.!.L.q.=.[ ~ z h h l 0.Q.!.!.!.!.Q.q.2 I J J z z h h h h h h h a S ~.~.~.~.~.", -"~.~.~.~.~.C d d d d d d d d d d > ..g.Y.E.Q.!.!.!.!.!.!.Q.E.T.B.k.a.d.P.Q.!.!.!.!.!.E.[ 2 J z z z g h h h h d d d d C ~.~.~.~.~.", -"~.~.~.~.~.y C p d d d d d d d d g 3 > l [ <.x.W.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.Q.z.> z z z h h h h h d d d d p C 7 ~.~.~.~.~.", -"~.~.~.~.~.~.S a d d d d d d d d d h h 3 , > ; =.Q.!.W.T.Q.!.!.!.!.!.!.!.!.!.!.!.Q.A.g 2 z h h h h h h d d d d d a S ~.~.~.~.~.~.", -"~.~.~.~.~.~.C h s d d d d d d d d d h g z H : <.!.!.t.l &.V.!.!.Q.Q.Q.Q.!.Q.Q.E.b.l > H h h h h h d d d d d d s m C ~.~.~.~.~.~.", -"~.~.~.~.~.~.X S a d d d d d d d d d h h h h p N.!.Q.=.: < c.!.Q.2.&.e.a.d.i.6.[ < 2 z h h h h d d d d d d d d a S ~.~.~.~.~.~.", -"~.~.~.~.~.~.~.A h s d d d d d d d d d h g 2 ~ E.!.E.{ 2 [ E.!.T.l : 2 1 3 2 > > h z h h h h d d d d d d d d s m A ~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.S a d d d d d d d d d h h : -.R.!.B.h 2 =.Q.!.M.p z z z h h z g h h h d d d d d d d d d d d a S ~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.N C p d d d d d d d d d h 3 ' 2.N.9.2 3 z.!.!.q.> J z h h h h h h d d d d d d d d d d d d p C n ~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.S h p d d d d d d d d d z 3 : p l J g 8.T.S.O.> z h h h h h d d d d d d d d d d d d d p h S ~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.S a s d d d d d d d d h h z d h I J a P o.P d g h h h d d d d d d d d d d d d d d s a S ~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.* S a s d d d d d d d d h h g z J J h 3 > d z h h h d d d d d d d d d d d d d d s a S * ~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.$ T a s d d d d d d d h h h z z z h g g h h d d d d d d d d d d d d d d d d s a T O ~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.& S a p d d d d d d h h h z g h h h h h d d d d d d d d d d d d d d d d p a S # ~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.8 S d p d d d d d d h h g h h h h d d d d d d d d d d d d d d d d d p h S = ~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.S A a s d d d d h h h h h d d d d d d d d d d d d d d d d d s a A S ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.0 T m p d d d d h h h d d d d d d d d d d d d d d d d d p B S 9 ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.V S m a p d h d d d d d d d d d d d d d d d d p a m S V ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.o V S C d p p d d d d d d d d d d d d p p d C S N . ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.5 C S A B d d a a d d a a a d B A S C 5 ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.O t B A A A A A A A A B t O ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", -"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~." -}; diff --git a/share/pixmaps/check.ico b/share/pixmaps/check.ico deleted file mode 100644 index 0c4e6e814..000000000 Binary files a/share/pixmaps/check.ico and /dev/null differ diff --git a/share/pixmaps/favicon.ico b/share/pixmaps/favicon.ico deleted file mode 100644 index 754eebc48..000000000 Binary files a/share/pixmaps/favicon.ico and /dev/null differ diff --git a/share/pixmaps/nsis-header.bmp b/share/pixmaps/nsis-header.bmp deleted file mode 100644 index 9ab0ce259..000000000 Binary files a/share/pixmaps/nsis-header.bmp and /dev/null differ diff --git a/share/pixmaps/nsis-wizard.bmp b/share/pixmaps/nsis-wizard.bmp deleted file mode 100644 index 71255c685..000000000 Binary files a/share/pixmaps/nsis-wizard.bmp and /dev/null differ diff --git a/share/pixmaps/send16.bmp b/share/pixmaps/send16.bmp deleted file mode 100644 index 676b5c4b4..000000000 Binary files a/share/pixmaps/send16.bmp and /dev/null differ diff --git a/share/pixmaps/send16mask.bmp b/share/pixmaps/send16mask.bmp deleted file mode 100644 index 06c747f93..000000000 Binary files a/share/pixmaps/send16mask.bmp and /dev/null differ diff --git a/share/pixmaps/send16masknoshadow.bmp b/share/pixmaps/send16masknoshadow.bmp deleted file mode 100644 index faf24e0d8..000000000 Binary files a/share/pixmaps/send16masknoshadow.bmp and /dev/null differ diff --git a/share/pixmaps/send20.bmp b/share/pixmaps/send20.bmp deleted file mode 100644 index 2b90422b3..000000000 Binary files a/share/pixmaps/send20.bmp and /dev/null differ diff --git a/share/pixmaps/send20mask.bmp b/share/pixmaps/send20mask.bmp deleted file mode 100644 index f124d0da0..000000000 Binary files a/share/pixmaps/send20mask.bmp and /dev/null differ diff --git a/share/setup.nsi.in b/share/setup.nsi.in deleted file mode 100644 index 6c0e895bb..000000000 --- a/share/setup.nsi.in +++ /dev/null @@ -1,179 +0,0 @@ -Name "@PACKAGE_NAME@ (@WINDOWS_BITS@-bit)" - -RequestExecutionLevel highest -SetCompressor /SOLID lzma - -# General Symbol Definitions -!define REGKEY "SOFTWARE\$(^Name)" -!define VERSION @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ -!define COMPANY "Bitcoin Core project" -!define URL http://www.bitcoin.org/ - -# MUI Symbol Definitions -!define MUI_ICON "@abs_top_srcdir@/share/pixmaps/bitcoin.ico" -!define MUI_WELCOMEFINISHPAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp" -!define MUI_HEADERIMAGE -!define MUI_HEADERIMAGE_RIGHT -!define MUI_HEADERIMAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-header.bmp" -!define MUI_FINISHPAGE_NOAUTOCLOSE -!define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM -!define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY} -!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup -!define MUI_STARTMENUPAGE_DEFAULTFOLDER "@PACKAGE_NAME@" -!define MUI_FINISHPAGE_RUN $INSTDIR\bitcoin-qt.exe -!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" -!define MUI_UNWELCOMEFINISHPAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp" -!define MUI_UNFINISHPAGE_NOAUTOCLOSE - -# Included files -!include Sections.nsh -!include MUI2.nsh -!if "@WINDOWS_BITS@" == "64" -!include x64.nsh -!endif - -# Variables -Var StartMenuGroup - -# Installer pages -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_STARTMENU Application $StartMenuGroup -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - -# Installer languages -!insertmacro MUI_LANGUAGE English - -# Installer attributes -OutFile @abs_top_srcdir@/bitcoin-${VERSION}-win@WINDOWS_BITS@-setup.exe -!if "@WINDOWS_BITS@" == "64" -InstallDir $PROGRAMFILES64\Bitcoin -!else -InstallDir $PROGRAMFILES\Bitcoin -!endif -CRCCheck on -XPStyle on -BrandingText " " -ShowInstDetails show -VIProductVersion ${VERSION}.@CLIENT_VERSION_BUILD@ -VIAddVersionKey ProductName "Bitcoin Core" -VIAddVersionKey ProductVersion "${VERSION}" -VIAddVersionKey CompanyName "${COMPANY}" -VIAddVersionKey CompanyWebsite "${URL}" -VIAddVersionKey FileVersion "${VERSION}" -VIAddVersionKey FileDescription "" -VIAddVersionKey LegalCopyright "" -InstallDirRegKey HKCU "${REGKEY}" Path -ShowUninstDetails show - -# Installer sections -Section -Main SEC0000 - SetOutPath $INSTDIR - SetOverwrite on - File @abs_top_srcdir@/release/bitcoin-qt.exe - File /oname=COPYING.txt @abs_top_srcdir@/COPYING - File /oname=readme.txt @abs_top_srcdir@/doc/README_windows.txt - SetOutPath $INSTDIR\daemon - File @abs_top_srcdir@/release/bitcoind.exe - File @abs_top_srcdir@/release/bitcoin-cli.exe - SetOutPath $INSTDIR\doc - File /r @abs_top_srcdir@/doc\*.* - SetOutPath $INSTDIR - WriteRegStr HKCU "${REGKEY}\Components" Main 1 - - # Remove old wxwidgets-based-bitcoin executable and locales: - Delete /REBOOTOK $INSTDIR\bitcoin.exe - RMDir /r /REBOOTOK $INSTDIR\locale -SectionEnd - -Section -post SEC0001 - WriteRegStr HKCU "${REGKEY}" Path $INSTDIR - SetOutPath $INSTDIR - WriteUninstaller $INSTDIR\uninstall.exe - !insertmacro MUI_STARTMENU_WRITE_BEGIN Application - CreateDirectory $SMPROGRAMS\$StartMenuGroup - CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" $INSTDIR\bitcoin-qt.exe - CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe - !insertmacro MUI_STARTMENU_WRITE_END - WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)" - WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}" - WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "${COMPANY}" - WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}" - WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\uninstall.exe - WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe - WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1 - WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1 - WriteRegStr HKCR "bitcoin" "URL Protocol" "" - WriteRegStr HKCR "bitcoin" "" "URL:Bitcoin" - WriteRegStr HKCR "bitcoin\DefaultIcon" "" $INSTDIR\bitcoin-qt.exe - WriteRegStr HKCR "bitcoin\shell\open\command" "" '"$INSTDIR\bitcoin-qt.exe" "%1"' -SectionEnd - -# Macro for selecting uninstaller sections -!macro SELECT_UNSECTION SECTION_NAME UNSECTION_ID - Push $R0 - ReadRegStr $R0 HKCU "${REGKEY}\Components" "${SECTION_NAME}" - StrCmp $R0 1 0 next${UNSECTION_ID} - !insertmacro SelectSection "${UNSECTION_ID}" - GoTo done${UNSECTION_ID} -next${UNSECTION_ID}: - !insertmacro UnselectSection "${UNSECTION_ID}" -done${UNSECTION_ID}: - Pop $R0 -!macroend - -# Uninstaller sections -Section /o -un.Main UNSEC0000 - Delete /REBOOTOK $INSTDIR\bitcoin-qt.exe - Delete /REBOOTOK $INSTDIR\COPYING.txt - Delete /REBOOTOK $INSTDIR\readme.txt - RMDir /r /REBOOTOK $INSTDIR\daemon - RMDir /r /REBOOTOK $INSTDIR\doc - DeleteRegValue HKCU "${REGKEY}\Components" Main -SectionEnd - -Section -un.post UNSEC0001 - DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" - Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" - Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\$(^Name).lnk" - Delete /REBOOTOK "$SMSTARTUP\Bitcoin.lnk" - Delete /REBOOTOK $INSTDIR\uninstall.exe - Delete /REBOOTOK $INSTDIR\debug.log - Delete /REBOOTOK $INSTDIR\db.log - DeleteRegValue HKCU "${REGKEY}" StartMenuGroup - DeleteRegValue HKCU "${REGKEY}" Path - DeleteRegKey /IfEmpty HKCU "${REGKEY}\Components" - DeleteRegKey /IfEmpty HKCU "${REGKEY}" - DeleteRegKey HKCR "bitcoin" - RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup - RmDir /REBOOTOK $INSTDIR - Push $R0 - StrCpy $R0 $StartMenuGroup 1 - StrCmp $R0 ">" no_smgroup -no_smgroup: - Pop $R0 -SectionEnd - -# Installer functions -Function .onInit - InitPluginsDir -!if "@WINDOWS_BITS@" == "64" - ${If} ${RunningX64} - ; disable registry redirection (enable access to 64-bit portion of registry) - SetRegView 64 - ${Else} - MessageBox MB_OK|MB_ICONSTOP "Cannot install 64-bit version on a 32-bit system." - Abort - ${EndIf} -!endif -FunctionEnd - -# Uninstaller functions -Function un.onInit - ReadRegStr $INSTDIR HKCU "${REGKEY}" Path - !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup - !insertmacro SELECT_UNSECTION Main ${UNSEC0000} -FunctionEnd diff --git a/share/ui.rc b/share/ui.rc deleted file mode 100644 index c3cece1ef..000000000 --- a/share/ui.rc +++ /dev/null @@ -1,15 +0,0 @@ -bitcoin ICON "pixmaps/bitcoin.ico" - -#include "wx/msw/wx.rc" - -check ICON "pixmaps/check.ico" -send16 BITMAP "pixmaps/send16.bmp" -send16mask BITMAP "pixmaps/send16mask.bmp" -send16masknoshadow BITMAP "pixmaps/send16masknoshadow.bmp" -send20 BITMAP "pixmaps/send20.bmp" -send20mask BITMAP "pixmaps/send20mask.bmp" -addressbook16 BITMAP "pixmaps/addressbook16.bmp" -addressbook16mask BITMAP "pixmaps/addressbook16mask.bmp" -addressbook20 BITMAP "pixmaps/addressbook20.bmp" -addressbook20mask BITMAP "pixmaps/addressbook20mask.bmp" -favicon ICON "pixmaps/favicon.ico" diff --git a/src/Makefile.am b/src/Makefile.am index 369b1d54b..e7b03afad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,8 +23,8 @@ BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include -BITCOIN_INCLUDES += -I$(srcdir)/snark/build/include -BITCOIN_INCLUDES += -I$(srcdir)/snark/build/include/libsnark +BITCOIN_INCLUDES += -I$(srcdir)/snark +BITCOIN_INCLUDES += -I$(srcdir)/snark/libsnark BITCOIN_INCLUDES += -I$(srcdir)/univalue/include LIBBITCOIN_SERVER=libbitcoin_server.a @@ -34,19 +34,13 @@ LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBSECP256K1=secp256k1/libsecp256k1.la -LIBSNARK=snark/build/lib/libsnark.a +LIBSNARK=snark/libsnark.a LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) -# A phony target is included here to ensure libsnark is built first, so that its -# header files are collated for use in later build steps. -# See https://stackoverflow.com/a/10726725 --include collate-libsnark -collate-libsnark: $(LIBSNARK) - LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -fstack-protector-all LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1 if HAVE_OPENMP @@ -54,10 +48,10 @@ LIBSNARK_CONFIG_FLAGS += MULTICORE=1 endif $(LIBSNARK): $(wildcard snark/src/*) - $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ install PREFIX=$(srcdir)/build DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" libsnark-tests: $(wildcard snark/src/*) - $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check PREFIX=$(srcdir)/build DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" + $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ @@ -149,6 +143,7 @@ BITCOIN_CORE_H = \ compressor.h \ consensus/consensus.h \ consensus/params.h \ + consensus/upgrades.h \ consensus/validation.h \ core_io.h \ core_memusage.h \ @@ -215,6 +210,7 @@ BITCOIN_CORE_H = \ utiltls.h \ validationinterface.h \ version.h \ + wallet/asyncrpcoperation_mergetoaddress.h \ wallet/asyncrpcoperation_sendmany.h \ wallet/asyncrpcoperation_shieldcoinbase.h \ wallet/crypter.h \ @@ -309,6 +305,7 @@ libbitcoin_wallet_a_SOURCES = \ utiltest.h \ zcbenchmarks.cpp \ zcbenchmarks.h \ + wallet/asyncrpcoperation_mergetoaddress.cpp \ wallet/asyncrpcoperation_sendmany.cpp \ wallet/asyncrpcoperation_shieldcoinbase.cpp \ wallet/crypter.cpp \ @@ -367,6 +364,7 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ coins.cpp \ compressor.cpp \ + consensus/upgrades.cpp \ core_read.cpp \ core_write.cpp \ hash.cpp \ diff --git a/src/Makefile.gtest.include b/src/Makefile.gtest.include index 96647371e..3749b8db8 100644 --- a/src/Makefile.gtest.include +++ b/src/Makefile.gtest.include @@ -25,6 +25,7 @@ zcash_gtest_SOURCES = \ gtest/test_random.cpp \ gtest/test_rpc.cpp \ gtest/test_transaction.cpp \ + gtest/test_upgrades.cpp \ gtest/test_validation.cpp \ gtest/test_circuit.cpp \ gtest/test_txid.cpp \ diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index cfe2a5960..0c02b3184 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -7,6 +7,7 @@ #include "clientversion.h" #include "coins.h" #include "consensus/consensus.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "keystore.h" #include "primitives/transaction.h" @@ -71,7 +72,7 @@ static bool AppInitRawTx(int argc, char* argv[]) strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N")); strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX")); strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX")); - strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " + + strUsage += HelpMessageOpt("sign=HEIGHT:SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " + _("This command requires JSON registers:") + _("prevtxs=JSON object") + ", " + _("privatekeys=JSON object") + ". " + @@ -158,12 +159,21 @@ static void RegisterLoad(const string& strInput) static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal) { int64_t newVersion = atoi64(cmdVal); - if (newVersion < CTransaction::MIN_CURRENT_VERSION || newVersion > CTransaction::MAX_CURRENT_VERSION) + if (newVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION || newVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION) throw runtime_error("Invalid TX version requested"); tx.nVersion = (int) newVersion; } +static void MutateTxExpiry(CMutableTransaction& tx, const string& cmdVal) +{ + int64_t newExpiry = atoi64(cmdVal); + if (newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) { + throw runtime_error("Invalid TX expiry requested"); + } + tx.nExpiryHeight = (int) newExpiry; +} + static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal) { int64_t newLocktime = atoi64(cmdVal); @@ -323,10 +333,39 @@ vector ParseHexUO(map& o, string strKey) return ParseHexUV(o[strKey], strKey); } -static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) +static CAmount AmountFromValue(const UniValue& value) { - int nHashType = SIGHASH_ALL; + if (!value.isNum() && !value.isStr()) + throw runtime_error("Amount is not a number or string"); + CAmount amount; + if (!ParseFixedPoint(value.getValStr(), 8, &amount)) + throw runtime_error("Invalid amount"); + if (!MoneyRange(amount)) + throw runtime_error("Amount out of range"); + return amount; +} + +static void MutateTxSign(CMutableTransaction& tx, const string& strInput) +{ + // separate HEIGHT:SIGHASH-FLAGS in string + size_t pos = strInput.find(':'); + if ((pos == 0) || + (pos == (strInput.size() - 1))) + throw runtime_error("Invalid sighash flag separator"); + + // extract and validate HEIGHT + string strHeight = strInput.substr(0, pos); + int nHeight = atoi(strHeight); + if (nHeight <= 0) { + throw runtime_error("invalid height"); + } + // extract and validate SIGHASH-FLAGS + int nHashType = SIGHASH_ALL; + string flagStr; + if (pos != string::npos) { + flagStr = strInput.substr(pos + 1, string::npos); + } if (flagStr.size() > 0) if (!findSighashFlags(nHashType, flagStr)) throw runtime_error("unknown sighash flag/sign option"); @@ -394,7 +433,10 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) if ((unsigned int)nOut >= coins->vout.size()) coins->vout.resize(nOut+1); coins->vout[nOut].scriptPubKey = scriptPubKey; - coins->vout[nOut].nValue = 0; // we don't know the actual output value + coins->vout[nOut].nValue = 0; + if (prevOut.exists("amount")) { + coins->vout[nOut].nValue = AmountFromValue(prevOut["amount"]); + } } // if redeemScript given and private keys given, @@ -413,6 +455,9 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + // Grab the consensus branch ID for the given height + auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); + // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; @@ -422,17 +467,19 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) continue; } const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey; + const CAmount& amount = coins->vout[txin.prevout.n].nValue; - txin.scriptSig.clear(); + SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); + ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId); // ... and merge in other signatures: - BOOST_FOREACH(const CTransaction& txv, txVariants) { - txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); - } - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i))) + BOOST_FOREACH(const CTransaction& txv, txVariants) + sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId); + UpdateTransaction(mergedTx, i, sigdata); + + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId)) fComplete = false; } @@ -466,6 +513,8 @@ static void MutateTx(CMutableTransaction& tx, const string& command, MutateTxVersion(tx, commandVal); else if (command == "locktime") MutateTxLocktime(tx, commandVal); + else if (command == "expiry") + MutateTxExpiry(tx, commandVal); else if (command == "delin") MutateTxDelInput(tx, commandVal); diff --git a/src/chain.h b/src/chain.h index a3b1b7ae9..937e20bda 100644 --- a/src/chain.h +++ b/src/chain.h @@ -94,8 +94,14 @@ enum BlockStatus: uint32_t { BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed BLOCK_FAILED_CHILD = 64, //! descends from failed block BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, + + BLOCK_ACTIVATES_UPGRADE = 128, //! block activates a network upgrade }; +//! Short-hand for the highest consensus validity we implement. +//! Blocks with this validity are assumed to satisfy all consensus rules. +static const BlockStatus BLOCK_VALID_CONSENSUS = BLOCK_VALID_SCRIPTS; + /** The block chain is a tree shaped structure starting with the * genesis block at the root, with each block potentially having multiple * candidates to be the next block. A blockindex may have multiple pprev pointing @@ -140,6 +146,11 @@ public: //! Verification status of this block. See enum BlockStatus unsigned int nStatus; + //! Branch ID corresponding to the consensus rules used to validate this block. + //! Only cached if block validity is BLOCK_VALID_CONSENSUS. + //! Persisted at each activation height, memory-only for intervening blocks. + boost::optional nCachedBranchId; + //! The anchor for the tree state up to the start of this block uint256 hashAnchor; @@ -180,6 +191,7 @@ public: nTx = 0; nChainTx = 0; nStatus = 0; + nCachedBranchId = boost::none; hashAnchor = uint256(); hashAnchorEnd = uint256(); nSequenceId = 0; @@ -341,6 +353,18 @@ public: READWRITE(VARINT(nDataPos)); if (nStatus & BLOCK_HAVE_UNDO) READWRITE(VARINT(nUndoPos)); + if (nStatus & BLOCK_ACTIVATES_UPGRADE) { + if (ser_action.ForRead()) { + uint32_t branchId; + READWRITE(branchId); + nCachedBranchId = branchId; + } else { + // nCachedBranchId must always be set if BLOCK_ACTIVATES_UPGRADE is set. + assert(nCachedBranchId); + uint32_t branchId = *nCachedBranchId; + READWRITE(branchId); + } + } READWRITE(hashAnchor); // block header diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 31a15510b..5e958d17d 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -16,10 +16,56 @@ #include "base58.h" -using namespace std; - #include "chainparamsseeds.h" +static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, const uint256& nNonce, const std::vector& nSolution, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) +{ + // To create a genesis block for a new chain which is Overwintered: + // txNew.nVersion = 3 + // txNew.fOverwintered = true + // txNew.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID + // txNew.nExpiryHeight = + CMutableTransaction txNew; + txNew.nVersion = 1; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 520617983 << CScriptNum(4) << std::vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].nValue = genesisReward; + txNew.vout[0].scriptPubKey = genesisOutputScript; + + CBlock genesis; + genesis.nTime = nTime; + genesis.nBits = nBits; + genesis.nNonce = nNonce; + genesis.nSolution = nSolution; + genesis.nVersion = nVersion; + genesis.vtx.push_back(txNew); + genesis.hashPrevBlock.SetNull(); + genesis.hashMerkleRoot = genesis.BuildMerkleTree(); + return genesis; +} + +/** + * Build the genesis block. Note that the output of its generation + * transaction cannot be spent since it did not originally exist in the + * database (and is in any case of zero value). + * + * >>> from pyblake2 import blake2s + * >>> 'Zcash' + blake2s(b'The Economist 2016-10-29 Known unknown: Another crypto-currency is born. BTC#436254 0000000000000000044f321997f336d2908cf8c8d6893e88dbf067e2d949487d ETH#2521903 483039a6b6bd8bd05f0584f9a078d075e454925eb71c1f13eaff59b405a721bb DJIA close on 27 Oct 2016: 18,169.68').hexdigest() + * + * CBlock(hash=00040fe8, ver=4, hashPrevBlock=00000000000000, hashMerkleRoot=c4eaa5, nTime=1477641360, nBits=1f07ffff, nNonce=4695, vtx=1) + * CTransaction(hash=c4eaa5, ver=1, vin.size=1, vout.size=1, nLockTime=0) + * CTxIn(COutPoint(000000, -1), coinbase 04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334) + * CTxOut(nValue=0.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) + * vMerkleTree: c4eaa5 + */ +static CBlock CreateGenesisBlock(uint32_t nTime, const uint256& nNonce, const std::vector& nSolution, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) +{ + const char* pszTimestamp = "Zdashe540ecf100001889836c7d491a2f44e6bc6076d59e5e317255946b71be3fc516"; + const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; + return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nSolution, nBits, nVersion, genesisReward); +} + /** * Main network */ @@ -50,8 +96,18 @@ public: consensus.nPowMaxAdjustDown = 32; // 32% adjustment down consensus.nPowMaxAdjustUp = 16; // 16% adjustment up consensus.nPowTargetSpacing = 2.5 * 60; + consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; + consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = + Consensus::NetworkUpgrade::ALWAYS_ACTIVE; + consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nProtocolVersion = 170002; + consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170004; + consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + /** - * The message start string should be awesome! ⓩ❤ + * The message start string should be awesome! ⓩ❤ */ pchMessageStart[0] = 0x24; pchMessageStart[1] = 0xe9; @@ -67,30 +123,11 @@ public: nEquihashN = N; nEquihashK = K; - /** - * Build the genesis block. Note that the output of its generation - * transaction cannot be spent since it did not originally exist in the - * database (and is in any case of zero value). - * - * >>> from pyblake2 import blake2s - * >>> 'Zcash' + blake2s(b'Reuters:... ').hexdigest() - */ - const char* pszTimestamp = "Zdashe540ecf100001889836c7d491a2f44e6bc6076d59e5e317255946b71be3fc516"; - CMutableTransaction txNew; - txNew.vin.resize(1); - txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 520617983 << CScriptNum(4) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); - txNew.vout[0].nValue = 0; - txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; - genesis.vtx.push_back(txNew); - genesis.hashPrevBlock.SetNull(); - genesis.hashMerkleRoot = genesis.BuildMerkleTree(); - genesis.nVersion = 4; - genesis.nTime = 1479401611; - genesis.nBits = 0x1f07ffff; - genesis.nNonce = uint256S("0x1205000000000000000000000000000000000000000000000000000000000000"); - genesis.nSolution = ParseHex("0045f33727869d999e1d90de13eec508bb9eedf7c623ae0926922a749df12927967ce41f0363365e536a149ced0a25ce7258bcf4d36c9d69ea830ecafaac0a20576ee2405fa6e1ed91e5e5f3e72add8dae92175e05bb114100c654b90a0ea0e35e3ecee480d073b90c0d252963519492dce839f14bd3e54b017972fe05c30f61d73437d2ccb8a8dac1f33ba27c9d8a81bc02911a0f04f0af099ba8cc9114bd0de60fcd699673bc7a05d06baf544c5daa773991ff85c269c17f3a58618818f91d6ee9e4c393cd8d03428a2cc9be4243384caf197c77029b8c6c9387ab7a4966faac8efb13f7f9e259040fbbc1295551ad10084dba5ef0b732da7c90bd06026152acc74aad871aa3c2e46666d262129f07e128a0ea322b532851d649d2e0443954dafaaddfa6af28a70c786b94d904cb8ad3fda5364d9d5cccd1ce802f801dad25644a7dcab1c44191f24cdd8997f19c3602bc6e936aca34413a3270f837d94b211c5ad7533a070fe7b5651db5bf5d2aa13d503af5eef912fdcb5704a1bfc4c095d9b3da8f62261ed0dea089bf5b12db067ce1b4bee14f6515a180dedfeac9d794649da2b203e2a975db5c961daf788239ec722a7afbc63b8cb30c11e0ce1943f71981c3437530a4c0fcec0f9e7c6c1f5e85373ff132ddccb202916665c5559ddbcff20c743f15e2b7748a11d5de283f8cf190cb0c47feec730f6bde470ae172b9fdfc07e96362dd9238833876ff14b8028e811af7610b08842aac55f79f066e5df160104bd571f44fb16d7476e2626458c2992f6291781915d5ee927594c8a5966ba379ace56cf30a9c5f79e70fa6347e664796eea268d74862522ac275bf94ef2e406034ff121345351b92245ba834c752249d3506a111407bbd10e31b1167f9c3702fc54176e18ad8ca6211c892d4ba4598b3d834c2aa06392e21b4ff3d6d510132989a9828086bbbd1e03debe3fd44e34550c54103df97e25709e086efefc27013b9fc08bc777f96630876dfcba638d5f1f2fe10935d5fb950388ca485044535350e83267d0b5c75e5f570cd849d8567daecb90b011f72bccde31e8c6b13a630b82dc1fe68f7ef261013e2a91ed033c11fa201f4a32f7a05a58cbbce0a13f175c5e08a3ced164686a26277be7bbac9fed583276d12d67a12649b4f46e466bdc57bed60c3f8bd6e05f73d54686d36e97a6461cbda430abf9ec8df6699160822abbc947463338741c961fcaab0dbbd2a2b92084d0b372242e6103aa54479fc7b350f35c23eb1f3161352ec3e1ba178fd82147ff42ba02164405fe74606b6c525883dddc5fd8431bb49c889571c155974af19291e49f55fbfe7c823f526f77edc9bba773f9e370baf614175515eef3f7be1750ee2a3c915a0f8e3ea31bdd397668ebef7f0cf75ddecec887df2baf771e1013d2d4795c39ba8449c18d559eab9c2718f39531c0b632437506c9061ee9995e11173da85948b5b82e02e54977eb64db682af9a1993bbd16fcab3d55be7493a38ab9012d6c3f5834f3740fcc725aa70e0570b46073ad43c7b0a582af576f8e2afd4c6c75d933b0d8955a49c2b522d84a9fc9c75bbf2b5363667e5b42b420eddfa537ac5d15d7a4ea9c5dfd063cb03e81da219163fe7135d61db9d19f891e5784613a59df7ffefa2017f8d6edfde9ce19babd5963aae94ad7bfd52e736323c73f9765c9026f1b0a560dbdcc71563586f4ced072c0903bdf6362fe4f4c0cea265ad48a6639bccaa08b5593a9f0eeac5cfcc14ca6d2e7449ec029598b4061793745ba3e53dc289c16ee84c7c2575824e7a5e372d8c8e1bf0a2dfa90283a67bd305c684b39af1d109004522301344a9c346a0e227c45749aa24b11623211155bad78e1a137376738662a78619dceaf0c79f"); - + genesis = CreateGenesisBlock( + 1479401611, + uint256S("0x1205000000000000000000000000000000000000000000000000000000000000"), + ParseHex("0045f33727869d999e1d90de13eec508bb9eedf7c623ae0926922a749df12927967ce41f0363365e536a149ced0a25ce7258bcf4d36c9d69ea830ecafaac0a20576ee2405fa6e1ed91e5e5f3e72add8dae92175e05bb114100c654b90a0ea0e35e3ecee480d073b90c0d252963519492dce839f14bd3e54b017972fe05c30f61d73437d2ccb8a8dac1f33ba27c9d8a81bc02911a0f04f0af099ba8cc9114bd0de60fcd699673bc7a05d06baf544c5daa773991ff85c269c17f3a58618818f91d6ee9e4c393cd8d03428a2cc9be4243384caf197c77029b8c6c9387ab7a4966faac8efb13f7f9e259040fbbc1295551ad10084dba5ef0b732da7c90bd06026152acc74aad871aa3c2e46666d262129f07e128a0ea322b532851d649d2e0443954dafaaddfa6af28a70c786b94d904cb8ad3fda5364d9d5cccd1ce802f801dad25644a7dcab1c44191f24cdd8997f19c3602bc6e936aca34413a3270f837d94b211c5ad7533a070fe7b5651db5bf5d2aa13d503af5eef912fdcb5704a1bfc4c095d9b3da8f62261ed0dea089bf5b12db067ce1b4bee14f6515a180dedfeac9d794649da2b203e2a975db5c961daf788239ec722a7afbc63b8cb30c11e0ce1943f71981c3437530a4c0fcec0f9e7c6c1f5e85373ff132ddccb202916665c5559ddbcff20c743f15e2b7748a11d5de283f8cf190cb0c47feec730f6bde470ae172b9fdfc07e96362dd9238833876ff14b8028e811af7610b08842aac55f79f066e5df160104bd571f44fb16d7476e2626458c2992f6291781915d5ee927594c8a5966ba379ace56cf30a9c5f79e70fa6347e664796eea268d74862522ac275bf94ef2e406034ff121345351b92245ba834c752249d3506a111407bbd10e31b1167f9c3702fc54176e18ad8ca6211c892d4ba4598b3d834c2aa06392e21b4ff3d6d510132989a9828086bbbd1e03debe3fd44e34550c54103df97e25709e086efefc27013b9fc08bc777f96630876dfcba638d5f1f2fe10935d5fb950388ca485044535350e83267d0b5c75e5f570cd849d8567daecb90b011f72bccde31e8c6b13a630b82dc1fe68f7ef261013e2a91ed033c11fa201f4a32f7a05a58cbbce0a13f175c5e08a3ced164686a26277be7bbac9fed583276d12d67a12649b4f46e466bdc57bed60c3f8bd6e05f73d54686d36e97a6461cbda430abf9ec8df6699160822abbc947463338741c961fcaab0dbbd2a2b92084d0b372242e6103aa54479fc7b350f35c23eb1f3161352ec3e1ba178fd82147ff42ba02164405fe74606b6c525883dddc5fd8431bb49c889571c155974af19291e49f55fbfe7c823f526f77edc9bba773f9e370baf614175515eef3f7be1750ee2a3c915a0f8e3ea31bdd397668ebef7f0cf75ddecec887df2baf771e1013d2d4795c39ba8449c18d559eab9c2718f39531c0b632437506c9061ee9995e11173da85948b5b82e02e54977eb64db682af9a1993bbd16fcab3d55be7493a38ab9012d6c3f5834f3740fcc725aa70e0570b46073ad43c7b0a582af576f8e2afd4c6c75d933b0d8955a49c2b522d84a9fc9c75bbf2b5363667e5b42b420eddfa537ac5d15d7a4ea9c5dfd063cb03e81da219163fe7135d61db9d19f891e5784613a59df7ffefa2017f8d6edfde9ce19babd5963aae94ad7bfd52e736323c73f9765c9026f1b0a560dbdcc71563586f4ced072c0903bdf6362fe4f4c0cea265ad48a6639bccaa08b5593a9f0eeac5cfcc14ca6d2e7449ec029598b4061793745ba3e53dc289c16ee84c7c2575824e7a5e372d8c8e1bf0a2dfa90283a67bd305c684b39af1d109004522301344a9c346a0e227c45749aa24b11623211155bad78e1a137376738662a78619dceaf0c79f"), + 0x1f07ffff, 4, 0); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x0003a67bc26fe564b75daf11186d360652eb435a35ba3d9d3e7e5d5f8e62dc17")); assert(genesis.hashMerkleRoot == uint256S("0x830539f9ec196f36a2759638b674a51b668eba7bbf6af10c56fed4af666be177")); @@ -125,7 +162,7 @@ public: fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = false; - checkpointData = (Checkpoints::CCheckpointData) { + checkpointData = (CCheckpointData) { boost::assign::map_list_of (0, consensus.hashGenesisBlock) (120, uint256S("0x01e107af8605050c438e904a145e0e6479077bb2b4abbed8f9067adbeb37dd77")), @@ -201,32 +238,53 @@ static CMainParams mainParams; /** * Testnet (v3) */ -class CTestNetParams : public CMainParams { +class CTestNetParams : public CChainParams { public: CTestNetParams() { strNetworkID = "test"; strCurrencyUnits = "TUSH"; + consensus.fCoinbaseMustBeProtected = true; + consensus.nSubsidySlowStartInterval = 20000; + consensus.nSubsidyHalvingInterval = 840000; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 400; consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.nPowAveragingWindow = 17; assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); + consensus.nPowMaxAdjustDown = 32; // 32% adjustment down + consensus.nPowMaxAdjustUp = 16; // 16% adjustment up + consensus.nPowTargetSpacing = 2.5 * 60; + consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; + consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = + Consensus::NetworkUpgrade::ALWAYS_ACTIVE; + consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nProtocolVersion = 170002; + consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170003; + consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 207500; + pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0x1a; pchMessageStart[2] = 0xf9; pchMessageStart[3] = 0xbf; vAlertPubKey = ParseHex("040c2275ef276b57c646edd5d4441b911c6b166596b0ee853e67842c580b9ed14dab42c7db0985afa1454f9480004e9597178ad4c51d54069bc1013909818a7b81"); nDefaultPort = 18888; - //nMinerThreads = 0; #Error on 1.0.12-rc Build to 1.0.9 + nMaxTipAge = 24 * 60 * 60; nPruneAfterHeight = 1000; + const size_t N = 200, K = 9; + BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); + nEquihashN = N; + nEquihashK = K; - //! Modify the testnet genesis block so the timestamp is valid for a later start. - genesis.nTime = 1506883264; - genesis.nBits = 0x2007ffff; - genesis.nNonce = uint256S("0x0000000000000000000000000000000000000000000000000000000000000007"); - genesis.nSolution = ParseHex("00e76338efc84e87b18b92ae132b31a6ff581ff89f1aeacf5c650f46ba9b6db78640fbb7f1ebf417ac890f747e4965f231ad966795d88eb3fab219fcb91d664b24e26d62e6572bc28289d058fcad472cc91ce83102560a46f8c2bef9f3865407beff0d3de381d0c0330f0e10fa1b052c495a9a2669edf9a385ab18359ed61953dc000c870899653ee2b391bd5930cc134e1bea41cb64bae2262cb186b12613df6098c9a062ff23690367c5698159c7aae04e03fcad58686e0cda1223da0cd4aeb761628f77999a52e1b1d58dee4c5f1d283c18d4264e5ebb73b5e8a241905ab2a38097157508902b9ede96e32ccf27bd5fa41cdaf65eed6ff54e26340726d8abdb207363e176c29798a9b5e94b0eab5a56076b95a24659daa7cbfd70897f06c891a5b673e98c29638ed5fcdecacfa4cf3b30a47413c71b1a5b57c240ae3cd001a9753b8e0af92cddeea7f28edffb3ae304e307e83ad7d4ed899972f1a4d8b98d8ec0bee6b40e594c15936b9d89c2e1c485087cae539d97bea3a14537daa89dabd5dfb45ea7266def7baafcbf5a6a3150f506d810333a2da6d8eb4f2e6de036dce45d95880612bfcbe9e446a954c133746f7cc5deebb27b21e8199603ec0eb0ee41d2c0a22f1363622ccfe672bfd00d566cdfdc4c4555ea3baa9662eae5ef399ebb345042ad4a607fd78c615484b66746eb2e56edf07b79c9077df6370fa17d91f8c4036fc3afb7b2065598a169142f12c75725986b3d7b33768fcb87de68ecfa924308cea135fb0feb5121d82538dd5378425beedcc36c21d8266e6c1c6147dd22c27f90a80f2cf8b5160f830785250422b51857cdf6b1d5851a08126dbebc957a0816a4f914a4a02b48e813f64745fcf1093a6cf9660f3d7e556c87fb55d98d420fe02497d11dbf5191310f7abe28d8c7ebb28f7ae702d0d34de236e11ecbcd028008c78821db534c8f36e6ff633d8eb73057967a0bf41b9b0dc3af5856e6325522513279924fba9d61035bce23c89d39151d4a907e0b9b407dc5c3daae4c0f3f4c996d4de800b696a285edc2d13d33616bc33d14fb15900f97b6f9b8c83326471f12c540829581f14e814ec121a922f9bf10e9f8ba7359d6be99fc8a3d2b65d3a691f22e45af9a84ce0332930944fe4ad535634e9c65af25c0a1ca965a3f9b77cf9f37195e5c8c04d19999d828706b6fad344f775ccdc17a60de507f3d4c866ea2d38e37ceae749038c56962e258f84683149948aded24e461c5b682c68efcfa263e631eca06453c926e39ed0443aa4de6b70dbb13061114b44d2f10f7e0b4be5f31559764f1f92175029164e19f595712bdbc51aad5d445537aa392d543e719fb167267d62d933e96286698f39ef7c370adfafd423f95fff9112eabde6eca5efb5b107fa3e8f9c7147628ccfedadb03b9e43712a88505dfe620f1eb6610fcdf4fcefcd20ec4f429d8f2dd17e8a6248b982ebc2ddf663ad7f90af22fb325534505995e555c53ae80e26240ff844a0f71050ef6b6ddb5b88c551f9759950622bc9a012006224f0d4e5cbdf118293190c74f4f9e5617d445e145a24cb19061c0bff7223b77bee96b7fbe89feef5b255ffda27df3a975cf57757974f591b5abadb0138e3d2fcc522beb9c2da51d94470e3f25a58b75d7ad01041bec72c021f6737741f1360ba0c2d269d35b0fb81b75a7cb855372a1f8e0494614db52cf04719ad78f0c427eb23ee3c8efe797364b94ea11c643db1aa3c01a2b16c46a888c6472b41648b74b829211e9f55d3c175e57906155a6174ac164345fed374dc4b1721732258f742dbd4ab0bee777c4f2b6781cda1ed0d90da21c9c11e85749833ad143c3c65231bb3e39325a7799342dea78e055383789d6136d12620caea3ecda8ed3"); + genesis = CreateGenesisBlock( + 1506883264, + uint256S("0x0000000000000000000000000000000000000000000000000000000000000007"), + ParseHex("00e76338efc84e87b18b92ae132b31a6ff581ff89f1aeacf5c650f46ba9b6db78640fbb7f1ebf417ac890f747e4965f231ad966795d88eb3fab219fcb91d664b24e26d62e6572bc28289d058fcad472cc91ce83102560a46f8c2bef9f3865407beff0d3de381d0c0330f0e10fa1b052c495a9a2669edf9a385ab18359ed61953dc000c870899653ee2b391bd5930cc134e1bea41cb64bae2262cb186b12613df6098c9a062ff23690367c5698159c7aae04e03fcad58686e0cda1223da0cd4aeb761628f77999a52e1b1d58dee4c5f1d283c18d4264e5ebb73b5e8a241905ab2a38097157508902b9ede96e32ccf27bd5fa41cdaf65eed6ff54e26340726d8abdb207363e176c29798a9b5e94b0eab5a56076b95a24659daa7cbfd70897f06c891a5b673e98c29638ed5fcdecacfa4cf3b30a47413c71b1a5b57c240ae3cd001a9753b8e0af92cddeea7f28edffb3ae304e307e83ad7d4ed899972f1a4d8b98d8ec0bee6b40e594c15936b9d89c2e1c485087cae539d97bea3a14537daa89dabd5dfb45ea7266def7baafcbf5a6a3150f506d810333a2da6d8eb4f2e6de036dce45d95880612bfcbe9e446a954c133746f7cc5deebb27b21e8199603ec0eb0ee41d2c0a22f1363622ccfe672bfd00d566cdfdc4c4555ea3baa9662eae5ef399ebb345042ad4a607fd78c615484b66746eb2e56edf07b79c9077df6370fa17d91f8c4036fc3afb7b2065598a169142f12c75725986b3d7b33768fcb87de68ecfa924308cea135fb0feb5121d82538dd5378425beedcc36c21d8266e6c1c6147dd22c27f90a80f2cf8b5160f830785250422b51857cdf6b1d5851a08126dbebc957a0816a4f914a4a02b48e813f64745fcf1093a6cf9660f3d7e556c87fb55d98d420fe02497d11dbf5191310f7abe28d8c7ebb28f7ae702d0d34de236e11ecbcd028008c78821db534c8f36e6ff633d8eb73057967a0bf41b9b0dc3af5856e6325522513279924fba9d61035bce23c89d39151d4a907e0b9b407dc5c3daae4c0f3f4c996d4de800b696a285edc2d13d33616bc33d14fb15900f97b6f9b8c83326471f12c540829581f14e814ec121a922f9bf10e9f8ba7359d6be99fc8a3d2b65d3a691f22e45af9a84ce0332930944fe4ad535634e9c65af25c0a1ca965a3f9b77cf9f37195e5c8c04d19999d828706b6fad344f775ccdc17a60de507f3d4c866ea2d38e37ceae749038c56962e258f84683149948aded24e461c5b682c68efcfa263e631eca06453c926e39ed0443aa4de6b70dbb13061114b44d2f10f7e0b4be5f31559764f1f92175029164e19f595712bdbc51aad5d445537aa392d543e719fb167267d62d933e96286698f39ef7c370adfafd423f95fff9112eabde6eca5efb5b107fa3e8f9c7147628ccfedadb03b9e43712a88505dfe620f1eb6610fcdf4fcefcd20ec4f429d8f2dd17e8a6248b982ebc2ddf663ad7f90af22fb325534505995e555c53ae80e26240ff844a0f71050ef6b6ddb5b88c551f9759950622bc9a012006224f0d4e5cbdf118293190c74f4f9e5617d445e145a24cb19061c0bff7223b77bee96b7fbe89feef5b255ffda27df3a975cf57757974f591b5abadb0138e3d2fcc522beb9c2da51d94470e3f25a58b75d7ad01041bec72c021f6737741f1360ba0c2d269d35b0fb81b75a7cb855372a1f8e0494614db52cf04719ad78f0c427eb23ee3c8efe797364b94ea11c643db1aa3c01a2b16c46a888c6472b41648b74b829211e9f55d3c175e57906155a6174ac164345fed374dc4b1721732258f742dbd4ab0bee777c4f2b6781cda1ed0d90da21c9c11e85749833ad143c3c65231bb3e39325a7799342dea78e055383789d6136d12620caea3ecda8ed3"), + 0x2007ffff, 4, 0); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x" + consensus.hashGenesisBlock.ToString())); + assert(genesis.hashMerkleRoot == uint256S("0x830539f9ec196f36a2759638b674a51b668eba7bbf6af10c56fed4af666be177")); vFixedSeeds.clear(); vSeeds.clear(); @@ -257,7 +315,7 @@ public: fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = true; - checkpointData = (Checkpoints::CCheckpointData) { + checkpointData = (CCheckpointData) { boost::assign::map_list_of (0, consensus.hashGenesisBlock), 1506883264, // * UNIX timestamp of last checkpoint block @@ -289,7 +347,7 @@ static CTestNetParams testNetParams; /** * Regression test */ -class CRegTestParams : public CTestNetParams { +class CRegTestParams : public CChainParams { public: CRegTestParams() { strNetworkID = "regtest"; @@ -301,27 +359,41 @@ public: consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + consensus.nPowAveragingWindow = 17; assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up + consensus.nPowTargetSpacing = 2.5 * 60; + consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; + consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = + Consensus::NetworkUpgrade::ALWAYS_ACTIVE; + consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nProtocolVersion = 170002; + consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170003; + consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + pchMessageStart[0] = 0xaa; pchMessageStart[1] = 0xe8; pchMessageStart[2] = 0x3f; pchMessageStart[3] = 0x5f; - //nMinerThreads = 1; + nDefaultPort = 18444; nMaxTipAge = 24 * 60 * 60; + nPruneAfterHeight = 1000; const size_t N = 48, K = 5; BOOST_STATIC_ASSERT(equihash_parameters_acceptable(N, K)); nEquihashN = N; nEquihashK = K; - genesis.nTime = 1519568466; - genesis.nBits = 0x200f0f0f; - genesis.nNonce = uint256S("0x0000000000000000000000000000000000000000000000000000000000000016"); - genesis.nSolution = ParseHex("0d1d1ef025037da781252f695ff279c12d492c5ed53e565c8ecdc044ede53cea96cff5fc"); + + genesis = CreateGenesisBlock( + 1519568466, + uint256S("0x0000000000000000000000000000000000000000000000000000000000000016"), + ParseHex("0d1d1ef025037da781252f695ff279c12d492c5ed53e565c8ecdc044ede53cea96cff5fc"), + 0x200f0f0f, 4, 0); consensus.hashGenesisBlock = genesis.GetHash(); - nDefaultPort = 18444; assert(consensus.hashGenesisBlock == uint256S("0x0379ff1530af893f2f2e61146db6e900dd828dc8254215b9de23df2dba06664f")); - nPruneAfterHeight = 1000; + assert(genesis.hashMerkleRoot == uint256S("0x830539f9ec196f36a2759638b674a51b668eba7bbf6af10c56fed4af666be177")); vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. @@ -332,18 +404,34 @@ public: fMineBlocksOnDemand = true; fTestnetToBeDeprecatedFieldRPC = false; - checkpointData = (Checkpoints::CCheckpointData){ + checkpointData = (CCheckpointData){ boost::assign::map_list_of ( 0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")), 0, 0, 0 }; + // These prefixes are the same as the testnet prefixes + base58Prefixes[PUBKEY_ADDRESS] = {0x1D,0x25}; + base58Prefixes[SCRIPT_ADDRESS] = {0x1C,0xBA}; + base58Prefixes[SECRET_KEY] = {0xEF}; + // do not rely on these BIP32 prefixes; they are not specified and may change + base58Prefixes[EXT_PUBLIC_KEY] = {0x04,0x35,0x87,0xCF}; + base58Prefixes[EXT_SECRET_KEY] = {0x04,0x35,0x83,0x94}; + base58Prefixes[ZCPAYMENT_ADDRRESS] = {0x16,0xB6}; + base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; + base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" }; assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight()); } + + void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight) + { + assert(idx > Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES); + consensus.vUpgrades[idx].nActivationHeight = nActivationHeight; + } }; static CRegTestParams regTestParams; @@ -408,7 +496,7 @@ CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const { CBitcoinAddress address(GetFoundersRewardAddressAtHeight(nHeight).c_str()); assert(address.IsValid()); assert(address.IsScript()); - CScriptID scriptID = get(address.Get()); // Get() returns a boost variant + CScriptID scriptID = boost::get(address.Get()); // Get() returns a boost variant CScript script = CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; return script; } @@ -417,3 +505,8 @@ std::string CChainParams::GetFoundersRewardAddressAtIndex(int i) const { assert(i >= 0 && i < vFoundersRewardAddress.size()); return vFoundersRewardAddress[i]; } + +void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight) +{ + regTestParams.UpdateNetworkUpgradeParameters(idx, nActivationHeight); +} diff --git a/src/chainparams.h b/src/chainparams.h index 0de8d01b5..f1d9b43c3 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -7,7 +7,6 @@ #define BITCOIN_CHAINPARAMS_H #include "chainparamsbase.h" -#include "checkpoints.h" #include "consensus/params.h" #include "primitives/block.h" #include "protocol.h" @@ -24,6 +23,14 @@ struct SeedSpec6 { uint16_t port; }; +typedef std::map MapCheckpoints; + +struct CCheckpointData { + MapCheckpoints mapCheckpoints; + int64_t nTimeLastCheckpoint; + int64_t nTransactionsLastCheckpoint; + double fTransactionsPerDay; +}; /** * CChainParams defines various tweakable parameters of a given instance of the @@ -75,7 +82,7 @@ public: const std::vector& DNSSeeds() const { return vSeeds; } const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } const std::vector& FixedSeeds() const { return vFixedSeeds; } - const Checkpoints::CCheckpointData& Checkpoints() const { return checkpointData; } + const CCheckpointData& Checkpoints() const { return checkpointData; } /** Return the founder's reward address and script for a given block height */ std::string GetFoundersRewardAddressAtHeight(int height) const; CScript GetFoundersRewardScriptAtHeight(int height) const; @@ -105,7 +112,7 @@ protected: bool fRequireStandard = false; bool fMineBlocksOnDemand = false; bool fTestnetToBeDeprecatedFieldRPC = false; - Checkpoints::CCheckpointData checkpointData; + CCheckpointData checkpointData; std::vector vFoundersRewardAddress; }; @@ -127,4 +134,9 @@ void SelectParams(CBaseChainParams::Network network); */ bool SelectParamsFromCommandLine(); +/** + * Allows modifying the network upgrade regtest parameters. + */ +void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight); + #endif // BITCOIN_CHAINPARAMS_H diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 180a4b0ad..750b22f39 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -25,7 +25,7 @@ static CBaseMainParams mainParams; /** * Testnet (v4) */ -class CBaseTestNetParams : public CBaseMainParams +class CBaseTestNetParams : public CBaseChainParams { public: CBaseTestNetParams() @@ -39,11 +39,12 @@ static CBaseTestNetParams testNetParams; /* * Regression test */ -class CBaseRegTestParams : public CBaseTestNetParams +class CBaseRegTestParams : public CBaseChainParams { public: CBaseRegTestParams() { + nRPCPort = 18822; strDataDir = "regtest"; } }; diff --git a/src/checkpoints.h b/src/checkpoints.h index 001e3cc80..5fce6fa81 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -10,6 +10,7 @@ #include class CBlockIndex; +struct CCheckpointData; /** * Block-chain checkpoints are compiled-in sanity checks. @@ -17,14 +18,6 @@ class CBlockIndex; */ namespace Checkpoints { -typedef std::map MapCheckpoints; - -struct CCheckpointData { - MapCheckpoints mapCheckpoints; - int64_t nTimeLastCheckpoint; - int64_t nTransactionsLastCheckpoint; - double fTransactionsPerDay; -}; //! Return conservative estimate of total number of blocks, 0 if unknown int GetTotalBlocksEstimate(const CCheckpointData& data); diff --git a/src/clientversion.h b/src/clientversion.h index eb30ec550..f30bf9da9 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -18,7 +18,7 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 0 -#define CLIENT_VERSION_REVISION 14 +#define CLIENT_VERSION_REVISION 15 #define CLIENT_VERSION_BUILD 50 //! Set to true for release, false for prerelease or test build diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index d700666bc..8650c453a 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -9,7 +9,11 @@ /** The minimum allowed block version (network rule) */ static const int32_t MIN_BLOCK_VERSION = 4; /** The minimum allowed transaction version (network rule) */ -static const int32_t MIN_TX_VERSION = 1; +static const int32_t SPROUT_MIN_TX_VERSION = 1; +/** The minimum allowed transaction version (network rule) */ +static const int32_t OVERWINTER_MIN_TX_VERSION = 3; +/** The maximum allowed transaction version (network rule) */ +static const int32_t OVERWINTER_MAX_TX_VERSION = 3; /** The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = 2000000; /** The maximum allowed number of signature check operations in a block (network rule) */ @@ -18,6 +22,8 @@ static const unsigned int MAX_BLOCK_SIGOPS = 20000; static const unsigned int MAX_TX_SIZE = 100000; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; +/** The minimum value which is invalid for expiry height, used by CTransaction and CMutableTransaction */ +static constexpr uint32_t TX_EXPIRY_HEIGHT_THRESHOLD = 500000000; /** Flags for LockTime() */ enum { diff --git a/src/consensus/params.h b/src/consensus/params.h index c74e66d5f..11504dbc8 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -9,6 +9,54 @@ #include "uint256.h" namespace Consensus { + +/** + * Index into Params.vUpgrades and NetworkUpgradeInfo + * + * Being array indices, these MUST be numbered consecutively. + * + * The order of these indices MUST match the order of the upgrades on-chain, as + * several functions depends on the enum being sorted. + */ +enum UpgradeIndex { + // Sprout must be first + BASE_SPROUT, + UPGRADE_TESTDUMMY, + UPGRADE_OVERWINTER, + // NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp + MAX_NETWORK_UPGRADES +}; + +struct NetworkUpgrade { + /** + * The first protocol version which will understand the new consensus rules + */ + int nProtocolVersion; + + /** + * Height of the first block for which the new consensus rules will be active + */ + int nActivationHeight; + + /** + * Special value for nActivationHeight indicating that the upgrade is always active. + * This is useful for testing, as it means tests don't need to deal with the activation + * process (namely, faking a chain of somewhat-arbitrary length). + * + * New blockchains that want to enable upgrade rules from the beginning can also use + * this value. However, additional care must be taken to ensure the genesis block + * satisfies the enabled rules. + */ + static constexpr int ALWAYS_ACTIVE = 0; + + /** + * Special value for nActivationHeight indicating that the upgrade will never activate. + * This is useful when adding upgrade code that has a testnet activation height, but + * should remain disabled on mainnet. + */ + static constexpr int NO_ACTIVATION_HEIGHT = -1; +}; + /** * Parameters that influence chain consensus. */ @@ -39,6 +87,7 @@ struct Params { int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; int nMajorityWindow; + NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES]; /** Proof of work parameters */ uint256 powLimit; int64_t nPowAveragingWindow; diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp new file mode 100644 index 000000000..17606bc63 --- /dev/null +++ b/src/consensus/upgrades.cpp @@ -0,0 +1,124 @@ +// Copyright (c) 2018 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "consensus/upgrades.h" + +/** + * General information about each network upgrade. + * Ordered by Consensus::UpgradeIndex. + */ +const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = { + { + /*.nBranchId =*/ 0, + /*.strName =*/ "Sprout", + /*.strInfo =*/ "The Zcash network at launch", + }, + { + /*.nBranchId =*/ 0x74736554, + /*.strName =*/ "Test dummy", + /*.strInfo =*/ "Test dummy info", + }, + { + /*.nBranchId =*/ 0x5ba81b19, + /*.strName =*/ "Overwinter", + /*.strInfo =*/ "TBD", + } +}; + +UpgradeState NetworkUpgradeState( + int nHeight, + const Consensus::Params& params, + Consensus::UpgradeIndex idx) +{ + assert(nHeight >= 0); + assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES); + auto nActivationHeight = params.vUpgrades[idx].nActivationHeight; + + if (nActivationHeight == Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { + return UPGRADE_DISABLED; + } else if (nHeight >= nActivationHeight) { + // From ZIP 200: + // + // ACTIVATION_HEIGHT + // The non-zero block height at which the network upgrade rules will come + // into effect, and be enforced as part of the blockchain consensus. + // + // For removal of ambiguity, the block at height ACTIVATION_HEIGHT - 1 is + // subject to the pre-upgrade consensus rules, and would be the last common + // block in the event of a persistent pre-upgrade branch. + return UPGRADE_ACTIVE; + } else { + return UPGRADE_PENDING; + } +} + +bool NetworkUpgradeActive( + int nHeight, + const Consensus::Params& params, + Consensus::UpgradeIndex idx) +{ + return NetworkUpgradeState(nHeight, params, idx) == UPGRADE_ACTIVE; +} + +int CurrentEpoch(int nHeight, const Consensus::Params& params) { + for (auto idxInt = Consensus::MAX_NETWORK_UPGRADES - 1; idxInt >= Consensus::BASE_SPROUT; idxInt--) { + if (NetworkUpgradeActive(nHeight, params, Consensus::UpgradeIndex(idxInt))) { + return idxInt; + } + } +} + +uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params) { + return NetworkUpgradeInfo[CurrentEpoch(nHeight, params)].nBranchId; +} + +bool IsActivationHeight( + int nHeight, + const Consensus::Params& params, + Consensus::UpgradeIndex idx) +{ + assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES); + + // Don't count Sprout as an activation height + if (idx == Consensus::BASE_SPROUT) { + return false; + } + + return nHeight >= 0 && nHeight == params.vUpgrades[idx].nActivationHeight; +} + +bool IsActivationHeightForAnyUpgrade( + int nHeight, + const Consensus::Params& params) +{ + if (nHeight < 0) { + return false; + } + + // Don't count Sprout as an activation height + for (int idx = Consensus::BASE_SPROUT + 1; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) { + if (nHeight == params.vUpgrades[idx].nActivationHeight) + return true; + } + + return false; +} + +boost::optional NextActivationHeight( + int nHeight, + const Consensus::Params& params) +{ + if (nHeight < 0) { + return boost::none; + } + + // Don't count Sprout as an activation height + for (auto idx = Consensus::BASE_SPROUT + 1; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) { + if (NetworkUpgradeState(nHeight, params, Consensus::UpgradeIndex(idx)) == UPGRADE_PENDING) { + return params.vUpgrades[idx].nActivationHeight; + } + } + + return boost::none; +} diff --git a/src/consensus/upgrades.h b/src/consensus/upgrades.h new file mode 100644 index 000000000..6a9173264 --- /dev/null +++ b/src/consensus/upgrades.h @@ -0,0 +1,90 @@ +// Copyright (c) 2018 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ZCASH_CONSENSUS_UPGRADES_H +#define ZCASH_CONSENSUS_UPGRADES_H + +#include "consensus/params.h" + +#include + +enum UpgradeState { + UPGRADE_DISABLED, + UPGRADE_PENDING, + UPGRADE_ACTIVE +}; + +struct NUInfo { + /** Branch ID (a random non-zero 32-bit value) */ + uint32_t nBranchId; + /** User-facing name for the upgrade */ + std::string strName; + /** User-facing information string about the upgrade */ + std::string strInfo; +}; + +extern const struct NUInfo NetworkUpgradeInfo[]; + +// Consensus branch id to identify pre-overwinter (Sprout) consensus rules. +static const uint32_t SPROUT_BRANCH_ID = NetworkUpgradeInfo[Consensus::BASE_SPROUT].nBranchId; + +/** + * Checks the state of a given network upgrade based on block height. + * Caller must check that the height is >= 0 (and handle unknown heights). + */ +UpgradeState NetworkUpgradeState( + int nHeight, + const Consensus::Params& params, + Consensus::UpgradeIndex idx); + +/** + * Returns true if the given network upgrade is active as of the given block + * height. Caller must check that the height is >= 0 (and handle unknown + * heights). + */ +bool NetworkUpgradeActive( + int nHeight, + const Consensus::Params& params, + Consensus::UpgradeIndex idx); + +/** + * Returns the index of the most recent upgrade as of the given block height + * (corresponding to the current "epoch"). Consensus::BASE_SPROUT is the + * default value if no upgrades are active. Caller must check that the height + * is >= 0 (and handle unknown heights). + */ +int CurrentEpoch(int nHeight, const Consensus::Params& params); + +/** + * Returns the branch ID of the most recent upgrade as of the given block height + * (corresponding to the current "epoch"), or 0 if no upgrades are active. + * Caller must check that the height is >= 0 (and handle unknown heights). + */ +uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params); + +/** + * Returns true if the given block height is the activation height for the given + * upgrade. + */ +bool IsActivationHeight( + int nHeight, + const Consensus::Params& params, + Consensus::UpgradeIndex upgrade); + +/** + * Returns true if the given block height is the activation height for any upgrade. + */ +bool IsActivationHeightForAnyUpgrade( + int nHeight, + const Consensus::Params& params); + +/** + * Returns the activation height for the next upgrade after the given block height, + * or boost::none if there are no more known upgrades. + */ +boost::optional NextActivationHeight( + int nHeight, + const Consensus::Params& params); + +#endif // ZCASH_CONSENSUS_UPGRADES_H diff --git a/src/gtest/test_upgrades.cpp b/src/gtest/test_upgrades.cpp new file mode 100644 index 000000000..1066a28d0 --- /dev/null +++ b/src/gtest/test_upgrades.cpp @@ -0,0 +1,173 @@ +#include + +#include "chainparams.h" +#include "consensus/upgrades.h" + +#include + +class UpgradesTest : public ::testing::Test { +protected: + virtual void SetUp() { + } + + virtual void TearDown() { + // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + } +}; + +TEST_F(UpgradesTest, NetworkUpgradeState) { + SelectParams(CBaseChainParams::REGTEST); + const Consensus::Params& params = Params().GetConsensus(); + + // Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT + EXPECT_EQ( + NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY), + UPGRADE_DISABLED); + EXPECT_EQ( + NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY), + UPGRADE_DISABLED); + + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + + EXPECT_EQ( + NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY), + UPGRADE_ACTIVE); + EXPECT_EQ( + NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY), + UPGRADE_ACTIVE); + + int nActivationHeight = 100; + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); + + EXPECT_EQ( + NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY), + UPGRADE_PENDING); + EXPECT_EQ( + NetworkUpgradeState(nActivationHeight - 1, params, Consensus::UPGRADE_TESTDUMMY), + UPGRADE_PENDING); + EXPECT_EQ( + NetworkUpgradeState(nActivationHeight, params, Consensus::UPGRADE_TESTDUMMY), + UPGRADE_ACTIVE); + EXPECT_EQ( + NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY), + UPGRADE_ACTIVE); +} + +TEST_F(UpgradesTest, CurrentEpoch) { + SelectParams(CBaseChainParams::REGTEST); + const Consensus::Params& params = Params().GetConsensus(); + auto nBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_TESTDUMMY].nBranchId; + + // Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT + EXPECT_EQ(CurrentEpoch(0, params), Consensus::BASE_SPROUT); + EXPECT_EQ(CurrentEpochBranchId(0, params), 0); + EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::BASE_SPROUT); + EXPECT_EQ(CurrentEpochBranchId(1000000, params), 0); + + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + + EXPECT_EQ(CurrentEpoch(0, params), Consensus::UPGRADE_TESTDUMMY); + EXPECT_EQ(CurrentEpochBranchId(0, params), nBranchId); + EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::UPGRADE_TESTDUMMY); + EXPECT_EQ(CurrentEpochBranchId(1000000, params), nBranchId); + + int nActivationHeight = 100; + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); + + EXPECT_EQ(CurrentEpoch(0, params), Consensus::BASE_SPROUT); + EXPECT_EQ(CurrentEpochBranchId(0, params), 0); + EXPECT_EQ(CurrentEpoch(nActivationHeight - 1, params), Consensus::BASE_SPROUT); + EXPECT_EQ(CurrentEpochBranchId(nActivationHeight - 1, params), 0); + EXPECT_EQ(CurrentEpoch(nActivationHeight, params), Consensus::UPGRADE_TESTDUMMY); + EXPECT_EQ(CurrentEpochBranchId(nActivationHeight, params), nBranchId); + EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::UPGRADE_TESTDUMMY); + EXPECT_EQ(CurrentEpochBranchId(1000000, params), nBranchId); +} + +TEST_F(UpgradesTest, IsActivationHeight) { + SelectParams(CBaseChainParams::REGTEST); + const Consensus::Params& params = Params().GetConsensus(); + + // Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT + EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY)); + + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + + EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_TRUE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY)); + + int nActivationHeight = 100; + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); + + EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(nActivationHeight - 1, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_TRUE(IsActivationHeight(nActivationHeight, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(nActivationHeight + 1, params, Consensus::UPGRADE_TESTDUMMY)); + EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY)); +} + +TEST_F(UpgradesTest, IsActivationHeightForAnyUpgrade) { + SelectParams(CBaseChainParams::REGTEST); + const Consensus::Params& params = Params().GetConsensus(); + + // Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(0, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params)); + + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params)); + EXPECT_TRUE(IsActivationHeightForAnyUpgrade(0, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params)); + + int nActivationHeight = 100; + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); + + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(0, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(nActivationHeight - 1, params)); + EXPECT_TRUE(IsActivationHeightForAnyUpgrade(nActivationHeight, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(nActivationHeight + 1, params)); + EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params)); +} + +TEST_F(UpgradesTest, NextActivationHeight) { + SelectParams(CBaseChainParams::REGTEST); + const Consensus::Params& params = Params().GetConsensus(); + + // Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT + EXPECT_EQ(NextActivationHeight(-1, params), boost::none); + EXPECT_EQ(NextActivationHeight(0, params), boost::none); + EXPECT_EQ(NextActivationHeight(1, params), boost::none); + EXPECT_EQ(NextActivationHeight(1000000, params), boost::none); + + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + + EXPECT_EQ(NextActivationHeight(-1, params), boost::none); + EXPECT_EQ(NextActivationHeight(0, params), boost::none); + EXPECT_EQ(NextActivationHeight(1, params), boost::none); + EXPECT_EQ(NextActivationHeight(1000000, params), boost::none); + + int nActivationHeight = 100; + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); + + EXPECT_EQ(NextActivationHeight(-1, params), boost::none); + EXPECT_EQ(NextActivationHeight(0, params), nActivationHeight); + EXPECT_EQ(NextActivationHeight(1, params), nActivationHeight); + EXPECT_EQ(NextActivationHeight(nActivationHeight - 1, params), nActivationHeight); + EXPECT_EQ(NextActivationHeight(nActivationHeight, params), boost::none); + EXPECT_EQ(NextActivationHeight(nActivationHeight + 1, params), boost::none); + EXPECT_EQ(NextActivationHeight(1000000, params), boost::none); +} diff --git a/src/hash.h b/src/hash.h index 077155562..06fcced0a 100644 --- a/src/hash.h +++ b/src/hash.h @@ -12,6 +12,8 @@ #include "uint256.h" #include "version.h" +#include "sodium.h" + #include typedef uint256 ChainCode; @@ -150,6 +152,47 @@ public: } }; + +/** A writer stream (for serialization) that computes a 256-bit BLAKE2b hash. */ +class CBLAKE2bWriter +{ +private: + crypto_generichash_blake2b_state state; + +public: + int nType; + int nVersion; + + CBLAKE2bWriter(int nTypeIn, int nVersionIn, const unsigned char* personal) : nType(nTypeIn), nVersion(nVersionIn) { + assert(crypto_generichash_blake2b_init_salt_personal( + &state, + NULL, 0, // No key. + 32, + NULL, // No salt. + personal) == 0); + } + + CBLAKE2bWriter& write(const char *pch, size_t size) { + crypto_generichash_blake2b_update(&state, (const unsigned char*)pch, size); + return (*this); + } + + // invalidates the object + uint256 GetHash() { + uint256 result; + crypto_generichash_blake2b_final(&state, (unsigned char*)&result, 32); + return result; + } + + template + CBLAKE2bWriter& operator<<(const T& obj) { + // Serialize to this stream + ::Serialize(*this, obj, nType, nVersion); + return (*this); + } +}; + + /** Compute the 256-bit hash of an object's serialization. */ template uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) diff --git a/src/init.cpp b/src/init.cpp index 92161d51c..9a3ba45a7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -17,6 +17,7 @@ #endif #include "checkpoints.h" #include "compat/sanity.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #include "httpserver.h" #include "httprpc.h" @@ -47,8 +48,10 @@ #include #endif +#include #include #include +#include #include #include #include @@ -457,6 +460,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0)); strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1)); strUsage += HelpMessageOpt("-txconfirmtarget=", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); + strUsage += HelpMessageOpt("-txexpirydelta", strprintf(_("Set the number of blocks after which a transaction that has not been mined will become invalid (default: %u)"), DEFAULT_TX_EXPIRY_DELTA)); strUsage += HelpMessageOpt("-maxtxfee=", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"), CURRENCY_UNIT, FormatMoney(maxTxFee))); strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup")); @@ -494,6 +498,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-fuzzmessagestest=", "Randomly fuzz 1 of every network messages"); 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)); + strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)"); } string debugCategories = "addrman, alert, bench, coindb, db, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, " "rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these @@ -840,6 +845,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } else if (mapArgs.count("-paymentdisclosure")) { return InitError(_("Payment disclosure requires -experimentalfeatures.")); + } else if (mapArgs.count("-zmergetoaddress")) { + return InitError(_("RPC method z_mergetoaddress requires -experimentalfeatures.")); } } @@ -961,7 +968,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench.")); // Checkmempool and checkblockindex default to true in regtest mode - mempool.setSanityCheck(GetBoolArg("-checkmempool", chainparams.DefaultConsistencyChecks())); + int ratio = std::min(std::max(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); + if (ratio != 0) { + mempool.setSanityCheck(1.0 / ratio); + } fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); fCheckpointsEnabled = GetBoolArg("-checkpoints", true); @@ -1051,6 +1061,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); + expiryDelta = GetArg("-txexpirydelta", DEFAULT_TX_EXPIRY_DELTA); bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", true); fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false); @@ -1086,6 +1097,38 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } + if (!mapMultiArgs["-nuparams"].empty()) { + // Allow overriding network upgrade parameters for testing + if (Params().NetworkIDString() != "regtest") { + return InitError("Network upgrade parameters may only be overridden on regtest."); + } + const vector& deployments = mapMultiArgs["-nuparams"]; + for (auto i : deployments) { + std::vector vDeploymentParams; + boost::split(vDeploymentParams, i, boost::is_any_of(":")); + if (vDeploymentParams.size() != 2) { + return InitError("Network upgrade parameters malformed, expecting hexBranchId:activationHeight"); + } + int nActivationHeight; + if (!ParseInt32(vDeploymentParams[1], &nActivationHeight)) { + return InitError(strprintf("Invalid nActivationHeight (%s)", vDeploymentParams[1])); + } + bool found = false; + // Exclude Sprout from upgrades + for (auto i = Consensus::BASE_SPROUT + 1; i < Consensus::MAX_NETWORK_UPGRADES; ++i) + { + if (vDeploymentParams[0].compare(HexInt(NetworkUpgradeInfo[i].nBranchId)) == 0) { + UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex(i), nActivationHeight); + found = true; + LogPrintf("Setting network upgrade activation parameters for %s to height=%d\n", vDeploymentParams[0], nActivationHeight); + break; + } + } + if (!found) { + return InitError(strprintf("Invalid network upgrade (%s)", vDeploymentParams[0])); + } + } + } // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log @@ -1470,6 +1513,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) break; } + if (!fReindex) { + uiInterface.InitMessage(_("Rewinding blocks if needed...")); + if (!RewindBlockIndex(chainparams)) { + strLoadError = _("Unable to rewind the database to a pre-upgrade state. You will need to redownload the blockchain"); + break; + } + } + uiInterface.InitMessage(_("Verifying blocks...")); if (fHavePruned && GetArg("-checkblocks", 288) > MIN_BLOCKS_TO_KEEP) { LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n", diff --git a/src/key.cpp b/src/key.cpp index d6c0d25f0..8303c1101 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -85,16 +85,13 @@ static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *ou * . The optional parameters and publicKey fields are * included. * - * privkey must point to an output buffer of length at least PRIVATE_KEY_SIZE bytes. + * privkey must point to an output buffer of length at least CKey::PRIVATE_KEY_SIZE bytes. * privkeylen must initially be set to the size of the privkey buffer. Upon return it * will be set to the number of bytes used in the buffer. * key32 must point to a 32-byte raw private key. */ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { - assert(*privkeylen >= PRIVATE_KEY_SIZE); - static_assert( - PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE, - "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE"); + assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE); secp256k1_pubkey pubkey; size_t pubkeylen = 0; if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { @@ -120,11 +117,11 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); memcpy(ptr, key32, 32); ptr += 32; memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - pubkeylen = COMPRESSED_PUBLIC_KEY_SIZE; + pubkeylen = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE; secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); ptr += pubkeylen; *privkeylen = ptr - privkey; - assert(*privkeylen == COMPRESSED_PRIVATE_KEY_SIZE); + assert(*privkeylen == CKey::COMPRESSED_PRIVATE_KEY_SIZE); } else { static const unsigned char begin[] = { 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 @@ -146,11 +143,11 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); memcpy(ptr, key32, 32); ptr += 32; memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - pubkeylen = PUBLIC_KEY_SIZE; + pubkeylen = CPubKey::PUBLIC_KEY_SIZE; secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); ptr += pubkeylen; *privkeylen = ptr - privkey; - assert(*privkeylen == PRIVATE_KEY_SIZE); + assert(*privkeylen == CKey::PRIVATE_KEY_SIZE); } return 1; } @@ -191,7 +188,7 @@ CPrivKey CKey::GetPrivKey() const { CPubKey CKey::GetPubKey() const { assert(fValid); secp256k1_pubkey pubkey; - size_t clen = PUBLIC_KEY_SIZE; + size_t clen = CPubKey::PUBLIC_KEY_SIZE; CPubKey result; int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); assert(ret); @@ -204,8 +201,8 @@ CPubKey CKey::GetPubKey() const { bool CKey::Sign(const uint256 &hash, std::vector& vchSig, uint32_t test_case) const { if (!fValid) return false; - vchSig.resize(SIGNATURE_SIZE); - size_t nSigLen = SIGNATURE_SIZE; + vchSig.resize(CPubKey::SIGNATURE_SIZE); + size_t nSigLen = CPubKey::SIGNATURE_SIZE; unsigned char extra_entropy[32] = {0}; WriteLE32(extra_entropy, test_case); secp256k1_ecdsa_signature sig; @@ -233,7 +230,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const { bool CKey::SignCompact(const uint256 &hash, std::vector& vchSig) const { if (!fValid) return false; - vchSig.resize(COMPACT_SIGNATURE_SIZE); + vchSig.resize(CPubKey::COMPACT_SIGNATURE_SIZE); int rec = -1; secp256k1_ecdsa_recoverable_signature sig; int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, NULL); @@ -264,7 +261,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const LockObject(out); if ((nChild >> 31) == 0) { CPubKey pubkey = GetPubKey(); - assert(pubkey.size() == COMPRESSED_PUBLIC_KEY_SIZE); + assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, out); } else { assert(size() == 32); diff --git a/src/key.h b/src/key.h index 292769098..c2b75935c 100644 --- a/src/key.h +++ b/src/key.h @@ -16,16 +16,6 @@ #include -/** - * secp256k1: - */ -const unsigned int PRIVATE_KEY_SIZE = 279; -const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214; -/** - * see www.keylength.com - * script supports up to 75 for single byte push - */ - /** * secure_allocator is defined in allocators.h * CPrivKey is a serialized private key, with all parameters included @@ -36,6 +26,20 @@ typedef std::vector > CPrivKey; /** An encapsulated private key. */ class CKey { +public: + /** + * secp256k1: + */ + static const unsigned int PRIVATE_KEY_SIZE = 279; + static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214; + /** + * see www.keylength.com + * script supports up to 75 for single byte push + */ + static_assert( + PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE, + "COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE"); + private: //! Whether this private key is valid. We check for correctness when modifying the key //! data, so fValid should always correspond to the actual state. diff --git a/src/main.cpp b/src/main.cpp index e0e6b6386..68ee59753 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #include "deprecation.h" #include "init.h" @@ -78,6 +79,8 @@ size_t nCoinCacheUsage = 5000 * 300; uint64_t nPruneTarget = 0; bool fAlerts = DEFAULT_ALERTS; +unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA; + /** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); @@ -549,6 +552,9 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc CBlockIndex* pindex = (*mi).second; if (chain.Contains(pindex)) return pindex; + if (pindex->GetAncestor(chain.Height()) == chain.Tip()) { + return chain.Tip(); + } } } return chain.Genesis(); @@ -643,16 +649,22 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE } - - - - - -bool IsStandardTx(const CTransaction& tx, string& reason) +bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight) { - if (tx.nVersion > CTransaction::MAX_CURRENT_VERSION || tx.nVersion < CTransaction::MIN_CURRENT_VERSION) { - reason = "version"; - return false; + bool isOverwinter = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); + + if (isOverwinter) { + // Overwinter standard rules apply + if (tx.nVersion > CTransaction::OVERWINTER_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::OVERWINTER_MIN_CURRENT_VERSION) { + reason = "overwinter-version"; + return false; + } + } else { + // Sprout standard rules apply + if (tx.nVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION) { + reason = "version"; + return false; + } } BOOST_FOREACH(const CTxIn& txin, tx.vin) @@ -714,6 +726,14 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) return true; } +bool IsExpiredTx(const CTransaction &tx, int nBlockHeight) +{ + if (tx.nExpiryHeight == 0 || tx.IsCoinBase()) { + return false; + } + return static_cast(nBlockHeight) > tx.nExpiryHeight; +} + bool CheckFinalTx(const CTransaction &tx, int flags) { AssertLockHeld(cs_main); @@ -754,7 +774,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) * 2. P2SH scripts with a crazy number of expensive * CHECKSIG/CHECKMULTISIG operations */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId) { if (tx.IsCoinBase()) return true; // Coinbases don't use vin normally @@ -780,7 +800,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) // IsStandardTx() will have already returned false // and this method isn't called. vector > stack; - if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker())) + if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId)) return false; if (whichType == TX_SCRIPTHASH) @@ -842,6 +862,79 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in return nSigOps; } +/** + * Check a transaction contextually against a set of consensus rules valid at a given block height. + * + * Notes: + * 1. AcceptToMemoryPool calls CheckTransaction and this function. + * 2. ProcessNewBlock calls AcceptBlock, which calls CheckBlock (which calls CheckTransaction) + * and ContextualCheckBlock (which calls this function). + */ +bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, const int nHeight, const int dosLevel) +{ + bool isOverwinter = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); + bool isSprout = !isOverwinter; + + // If Sprout rules apply, reject transactions which are intended for Overwinter and beyond + if (isSprout && tx.fOverwintered) { + return state.DoS(dosLevel, error("ContextualCheckTransaction(): overwinter is not active yet"), + REJECT_INVALID, "tx-overwinter-not-active"); + } + + // If Overwinter rules apply: + if (isOverwinter) { + // Reject transactions with valid version but missing overwinter flag + if (tx.nVersion >= OVERWINTER_MIN_TX_VERSION && !tx.fOverwintered) { + return state.DoS(dosLevel, error("ContextualCheckTransaction(): overwinter flag must be set"), + REJECT_INVALID, "tx-overwinter-flag-not-set"); + } + + // Reject transactions with invalid version + if (tx.fOverwintered && tx.nVersion > OVERWINTER_MAX_TX_VERSION ) { + return state.DoS(100, error("CheckTransaction(): overwinter version too high"), + REJECT_INVALID, "bad-tx-overwinter-version-too-high"); + } + + // Reject transactions intended for Sprout + if (!tx.fOverwintered) { + return state.DoS(dosLevel, error("ContextualCheckTransaction: overwinter is active"), + REJECT_INVALID, "tx-overwinter-active"); + } + + // Check that all transactions are unexpired + if (IsExpiredTx(tx, nHeight)) { + return state.DoS(dosLevel, error("ContextualCheckTransaction(): transaction is expired"), REJECT_INVALID, "tx-overwinter-expired"); + } + } + + if (!(tx.IsCoinBase() || tx.vjoinsplit.empty())) { + auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); + // Empty output script. + CScript scriptCode; + uint256 dataToBeSigned; + try { + dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + } catch (std::logic_error ex) { + return state.DoS(100, error("CheckTransaction(): error computing signature hash"), + REJECT_INVALID, "error-computing-signature-hash"); + } + + BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32); + + // We rely on libsodium to check that the signature is canonical. + // https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0 + if (crypto_sign_verify_detached(&tx.joinSplitSig[0], + dataToBeSigned.begin(), 32, + tx.joinSplitPubKey.begin() + ) != 0) { + return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"), + REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); + } + } + return true; +} + + bool CheckTransaction(const CTransaction& tx, CValidationState &state, libzcash::ProofVerifier& verifier) { @@ -868,11 +961,46 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio { // Basic checks that don't depend on any context - // Check transaction version - if (tx.nVersion < MIN_TX_VERSION) { + /** + * Previously: + * 1. The consensus rule below was: + * if (tx.nVersion < SPROUT_MIN_TX_VERSION) { ... } + * which checked if tx.nVersion fell within the range: + * INT32_MIN <= tx.nVersion < SPROUT_MIN_TX_VERSION + * 2. The parser allowed tx.nVersion to be negative + * + * Now: + * 1. The consensus rule checks to see if tx.Version falls within the range: + * 0 <= tx.nVersion < SPROUT_MIN_TX_VERSION + * 2. The previous consensus rule checked for negative values within the range: + * INT32_MIN <= tx.nVersion < 0 + * This is unnecessary for Overwinter transactions since the parser now + * interprets the sign bit as fOverwintered, so tx.nVersion is always >=0, + * and when Overwinter is not active ContextualCheckTransaction rejects + * transactions with fOverwintered set. When fOverwintered is set, + * this function and ContextualCheckTransaction will together check to + * ensure tx.nVersion avoids the following ranges: + * 0 <= tx.nVersion < OVERWINTER_MIN_TX_VERSION + * OVERWINTER_MAX_TX_VERSION < tx.nVersion <= INT32_MAX + */ + if (!tx.fOverwintered && tx.nVersion < SPROUT_MIN_TX_VERSION) { return state.DoS(100, error("CheckTransaction(): version too low"), REJECT_INVALID, "bad-txns-version-too-low"); } + else if (tx.fOverwintered) { + if (tx.nVersion < OVERWINTER_MIN_TX_VERSION) { + return state.DoS(100, error("CheckTransaction(): overwinter version too low"), + REJECT_INVALID, "bad-tx-overwinter-version-too-low"); + } + if (tx.nVersionGroupId != OVERWINTER_VERSION_GROUP_ID) { + return state.DoS(100, error("CheckTransaction(): unknown tx version group id"), + REJECT_INVALID, "bad-tx-version-group-id"); + } + if (tx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { + return state.DoS(100, error("CheckTransaction(): expiry height is too high"), + REJECT_INVALID, "bad-tx-expiry-height-too-high"); + } + } // Transactions can contain empty `vin` and `vout` so long as // `vjoinsplit` is non-empty. @@ -999,30 +1127,6 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio if (txin.prevout.IsNull()) return state.DoS(10, error("CheckTransaction(): prevout is null"), REJECT_INVALID, "bad-txns-prevout-null"); - - if (tx.vjoinsplit.size() > 0) { - // Empty output script. - CScript scriptCode; - uint256 dataToBeSigned; - try { - dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL); - } catch (std::logic_error ex) { - return state.DoS(100, error("CheckTransaction(): error computing signature hash"), - REJECT_INVALID, "error-computing-signature-hash"); - } - - BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32); - - // We rely on libsodium to check that the signature is canonical. - // https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0 - if (crypto_sign_verify_detached(&tx.joinSplitSig[0], - dataToBeSigned.begin(), 32, - tx.joinSplitPubKey.begin() - ) != 0) { - return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"), - REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); - } - } } return true; @@ -1065,6 +1169,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (pfMissingInputs) *pfMissingInputs = false; + int nextBlockHeight = chainActive.Height() + 1; + auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus()); + // Node operator can choose to reject tx by number of transparent inputs static_assert(std::numeric_limits::max() >= std::numeric_limits::max(), "size_t too small"); size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0); @@ -1080,6 +1187,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (!CheckTransaction(tx, state, verifier)) return error("AcceptToMemoryPool: CheckTransaction failed"); + // DoS level set to 10 to be more forgiving. + // Check transaction contextually against the set of consensus rules which apply in the next block to be mined. + if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) { + return error("AcceptToMemoryPool: ContextualCheckTransaction failed"); + } + // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) return state.DoS(100, error("AcceptToMemoryPool: coinbase as individual tx"), @@ -1087,7 +1200,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; - if (Params().RequireStandard() && !IsStandardTx(tx, reason)) + if (Params().RequireStandard() && !IsStandardTx(tx, reason, nextBlockHeight)) return state.DoS(0, error("AcceptToMemoryPool: nonstandard transaction: %s", reason), REJECT_NONSTANDARD, reason); @@ -1170,7 +1283,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } // Check for non-standard pay-to-script-hash in inputs - if (Params().RequireStandard() && !AreInputsStandard(tx, view)) + if (Params().RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId)) return error("AcceptToMemoryPool: nonstandard transaction input"); // Check that the transaction doesn't have an excessive number of @@ -1190,7 +1303,23 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa CAmount nFees = nValueIn-nValueOut; double dPriority = view.GetPriority(tx, chainActive.Height()); - CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx)); + // Keep track of transactions that spend a coinbase, which we re-scan + // during reorgs to ensure COINBASE_MATURITY is still met. + bool fSpendsCoinbase = false; + BOOST_FOREACH(const CTxIn &txin, tx.vin) { + const CCoins *coins = view.AccessCoins(txin.prevout.hash); + if (coins->IsCoinBase()) { + fSpendsCoinbase = true; + break; + } + } + + // Grab the branch ID we expect this transaction to commit to. We don't + // yet know if it does, but if the entry gets added to the mempool, then + // it has passed ContextualCheckInputs and therefore this is correct. + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + + CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx), fSpendsCoinbase, consensusBranchId); unsigned int nSize = entry.GetTxSize(); // Accept a tx if it contains joinsplits and has at least the default fee specified by z_sendmany. @@ -1241,7 +1370,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus())) + PrecomputedTransactionData txdata(tx); + if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) { return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString()); } @@ -1255,7 +1385,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks, however allowing such transactions into the mempool // can be exploited as a DoS attack. - if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus())) + if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) { return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); } @@ -1642,7 +1772,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state } } -void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) +void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight) { // mark inputs spent if (!tx.IsCoinBase()) { @@ -1676,15 +1806,15 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); } -void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight) +void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) { CTxUndo txundo; - UpdateCoins(tx, state, inputs, txundo, nHeight); + UpdateCoins(tx, inputs, txundo, nHeight); } bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; - if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) { + if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) { return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error)); } return true; @@ -1767,7 +1897,17 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins } }// namespace Consensus -bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector *pvChecks) +bool ContextualCheckInputs( + const CTransaction& tx, + CValidationState &state, + const CCoinsViewCache &inputs, + bool fScriptChecks, + unsigned int flags, + bool cacheStore, + PrecomputedTransactionData& txdata, + const Consensus::Params& consensusParams, + uint32_t consensusBranchId, + std::vector *pvChecks) { if (!tx.IsCoinBase()) { @@ -1792,7 +1932,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons assert(coins); // Verify signature - CScriptCheck check(*coins, tx, i, flags, cacheStore); + CScriptCheck check(*coins, tx, i, flags, cacheStore, consensusBranchId, &txdata); if (pvChecks) { pvChecks->push_back(CScriptCheck()); check.swap(pvChecks->back()); @@ -1804,9 +1944,9 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons // arguments; if so, don't trigger DoS protection to // avoid splitting the network between upgraded and // non-upgraded nodes. - CScriptCheck check(*coins, tx, i, - flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore); - if (check()) + CScriptCheck check2(*coins, tx, i, + flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata); + if (check2()) return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } // Failures of other flags indicate a transaction that is @@ -2275,6 +2415,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin assert(tree.root() == old_tree_root); } + // Grab the consensus branch ID for the block's height + auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus()); + + std::vector txdata; + txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = block.vtx[i]; @@ -2342,11 +2487,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (nSigOps > MAX_BLOCK_SIGOPS) return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); + } + txdata.emplace_back(tx); + + if (!tx.IsCoinBase()) + { nFees += view.GetValueIn(tx)-tx.GetValueOut(); std::vector vChecks; - if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL)) + if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL)) return false; control.Add(vChecks); } @@ -2384,7 +2534,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (i > 0) { blockundo.vtxundo.push_back(CTxUndo()); } - UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); + UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) { @@ -2437,6 +2587,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin pindex->nStatus |= BLOCK_HAVE_UNDO; } + // Now that all consensus rules have been validated, set nCachedBranchId. + // Move this if BLOCK_VALID_CONSENSUS is ever altered. + static_assert(BLOCK_VALID_CONSENSUS == BLOCK_VALID_SCRIPTS, + "nCachedBranchId must be set after all consensus rules have been validated."); + if (IsActivationHeightForAnyUpgrade(pindex->nHeight, Params().GetConsensus())) { + pindex->nStatus |= BLOCK_ACTIVATES_UPGRADE; + pindex->nCachedBranchId = CurrentEpochBranchId(pindex->nHeight, chainparams.GetConsensus()); + } else if (pindex->pprev) { + pindex->nCachedBranchId = pindex->pprev->nCachedBranchId; + } + pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); setDirtyBlockIndex.insert(pindex); } @@ -2657,11 +2818,13 @@ void static UpdateTip(CBlockIndex *pindexNew) { } } -/** Disconnect chainActive's tip. */ -bool static DisconnectTip(CValidationState &state) { +/** + * Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and + * mempool.removeWithoutBranchId after this, with cs_main held. + */ +bool static DisconnectTip(CValidationState &state, bool fBare = false) { CBlockIndex *pindexDelete = chainActive.Tip(); assert(pindexDelete); - mempool.check(pcoinsTip); // Read block from disk. CBlock block; if (!ReadBlockFromDisk(block, pindexDelete)) @@ -2680,21 +2843,23 @@ bool static DisconnectTip(CValidationState &state) { // Write the chain state to disk, if necessary. if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) return false; - // Resurrect mempool transactions from the disconnected block. - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - // ignore validation errors in resurrected transactions - list removed; - CValidationState stateDummy; - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) - mempool.remove(tx, removed, true); - } - if (anchorBeforeDisconnect != anchorAfterDisconnect) { - // The anchor may not change between block disconnects, - // in which case we don't want to evict from the mempool yet! - mempool.removeWithAnchor(anchorBeforeDisconnect); - } - mempool.removeCoinbaseSpends(pcoinsTip, pindexDelete->nHeight); - mempool.check(pcoinsTip); + + if (!fBare) { + // Resurrect mempool transactions from the disconnected block. + BOOST_FOREACH(const CTransaction &tx, block.vtx) { + // ignore validation errors in resurrected transactions + list removed; + CValidationState stateDummy; + if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) + mempool.remove(tx, removed, true); + } + if (anchorBeforeDisconnect != anchorAfterDisconnect) { + // The anchor may not change between block disconnects, + // in which case we don't want to evict from the mempool yet! + mempool.removeWithAnchor(anchorBeforeDisconnect); + } + } + // Update chainActive and related variables. UpdateTip(pindexDelete->pprev); // Get the current commitment tree @@ -2719,10 +2884,10 @@ static int64_t nTimePostConnect = 0; /** * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. + * You probably want to call mempool.removeWithoutBranchId after this, with cs_main held. */ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) { assert(pindexNew->pprev == chainActive.Tip()); - mempool.check(pcoinsTip); // Read block from disk. int64_t nTime1 = GetTimeMicros(); CBlock block; @@ -2762,7 +2927,10 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * // Remove conflicting transactions from the mempool. list txConflicted; mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); - mempool.check(pcoinsTip); + + // Remove transactions that expire at new block height from mempool + mempool.removeExpired(pindexNew->nHeight); + // Update chainActive & related variables. UpdateTip(pindexNew); // Tell wallet about transactions that went from mempool @@ -2865,10 +3033,37 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo const CBlockIndex *pindexOldTip = chainActive.Tip(); const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); + // - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks. + // - If pindexMostWork is in a chain that doesn't have the same genesis block as our chain, + // then pindexFork will be null, and we would need to remove the entire chain including + // our genesis block. In practice this (probably) won't happen because of checks elsewhere. + auto reorgLength = pindexOldTip ? pindexOldTip->nHeight - (pindexFork ? pindexFork->nHeight : -1) : 0; + static_assert(MAX_REORG_LENGTH > 0, "We must be able to reorg some distance"); + if (reorgLength > MAX_REORG_LENGTH) { + auto msg = strprintf(_( + "A block chain reorganization has been detected that would roll back %d blocks! " + "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." + ), reorgLength, MAX_REORG_LENGTH) + "\n\n" + + _("Reorganization details") + ":\n" + + "- " + strprintf(_("Current tip: %s, height %d, work %s"), + pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" + + "- " + strprintf(_("New tip: %s, height %d, work %s"), + pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" + + "- " + strprintf(_("Fork point: %s, height %d"), + pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" + + _("Please help, human!"); + LogPrintf("*** %s\n", msg); + uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return false; + } + // Disconnect active blocks which are no longer in the best chain. + bool fBlocksDisconnected = false; while (chainActive.Tip() && chainActive.Tip() != pindexFork) { if (!DisconnectTip(state)) return false; + fBlocksDisconnected = true; } // Build list of new blocks to connect. @@ -2876,43 +3071,50 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo bool fContinue = true; int nHeight = pindexFork ? pindexFork->nHeight : -1; while (fContinue && nHeight != pindexMostWork->nHeight) { - // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need - // a few blocks along the way. - int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); - vpindexToConnect.clear(); - vpindexToConnect.reserve(nTargetHeight - nHeight); - CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); - while (pindexIter && pindexIter->nHeight != nHeight) { - vpindexToConnect.push_back(pindexIter); - pindexIter = pindexIter->pprev; - } - nHeight = nTargetHeight; - - // Connect new blocks. - BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { - if (state.IsInvalid()) { - // The block violates a consensus rule. - if (!state.CorruptionPossible()) - InvalidChainFound(vpindexToConnect.back()); - state = CValidationState(); - fInvalidFound = true; - fContinue = false; - break; + // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need + // a few blocks along the way. + int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); + vpindexToConnect.clear(); + vpindexToConnect.reserve(nTargetHeight - nHeight); + CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); + while (pindexIter && pindexIter->nHeight != nHeight) { + vpindexToConnect.push_back(pindexIter); + pindexIter = pindexIter->pprev; + } + nHeight = nTargetHeight; + + // Connect new blocks. + BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { + if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { + if (state.IsInvalid()) { + // The block violates a consensus rule. + if (!state.CorruptionPossible()) + InvalidChainFound(vpindexToConnect.back()); + state = CValidationState(); + fInvalidFound = true; + fContinue = false; + break; + } else { + // A system error occurred (disk space, database error, ...). + return false; + } } else { - // A system error occurred (disk space, database error, ...). - return false; - } - } else { - PruneBlockIndexCandidates(); - if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { - // We're in a better position than we were. Return temporarily to release the lock. - fContinue = false; - break; + PruneBlockIndexCandidates(); + if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { + // We're in a better position than we were. Return temporarily to release the lock. + fContinue = false; + break; + } } } } + + if (fBlocksDisconnected) { + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); } + mempool.removeWithoutBranchId( + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); + mempool.check(pcoinsTip); // Callbacks/notifications for a new best chain. if (fInvalidFound) @@ -2998,6 +3200,9 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { // ActivateBestChain considers blocks already in chainActive // unconditionally valid already, so force disconnect away from it. if (!DisconnectTip(state)) { + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + mempool.removeWithoutBranchId( + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); return false; } } @@ -3013,6 +3218,9 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { } InvalidChainFound(pindex); + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + mempool.removeWithoutBranchId( + CurrentEpochBranchId(chainActive.Tip()->nHeight + 1, Params().GetConsensus())); return true; } @@ -3367,6 +3575,12 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn // Check that all transactions are finalized BOOST_FOREACH(const CTransaction& tx, block.vtx) { + + // Check transaction contextually against consensus rules at block height + if (!ContextualCheckTransaction(tx, state, nHeight, 100)) { + return false; // Failure reason has been set in validation state object + } + int nLockTimeFlags = 0; int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) ? pindexPrev->GetMedianTimePast() @@ -3786,6 +4000,19 @@ bool static LoadBlockIndexDB() pindex->nChainSproutValue = pindex->nSproutValue; } } + // Construct in-memory chain of branch IDs. + // Relies on invariant: a block that does not activate a network upgrade + // will always be valid under the same consensus rules as its parent. + // Genesis block has a branch ID of zero by definition, but has no + // validity status because it is side-loaded into a fresh chain. + // Activation blocks will have branch IDs set (read from disk). + if (pindex->pprev) { + if (pindex->IsValid(BLOCK_VALID_CONSENSUS) && !pindex->nCachedBranchId) { + pindex->nCachedBranchId = pindex->pprev->nCachedBranchId; + } + } else { + pindex->nCachedBranchId = SPROUT_BRANCH_ID; + } if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) setBlockIndexCandidates.insert(pindex); if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) @@ -3981,6 +4208,135 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth return true; } +bool RewindBlockIndex(const CChainParams& params) +{ + LOCK(cs_main); + + // RewindBlockIndex is called after LoadBlockIndex, so at this point every block + // index will have nCachedBranchId set based on the values previously persisted + // to disk. By definition, a set nCachedBranchId means that the block was + // fully-validated under the corresponding consensus rules. Thus we can quickly + // identify whether the current active chain matches our expected sequence of + // consensus rule changes, with two checks: + // + // - BLOCK_ACTIVATES_UPGRADE is set only on blocks that activate upgrades. + // - nCachedBranchId for each block matches what we expect. + auto sufficientlyValidated = [¶ms](const CBlockIndex* pindex) { + auto consensus = params.GetConsensus(); + bool fFlagSet = pindex->nStatus & BLOCK_ACTIVATES_UPGRADE; + bool fFlagExpected = IsActivationHeightForAnyUpgrade(pindex->nHeight, consensus); + return fFlagSet == fFlagExpected && + pindex->nCachedBranchId && + *pindex->nCachedBranchId == CurrentEpochBranchId(pindex->nHeight, consensus); + }; + + int nHeight = 1; + while (nHeight <= chainActive.Height()) { + if (!sufficientlyValidated(chainActive[nHeight])) { + break; + } + nHeight++; + } + + // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1 + auto rewindLength = chainActive.Height() - nHeight; + if (rewindLength > 0 && rewindLength > MAX_REORG_LENGTH) { + auto pindexOldTip = chainActive.Tip(); + auto pindexRewind = chainActive[nHeight - 1]; + auto msg = strprintf(_( + "A block chain rewind has been detected that would roll back %d blocks! " + "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." + ), rewindLength, MAX_REORG_LENGTH) + "\n\n" + + _("Rewind details") + ":\n" + + "- " + strprintf(_("Current tip: %s, height %d"), + pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight) + "\n" + + "- " + strprintf(_("Rewinding to: %s, height %d"), + pindexRewind->phashBlock->GetHex(), pindexRewind->nHeight) + "\n\n" + + _("Please help, human!"); + LogPrintf("*** %s\n", msg); + uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return false; + } + + CValidationState state; + CBlockIndex* pindex = chainActive.Tip(); + while (chainActive.Height() >= nHeight) { + if (fPruneMode && !(chainActive.Tip()->nStatus & BLOCK_HAVE_DATA)) { + // If pruning, don't try rewinding past the HAVE_DATA point; + // since older blocks can't be served anyway, there's + // no need to walk further, and trying to DisconnectTip() + // will fail (and require a needless reindex/redownload + // of the blockchain). + break; + } + if (!DisconnectTip(state, true)) { + return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight); + } + // Occasionally flush state to disk. + if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) + return false; + } + + // Reduce validity flag and have-data flags. + // We do this after actual disconnecting, otherwise we'll end up writing the lack of data + // to disk before writing the chainstate, resulting in a failure to continue if interrupted. + for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { + CBlockIndex* pindexIter = it->second; + + // Note: If we encounter an insufficiently validated block that + // is on chainActive, it must be because we are a pruning node, and + // this block or some successor doesn't HAVE_DATA, so we were unable to + // rewind all the way. Blocks remaining on chainActive at this point + // must not have their validity reduced. + if (!sufficientlyValidated(pindexIter) && !chainActive.Contains(pindexIter)) { + // Reduce validity + pindexIter->nStatus = + std::min(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | + (pindexIter->nStatus & ~BLOCK_VALID_MASK); + // Remove have-data flags + pindexIter->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO); + // Remove branch ID + pindexIter->nStatus &= ~BLOCK_ACTIVATES_UPGRADE; + pindexIter->nCachedBranchId = boost::none; + // Remove storage location + pindexIter->nFile = 0; + pindexIter->nDataPos = 0; + pindexIter->nUndoPos = 0; + // Remove various other things + pindexIter->nTx = 0; + pindexIter->nChainTx = 0; + pindexIter->nSproutValue = boost::none; + pindexIter->nChainSproutValue = boost::none; + pindexIter->nSequenceId = 0; + // Make sure it gets written + setDirtyBlockIndex.insert(pindexIter); + // Update indices + setBlockIndexCandidates.erase(pindexIter); + auto ret = mapBlocksUnlinked.equal_range(pindexIter->pprev); + while (ret.first != ret.second) { + if (ret.first->second == pindexIter) { + mapBlocksUnlinked.erase(ret.first++); + } else { + ++ret.first; + } + } + } else if (pindexIter->IsValid(BLOCK_VALID_TRANSACTIONS) && pindexIter->nChainTx) { + setBlockIndexCandidates.insert(pindexIter); + } + } + + PruneBlockIndexCandidates(); + + CheckBlockIndex(); + + if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) { + return false; + } + + return true; +} + void UnloadBlockIndex() { LOCK(cs_main); @@ -4639,6 +4995,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return false; } + // When Overwinter is active, reject incoming connections from non-Overwinter nodes + const Consensus::Params& params = Params().GetConsensus(); + if (NetworkUpgradeActive(GetHeight(), params, Consensus::UPGRADE_OVERWINTER) + && pfrom->nVersion < params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion) + { + LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); + pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", + params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)); + pfrom->fDisconnect = true; + return false; + } + if (pfrom->nVersion == 10300) pfrom->nVersion = 300; if (!vRecv.empty()) @@ -4757,6 +5126,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } + // Disconnect existing peer connection when: + // 1. The version message has been received + // 2. Overwinter is active + // 3. Peer version is pre-Overwinter + else if (NetworkUpgradeActive(GetHeight(), chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER) + && (pfrom->nVersion < chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)) + { + LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); + pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", + chainparams.GetConsensus().vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion)); + pfrom->fDisconnect = true; + return false; + } + + else if (strCommand == "addr") { vector vAddr; diff --git a/src/main.h b/src/main.h index 3d270d2b5..18afbfa92 100644 --- a/src/main.h +++ b/src/main.h @@ -15,6 +15,7 @@ #include "chainparams.h" #include "coins.h" #include "consensus/consensus.h" +#include "consensus/upgrades.h" #include "net.h" #include "primitives/block.h" #include "primitives/transaction.h" @@ -46,6 +47,7 @@ class CInv; class CScriptCheck; class CValidationInterface; class CValidationState; +class PrecomputedTransactionData; struct CNodeStateStats; @@ -58,6 +60,8 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = DEFAULT_BLOCK_MAX_SIZE / static const bool DEFAULT_ALERTS = true; /** Minimum alert priority for enabling safe mode. */ static const int ALERT_PRIORITY_SAFE_MODE = 4000; +/** Maximum reorg length we will accept before we shut down and alert the user. */ +static const unsigned int MAX_REORG_LENGTH = COINBASE_MATURITY - 1; /** Maximum number of signature check operations in an IsStandard() P2SH script */ static const unsigned int MAX_P2SH_SIGOPS = 15; /** The maximum number of sigops we're willing to relay/mine in a single tx */ @@ -66,6 +70,8 @@ static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5; static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 100; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; +/** Default for -txexpirydelta, in number of blocks */ +static const unsigned int DEFAULT_TX_EXPIRY_DELTA = 20; /** The maximum size of a blk?????.dat file (since 0.8) */ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ @@ -114,6 +120,7 @@ struct BlockHasher size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); } }; +extern unsigned int expiryDelta; extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; extern CTxMemPool mempool; @@ -644,7 +651,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF * @param[in] mapInputs Map of previous transactions that have outputs we're spending * @return True if all inputs (scriptSigs) use only standard transaction forms */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId); /** * Count ECDSA signature operations the old-fashioned (pre-0.6) way @@ -669,11 +676,17 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma * instead of being performed inline. */ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, - unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, + unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, + const Consensus::Params& consensusParams, uint32_t consensusBranchId, std::vector *pvChecks = NULL); +/** Check a transaction contextually against a set of consensus rules */ +bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, int nHeight, int dosLevel); + /** Apply the effects of this transaction on the UTXO set represented by view */ -void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); +void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight); + +/** Transaction validation functions */ /** Context-independent validity checks */ bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier); @@ -682,7 +695,18 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio /** Check for standard transaction types * @return True if all outputs (scriptPubKeys) use only standard transaction forms */ -bool IsStandardTx(const CTransaction& tx, std::string& reason); +bool IsStandardTx(const CTransaction& tx, std::string& reason, int nHeight = 0); + +namespace Consensus { + +/** + * Check whether all inputs of this transaction are valid (no double spends and amounts) + * This does not modify the UTXO set. This does not check scripts and sigs. + * Preconditions: tx.IsCoinBase() is false. + */ +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams); + +} // namespace Consensus /** * Check if transaction is final and can be included in a block with the @@ -690,6 +714,12 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason); */ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime); +/** + * Check if transaction is expired and can be included in a block with the + * specified height. Consensus critical. + */ +bool IsExpiredTx(const CTransaction &tx, int nBlockHeight); + /** * Check if transaction will be final in the next block to be created. * @@ -707,27 +737,33 @@ class CScriptCheck { private: CScript scriptPubKey; + CAmount amount; const CTransaction *ptxTo; unsigned int nIn; unsigned int nFlags; bool cacheStore; + uint32_t consensusBranchId; ScriptError error; + PrecomputedTransactionData *txdata; public: - CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} - CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) : - scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), - ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { } + CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), consensusBranchId(0), error(SCRIPT_ERR_UNKNOWN_ERROR) {} + CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, uint32_t consensusBranchIdIn, PrecomputedTransactionData* txdataIn) : + scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue), + ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), consensusBranchId(consensusBranchIdIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { } bool operator()(); void swap(CScriptCheck &check) { scriptPubKey.swap(check.scriptPubKey); std::swap(ptxTo, check.ptxTo); + std::swap(amount, check.amount); std::swap(nIn, check.nIn); std::swap(nFlags, check.nFlags); std::swap(cacheStore, check.cacheStore); + std::swap(consensusBranchId, check.consensusBranchId); std::swap(error, check.error); + std::swap(txdata, check.txdata); } ScriptError GetScriptError() const { return error; } @@ -784,6 +820,13 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc +/** + * When there are blocks in the active chain with missing data (e.g. if the + * activation height and branch ID of a particular upgrade have been altered), + * rewind the chainstate and remove them from the block index. + */ +bool RewindBlockIndex(const CChainParams& params); + class CBlockFileInfo { public: @@ -855,7 +898,7 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex); /** Remove invalidity status from a block and its descendants. */ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex); -/** The currently-connected chain of blocks. */ +/** The currently-connected chain of blocks (protected by cs_main). */ extern CChain chainActive; /** Global variable that points to the active CCoinsView (protected by cs_main) */ @@ -871,8 +914,7 @@ extern CBlockTreeDB *pblocktree; */ int GetSpendHeight(const CCoinsViewCache& inputs); -namespace Consensus { -bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams); -} +/** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */ +CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight); #endif // BITCOIN_MAIN_H diff --git a/src/miner.cpp b/src/miner.cpp index 9f0af60f0..b65cadc3d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -13,6 +13,7 @@ #include "base58.h" #include "chainparams.h" #include "consensus/consensus.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #ifdef ENABLE_MINING #include "crypto/equihash.h" @@ -144,6 +145,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); const int nHeight = pindexPrev->nHeight + 1; + uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus()); pblock->nTime = GetAdjustedTime(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); CCoinsViewCache view(pcoinsTip); @@ -156,16 +158,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // This vector will be sorted into a priority queue: vector vecPriority; vecPriority.reserve(mempool.mapTx.size()); - for (map::iterator mi = mempool.mapTx.begin(); + for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { - const CTransaction& tx = mi->second.GetTx(); + const CTransaction& tx = mi->GetTx(); int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) ? nMedianTimePast : pblock->GetBlockTime(); - if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff)) + if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff) || IsExpiredTx(tx, nHeight)) continue; COrphan* porphan = NULL; @@ -199,7 +201,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) } mapDependers[txin.prevout.hash].push_back(porphan); porphan->setDependsOn.insert(txin.prevout.hash); - nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue; + nTotalIn += mempool.mapTx.find(txin.prevout.hash)->GetTx().vout[txin.prevout.n].nValue; continue; } const CCoins* coins = view.AccessCoins(txin.prevout.hash); @@ -231,7 +233,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) porphan->feeRate = feeRate; } else - vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx())); + vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx()))); } // Collect transactions into block @@ -294,10 +296,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // policy here, but we still have to ensure that the block we // create only contains transactions that are valid in new blocks. CValidationState state; - if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus())) + PrecomputedTransactionData txdata(tx); + if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) continue; - UpdateCoins(tx, state, view, nHeight); + UpdateCoins(tx, view, nHeight); // Added pblock->vtx.push_back(tx); @@ -337,12 +340,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); // Create coinbase tx - CMutableTransaction txNew; + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); txNew.vout.resize(1); txNew.vout[0].scriptPubKey = scriptPubKeyIn; txNew.vout[0].nValue = GetBlockSubsidy(nHeight, chainparams.GetConsensus()); + // Set to 0 so expiry height does not apply to coinbase txs + txNew.nExpiryHeight = 0; // Add fees txNew.vout[0].nValue += nFees; diff --git a/src/net.cpp b/src/net.cpp index aefc68655..d76560307 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -7,6 +7,7 @@ #include "config/bitcoin-config.h" #endif +#include "main.h" #include "net.h" #include "addrman.h" @@ -1098,6 +1099,34 @@ static bool AttemptToEvictConnection(bool fPreferNewConnection) { // Protect connections with certain characteristics + // Check version of eviction candidates and prioritize nodes which do not support network upgrade. + std::vector vTmpEvictionCandidates; + int height; + { + LOCK(cs_main); + height = chainActive.Height(); + } + + const Consensus::Params& params = Params().GetConsensus(); + int nActivationHeight = params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight; + + if (nActivationHeight > 0 && + height < nActivationHeight && + height >= nActivationHeight - NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD) + { + // Find any nodes which don't support Overwinter protocol version + BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) { + if (node->nVersion < params.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion) { + vTmpEvictionCandidates.push_back(node); + } + } + + // Prioritize these nodes by replacing eviction set with them + if (vTmpEvictionCandidates.size() > 0) { + vEvictionCandidates = vTmpEvictionCandidates; + } + } + // Deterministically select 4 peers to protect by netgroup. // An attacker cannot predict which netgroups will be protected. static CompareNetGroupKeyed comparerNetGroupKeyed; diff --git a/src/net.h b/src/net.h index 9bd9e017a..071e23640 100644 --- a/src/net.h +++ b/src/net.h @@ -61,6 +61,8 @@ static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ; static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ; /** The maximum number of peer connections to maintain. */ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; +/** The period before a network upgrade activates, where connections to upgrading peers are preferred (in blocks). */ +static const int NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD = 24 * 24 * 3; unsigned int ReceiveFloodSize(); unsigned int SendBufferSize(); diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 4141bea45..b362d3d6e 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -146,8 +146,9 @@ std::string CTxOut::ToString() const return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30)); } -CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::MIN_CURRENT_VERSION), nLockTime(0) {} -CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), +CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), nLockTime(0) {} +CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight), + vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig) { @@ -163,19 +164,34 @@ void CTransaction::UpdateHash() const *const_cast(&hash) = SerializeHash(*this); } -CTransaction::CTransaction() : nVersion(CTransaction::MIN_CURRENT_VERSION), vin(), vout(), nLockTime(0), vjoinsplit(), joinSplitPubKey(), joinSplitSig() { } +CTransaction::CTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), vin(), vout(), nLockTime(0), vjoinsplit(), joinSplitPubKey(), joinSplitSig() { } -CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vjoinsplit(tx.vjoinsplit), - joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig) +CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight), + vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), + vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig) { UpdateHash(); } +// Protected constructor which only derived classes can call. +// For developer testing only. +CTransaction::CTransaction( + const CMutableTransaction &tx, + bool evilDeveloperFlag) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), nExpiryHeight(tx.nExpiryHeight), + vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), + vjoinsplit(tx.vjoinsplit), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig) +{ + assert(evilDeveloperFlag); +} + CTransaction& CTransaction::operator=(const CTransaction &tx) { + *const_cast(&fOverwintered) = tx.fOverwintered; *const_cast(&nVersion) = tx.nVersion; + *const_cast(&nVersionGroupId) = tx.nVersionGroupId; *const_cast*>(&vin) = tx.vin; *const_cast*>(&vout) = tx.vout; *const_cast(&nLockTime) = tx.nLockTime; + *const_cast(&nExpiryHeight) = tx.nExpiryHeight; *const_cast*>(&vjoinsplit) = tx.vjoinsplit; *const_cast(&joinSplitPubKey) = tx.joinSplitPubKey; *const_cast(&joinSplitSig) = tx.joinSplitSig; @@ -248,12 +264,24 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const std::string CTransaction::ToString() const { std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n", - GetHash().ToString().substr(0,10), - nVersion, - vin.size(), - vout.size(), - nLockTime); + if (!fOverwintered) { + str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n", + GetHash().ToString().substr(0,10), + nVersion, + vin.size(), + vout.size(), + nLockTime); + } else if (nVersion >= 3) { + str += strprintf("CTransaction(hash=%s, ver=%d, fOverwintered=%d, nVersionGroupId=%08x, vin.size=%u, vout.size=%u, nLockTime=%u, nExpiryHeight=%u)\n", + GetHash().ToString().substr(0,10), + nVersion, + fOverwintered, + nVersionGroupId, + vin.size(), + vout.size(), + nLockTime, + nExpiryHeight); + } for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; for (unsigned int i = 0; i < vout.size(); i++) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index f9723e399..bcd7eaa8a 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -304,6 +304,10 @@ public: std::string ToString() const; }; +// Overwinter version group id +static constexpr uint32_t OVERWINTER_VERSION_GROUP_ID = 0x03C48270; +static_assert(OVERWINTER_VERSION_GROUP_ID != 0, "version group id must be non-zero as specified in ZIP 202"); + struct CMutableTransaction; /** The basic transaction that is broadcasted on the network and contained in @@ -316,14 +320,29 @@ private: const uint256 hash; void UpdateHash() const; +protected: + /** Developer testing only. Set evilDeveloperFlag to true. + * Convert a CMutableTransaction into a CTransaction without invoking UpdateHash() + */ + CTransaction(const CMutableTransaction &tx, bool evilDeveloperFlag); + public: typedef boost::array joinsplit_sig_t; - // Transactions that include a list of JoinSplits are version 2. - static const int32_t MIN_CURRENT_VERSION = 1; - static const int32_t MAX_CURRENT_VERSION = 2; + // Transactions that include a list of JoinSplits are >= version 2. + static const int32_t SPROUT_MIN_CURRENT_VERSION = 1; + static const int32_t SPROUT_MAX_CURRENT_VERSION = 2; + static const int32_t OVERWINTER_MIN_CURRENT_VERSION = 3; + static const int32_t OVERWINTER_MAX_CURRENT_VERSION = 3; + + static_assert(SPROUT_MIN_CURRENT_VERSION >= SPROUT_MIN_TX_VERSION, + "standard rule for tx version should be consistent with network rule"); + + static_assert(OVERWINTER_MIN_CURRENT_VERSION >= OVERWINTER_MIN_TX_VERSION, + "standard rule for tx version should be consistent with network rule"); - static_assert(MIN_CURRENT_VERSION >= MIN_TX_VERSION, + static_assert( (OVERWINTER_MAX_CURRENT_VERSION <= OVERWINTER_MAX_TX_VERSION && + OVERWINTER_MAX_CURRENT_VERSION >= OVERWINTER_MIN_CURRENT_VERSION), "standard rule for tx version should be consistent with network rule"); // The local variables are made const to prevent unintended modification @@ -331,10 +350,13 @@ public: // actually immutable; deserialization and assignment are implemented, // and bypass the constness. This is safe, as they update the entire // structure, including the hash. + const bool fOverwintered; const int32_t nVersion; + const uint32_t nVersionGroupId; const std::vector vin; const std::vector vout; const uint32_t nLockTime; + const uint32_t nExpiryHeight; const std::vector vjoinsplit; const uint256 joinSplitPubKey; const joinsplit_sig_t joinSplitSig = {{0}}; @@ -351,11 +373,34 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(*const_cast(&this->nVersion)); + if (ser_action.ForRead()) { + // When deserializing, unpack the 4 byte header to extract fOverwintered and nVersion. + uint32_t header; + READWRITE(header); + *const_cast(&fOverwintered) = header >> 31; + *const_cast(&this->nVersion) = header & 0x7FFFFFFF; + } else { + uint32_t header = GetHeader(); + READWRITE(header); + } nVersion = this->nVersion; + if (fOverwintered) { + READWRITE(*const_cast(&this->nVersionGroupId)); + } + + bool isOverwinterV3 = fOverwintered && + nVersionGroupId == OVERWINTER_VERSION_GROUP_ID && + nVersion == 3; + if (fOverwintered && !isOverwinterV3) { + throw std::ios_base::failure("Unknown transaction format"); + } + READWRITE(*const_cast*>(&vin)); READWRITE(*const_cast*>(&vout)); READWRITE(*const_cast(&nLockTime)); + if (isOverwinterV3) { + READWRITE(*const_cast(&nExpiryHeight)); + } if (nVersion >= 2) { READWRITE(*const_cast*>(&vjoinsplit)); if (vjoinsplit.size() > 0) { @@ -375,6 +420,16 @@ public: return hash; } + uint32_t GetHeader() const { + // When serializing v1 and v2, the 4 byte header is nVersion + uint32_t header = this->nVersion; + // When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion + if (fOverwintered) { + header |= 1 << 31; + } + return header; + } + // Return sum of txouts. CAmount GetValueOut() const; // GetValueIn() is a method on CCoinsViewCache, because @@ -410,10 +465,13 @@ public: /** A mutable version of CTransaction. */ struct CMutableTransaction { + bool fOverwintered; int32_t nVersion; + uint32_t nVersionGroupId; std::vector vin; std::vector vout; uint32_t nLockTime; + uint32_t nExpiryHeight; std::vector vjoinsplit; uint256 joinSplitPubKey; CTransaction::joinsplit_sig_t joinSplitSig = {{0}}; @@ -425,11 +483,39 @@ struct CMutableTransaction template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(this->nVersion); + if (ser_action.ForRead()) { + // When deserializing, unpack the 4 byte header to extract fOverwintered and nVersion. + uint32_t header; + READWRITE(header); + fOverwintered = header >> 31; + this->nVersion = header & 0x7FFFFFFF; + } else { + // When serializing v1 and v2, the 4 byte header is nVersion + uint32_t header = this->nVersion; + // When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion + if (fOverwintered) { + header |= 1 << 31; + } + READWRITE(header); + } nVersion = this->nVersion; + if (fOverwintered) { + READWRITE(nVersionGroupId); + } + + bool isOverwinterV3 = fOverwintered && + nVersionGroupId == OVERWINTER_VERSION_GROUP_ID && + nVersion == 3; + if (fOverwintered && !isOverwinterV3) { + throw std::ios_base::failure("Unknown transaction format"); + } + READWRITE(vin); READWRITE(vout); READWRITE(nLockTime); + if (isOverwinterV3) { + READWRITE(nExpiryHeight); + } if (nVersion >= 2) { READWRITE(vjoinsplit); if (vjoinsplit.size() > 0) { diff --git a/src/protocol.h b/src/protocol.h index b5e65032a..b0208b01c 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -71,10 +71,6 @@ enum { // set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want // network services but don't provide them. NODE_NETWORK = (1 << 0), - // NODE_GETUTXO means the node is capable of responding to the getutxo protocol request. - // Bitcoin Core does not support this but a patch set called Bitcoin XT does. - // See BIP 64 for details on how this is implemented. - NODE_GETUTXO = (1 << 1), // Bits 24-31 are reserved for temporary experiments. Just pick a bit that // isn't getting used, or one not being used much, and notify the diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 6e50a1334..0b87bb526 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -104,8 +104,8 @@ void CExtPubKey::Encode(unsigned char code[74]) const { code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF; memcpy(code+9, chaincode.begin(), 32); - assert(pubkey.size() == COMPRESSED_PUBLIC_KEY_SIZE); - memcpy(code+41, pubkey.begin(), COMPRESSED_PUBLIC_KEY_SIZE); + assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); + memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); } void CExtPubKey::Decode(const unsigned char code[74]) { diff --git a/src/pubkey.h b/src/pubkey.h index fcfa019cf..237237e05 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -14,18 +14,6 @@ #include #include -/** - * secp256k1: - */ -const unsigned int PUBLIC_KEY_SIZE = 65; -const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33; -const unsigned int SIGNATURE_SIZE = 72; -const unsigned int COMPACT_SIGNATURE_SIZE = 65; -/** - * see www.keylength.com - * script supports up to 75 for single byte push - */ - /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { @@ -39,6 +27,22 @@ typedef uint256 ChainCode; /** An encapsulated public key. */ class CPubKey { +public: + /** + * secp256k1: + */ + static const unsigned int PUBLIC_KEY_SIZE = 65; + static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33; + static const unsigned int SIGNATURE_SIZE = 72; + static const unsigned int COMPACT_SIGNATURE_SIZE = 65; + /** + * see www.keylength.com + * script supports up to 75 for single byte push + */ + static_assert( + PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE, + "COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE"); + private: /** @@ -46,9 +50,6 @@ private: * Its length can very cheaply be computed from the first byte. */ unsigned char vch[PUBLIC_KEY_SIZE]; - static_assert( - PUBLIC_KEY_SIZE >= COMPRESSED_PUBLIC_KEY_SIZE, - "COMPRESSED_PUBLIC_KEY_SIZE is larger than PUBLIC_KEY_SIZE"); //! Compute the length of a pubkey with a given first byte. unsigned int static GetLen(unsigned char chHeader) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 74c3bac89..898abedce 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -343,10 +343,9 @@ UniValue mempoolToJSON(bool fVerbose = false) { LOCK(mempool.cs); UniValue o(UniValue::VOBJ); - BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx) + BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx) { - const uint256& hash = entry.first; - const CTxMemPoolEntry& e = entry.second; + const uint256& hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); info.push_back(Pair("size", (int)e.GetTxSize())); info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); @@ -874,12 +873,45 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* return rv; } +static UniValue NetworkUpgradeDesc(const Consensus::Params& consensusParams, Consensus::UpgradeIndex idx, int height) +{ + UniValue rv(UniValue::VOBJ); + auto upgrade = NetworkUpgradeInfo[idx]; + rv.push_back(Pair("name", upgrade.strName)); + rv.push_back(Pair("activationheight", consensusParams.vUpgrades[idx].nActivationHeight)); + switch (NetworkUpgradeState(height, consensusParams, idx)) { + case UPGRADE_DISABLED: rv.push_back(Pair("status", "disabled")); break; + case UPGRADE_PENDING: rv.push_back(Pair("status", "pending")); break; + case UPGRADE_ACTIVE: rv.push_back(Pair("status", "active")); break; + } + rv.push_back(Pair("info", upgrade.strInfo)); + return rv; +} + +void NetworkUpgradeDescPushBack( + UniValue& networkUpgrades, + const Consensus::Params& consensusParams, + Consensus::UpgradeIndex idx, + int height) +{ + // Network upgrades with an activation height of NO_ACTIVATION_HEIGHT are + // hidden. This is used when network upgrade implementations are merged + // without specifying the activation height. + if (consensusParams.vUpgrades[idx].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { + networkUpgrades.push_back(Pair( + HexInt(NetworkUpgradeInfo[idx].nBranchId), + NetworkUpgradeDesc(consensusParams, idx, height))); + } +} + UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getblockchaininfo\n" "Returns an object containing various state info regarding block chain processing.\n" + "\nNote that when the chain tip is at the last block before a network upgrade activation,\n" + "consensus.chaintip != consensus.nextblock.\n" "\nResult:\n" "{\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" @@ -902,7 +934,19 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " },\n" " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" " }, ...\n" - " ]\n" + " ],\n" + " \"upgrades\": { (object) status of network upgrades\n" + " \"xxxx\" : { (string) branch ID of the upgrade\n" + " \"name\": \"xxxx\", (string) name of upgrade\n" + " \"activationheight\": xxxxxx, (numeric) block height of activation\n" + " \"status\": \"xxxx\", (string) status of upgrade\n" + " \"info\": \"xxxx\", (string) additional information about upgrade\n" + " }, ...\n" + " },\n" + " \"consensus\": { (object) branch IDs of the current and upcoming consensus rules\n" + " \"chaintip\": \"xxxxxxxx\", (string) branch ID used to validate the current chain tip\n" + " \"nextblock\": \"xxxxxxxx\" (string) branch ID that the next block will be validated under\n" + " }\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") @@ -937,6 +981,17 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams)); obj.push_back(Pair("softforks", softforks)); + UniValue upgrades(UniValue::VOBJ); + for (int i = Consensus::UPGRADE_OVERWINTER; i < Consensus::MAX_NETWORK_UPGRADES; i++) { + NetworkUpgradeDescPushBack(upgrades, consensusParams, Consensus::UpgradeIndex(i), tip->nHeight); + } + obj.push_back(Pair("upgrades", upgrades)); + + UniValue consensus(UniValue::VOBJ); + consensus.push_back(Pair("chaintip", HexInt(CurrentEpochBranchId(tip->nHeight, consensusParams)))); + consensus.push_back(Pair("nextblock", HexInt(CurrentEpochBranchId(tip->nHeight + 1, consensusParams)))); + obj.push_back(Pair("consensus", consensus)); + if (fPruneMode) { CBlockIndex *block = chainActive.Tip(); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 35928e647..67aa4e2de 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -123,6 +123,10 @@ static const CRPCConvertParam vRPCConvertParams[] = { "z_gettotalbalance", 0}, { "z_gettotalbalance", 1}, { "z_gettotalbalance", 2}, + { "z_mergetoaddress", 0}, + { "z_mergetoaddress", 2}, + { "z_mergetoaddress", 3}, + { "z_mergetoaddress", 4}, { "z_sendmany", 1}, { "z_sendmany", 2}, { "z_sendmany", 3}, diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 1b1f3e20c..50492d0c6 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -403,6 +403,33 @@ static UniValue GetNetworksInfo() return networks; } +UniValue getdeprecationinfo(const UniValue& params, bool fHelp) +{ + const CChainParams& chainparams = Params(); + if (fHelp || params.size() != 0 || chainparams.NetworkIDString() != "main") + throw runtime_error( + "getdeprecationinfo\n" + "Returns an object containing current version and deprecation block height. Applicable only on mainnet.\n" + "\nResult:\n" + "{\n" + " \"version\": xxxxx, (numeric) the server version\n" + " \"subversion\": \"/MagicBean:x.y.z[-v]/\", (string) the server subversion string\n" + " \"deprecationheight\": xxxxx, (numeric) the block height at which this version will deprecate and shut down (unless -disabledeprecation is set)\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getdeprecationinfo", "") + + HelpExampleRpc("getdeprecationinfo", "") + ); + + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("version", CLIENT_VERSION)); + obj.push_back(Pair("subversion", + FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()))); + obj.push_back(Pair("deprecationheight", DEPRECATION_HEIGHT)); + + return obj; +} + UniValue getnetworkinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index c69f49bfc..d46f2fa89 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #include "core_io.h" #include "init.h" @@ -118,8 +119,15 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& uint256 txid = tx.GetHash(); entry.push_back(Pair("txid", txid.GetHex())); + entry.push_back(Pair("overwintered", tx.fOverwintered)); entry.push_back(Pair("version", tx.nVersion)); + if (tx.fOverwintered) { + entry.push_back(Pair("versiongroupid", HexInt(tx.nVersionGroupId))); + } entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); + if (tx.fOverwintered) { + entry.push_back(Pair("expiryheight", (int64_t)tx.nExpiryHeight)); + } UniValue vin(UniValue::VARR); BOOST_FOREACH(const CTxIn& txin, tx.vin) { UniValue in(UniValue::VOBJ); @@ -199,9 +207,16 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) uint256 txid = tx.GetHash(); entry.push_back(Pair("txid", txid.GetHex())); + entry.push_back(Pair("overwintered", tx.fOverwintered)); entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); entry.push_back(Pair("version", tx.nVersion)); + if (tx.fOverwintered) { + entry.push_back(Pair("versiongroupid", HexInt(tx.nVersionGroupId))); + } entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); + if (tx.fOverwintered) { + entry.push_back(Pair("expiryheight", (int64_t)tx.nExpiryHeight)); + } UniValue vin(UniValue::VARR); BOOST_FOREACH(const CTxIn& txin, tx.vin) { @@ -278,6 +293,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) " \"txid\" : \"id\", (string) The transaction id (same as provided)\n" " \"version\" : n, (numeric) The version\n" " \"locktime\" : ttt, (numeric) The lock time\n" + " \"expiryheight\" : ttt, (numeric, optional) The block height after which the transaction expires\n" " \"vin\" : [ (array of json objects)\n" " {\n" " \"txid\": \"id\", (string) The transaction id\n" @@ -544,7 +560,16 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) UniValue inputs = params[0].get_array(); UniValue sendTo = params[1].get_obj(); - CMutableTransaction rawTx; + int nextBlockHeight = chainActive.Height() + 1; + CMutableTransaction rawTx = CreateNewContextualCMutableTransaction( + Params().GetConsensus(), nextBlockHeight); + + if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + rawTx.nExpiryHeight = nextBlockHeight + expiryDelta; + if (rawTx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD){ + throw JSONRPCError(RPC_INVALID_PARAMETER, "nExpiryHeight must be less than TX_EXPIRY_HEIGHT_THRESHOLD."); + } + } for (size_t idx = 0; idx < inputs.size(); idx++) { const UniValue& input = inputs[idx]; @@ -597,8 +622,11 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp) "\nResult:\n" "{\n" " \"txid\" : \"id\", (string) The transaction id\n" + " \"overwintered\" : bool (boolean) The Overwintered flag\n" " \"version\" : n, (numeric) The version\n" + " \"versiongroupid\": \"hex\" (string, optional) The version group id (Overwintered txs)\n" " \"locktime\" : ttt, (numeric) The lock time\n" + " \"expiryheight\" : n, (numeric, optional) Last valid block height for mining transaction (Overwintered txs)\n" " \"vin\" : [ (array of json objects)\n" " {\n" " \"txid\": \"id\", (string) The transaction id\n" @@ -752,7 +780,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) " \"txid\":\"id\", (string, required) The transaction id\n" " \"vout\":n, (numeric, required) The output number\n" " \"scriptPubKey\": \"hex\", (string, required) script key\n" - " \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n" + " \"redeemScript\": \"hex\", (string, required for P2SH) redeem script\n" + " \"amount\": value (numeric, required) The amount spent\n" " }\n" " ,...\n" " ]\n" @@ -890,7 +919,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) if ((unsigned int)nOut >= coins->vout.size()) coins->vout.resize(nOut+1); coins->vout[nOut].scriptPubKey = scriptPubKey; - coins->vout[nOut].nValue = 0; // we don't know the actual output value + coins->vout[nOut].nValue = 0; + if (prevOut.exists("amount")) { + coins->vout[nOut].nValue = AmountFromValue(find_value(prevOut, "amount")); + } } // if redeemScript given and not using the local wallet (private keys @@ -933,9 +965,15 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + // Grab the current consensus branch ID + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + // Script verification errors UniValue vErrors(UniValue::VARR); + // Use CTransaction for the constant parts of the + // transaction to avoid rehashing. + const CTransaction txConst(mergedTx); // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; @@ -945,18 +983,22 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) continue; } const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey; + const CAmount& amount = coins->vout[txin.prevout.n].nValue; - txin.scriptSig.clear(); + SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); + ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId); // ... and merge in other signatures: BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { - txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); + sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId); } + + UpdateTransaction(mergedTx, i, sigdata); + ScriptError serror = SCRIPT_ERR_OK; - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) { + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), consensusBranchId, &serror)) { TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); } } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index e337bb16a..fc5e93c8e 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -265,6 +265,7 @@ static const CRPCCommand vRPCCommands[] = /* P2P networking */ { "network", "getnetworkinfo", &getnetworkinfo, true }, + { "network", "getdeprecationinfo", &getdeprecationinfo, true }, { "network", "addnode", &addnode, true }, { "network", "disconnectnode", &disconnectnode, true }, { "network", "getaddednodeinfo", &getaddednodeinfo, true }, @@ -397,6 +398,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "z_listunspent", &z_listunspent, false }, { "wallet", "z_getbalance", &z_getbalance, false }, { "wallet", "z_gettotalbalance", &z_gettotalbalance, false }, + { "wallet", "z_mergetoaddress", &z_mergetoaddress, false }, { "wallet", "z_sendmany", &z_sendmany, false }, { "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false }, { "wallet", "z_getoperationstatus", &z_getoperationstatus, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index fd4094d55..0764905c4 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -245,6 +245,7 @@ extern UniValue getinfo(const UniValue& params, bool fHelp); extern UniValue getwalletinfo(const UniValue& params, bool fHelp); extern UniValue getblockchaininfo(const UniValue& params, bool fHelp); extern UniValue getnetworkinfo(const UniValue& params, bool fHelp); +extern UniValue getdeprecationinfo(const UniValue& params, bool fHelp); extern UniValue setmocktime(const UniValue& params, bool fHelp); extern UniValue resendwallettransactions(const UniValue& params, bool fHelp); extern UniValue zc_benchmark(const UniValue& params, bool fHelp); @@ -301,6 +302,7 @@ extern UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp); // extern UniValue z_listunspent(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_getbalance(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_gettotalbalance(const UniValue& params, bool fHelp); // in rpcwallet.cpp +extern UniValue z_mergetoaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_sendmany(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_shieldcoinbase(const UniValue& params, bool fHelp); // in rpcwallet.cpp extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp); // in rpcwallet.cpp diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index e61b4bb49..66153477e 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -5,6 +5,7 @@ #include "interpreter.h" +#include "consensus/upgrades.h" #include "primitives/transaction.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" @@ -232,7 +233,13 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { return true; } -bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) +bool EvalScript( + vector >& stack, + const CScript& script, + unsigned int flags, + const BaseSignatureChecker& checker, + uint32_t consensusBranchId, + ScriptError* serror) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); @@ -828,7 +835,7 @@ bool EvalScript(vector >& stack, const CScript& script, un //serror is set return false; } - bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script); + bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId); popstack(stack); popstack(stack); @@ -886,7 +893,7 @@ bool EvalScript(vector >& stack, const CScript& script, un } // Check signature - bool fOk = checker.CheckSig(vchSig, vchPubKey, script); + bool fOk = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId); if (fOk) { isig++; @@ -1050,15 +1057,148 @@ public: } }; +const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = + {'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'}; +const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = + {'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'}; +const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = + {'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'}; +const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = + {'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'}; + +uint256 GetPrevoutHash(const CTransaction& txTo) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vin.size(); n++) { + ss << txTo.vin[n].prevout; + } + return ss.GetHash(); +} + +uint256 GetSequenceHash(const CTransaction& txTo) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vin.size(); n++) { + ss << txTo.vin[n].nSequence; + } + return ss.GetHash(); +} + +uint256 GetOutputsHash(const CTransaction& txTo) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vout.size(); n++) { + ss << txTo.vout[n]; + } + return ss.GetHash(); +} + +uint256 GetJoinSplitsHash(const CTransaction& txTo) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_JOINSPLITS_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vjoinsplit.size(); n++) { + ss << txTo.vjoinsplit[n]; + } + ss << txTo.joinSplitPubKey; + return ss.GetHash(); +} + } // anon namespace -uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) +PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) +{ + hashPrevouts = GetPrevoutHash(txTo); + hashSequence = GetSequenceHash(txTo); + hashOutputs = GetOutputsHash(txTo); + hashJoinSplits = GetJoinSplitsHash(txTo); +} + +SigVersion SignatureHashVersion(const CTransaction& txTo) +{ + if (txTo.fOverwintered) { + return SIGVERSION_OVERWINTER; + } else { + return SIGVERSION_SPROUT; + } +} + +uint256 SignatureHash( + const CScript& scriptCode, + const CTransaction& txTo, + unsigned int nIn, + int nHashType, + const CAmount& amount, + uint32_t consensusBranchId, + const PrecomputedTransactionData* cache) { if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) { // nIn out of range throw logic_error("input index is out of range"); } + auto sigversion = SignatureHashVersion(txTo); + + if (sigversion == SIGVERSION_OVERWINTER) { + uint256 hashPrevouts; + uint256 hashSequence; + uint256 hashOutputs; + uint256 hashJoinSplits; + + if (!(nHashType & SIGHASH_ANYONECANPAY)) { + hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo); + } + + if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { + hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo); + } + + if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { + hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo); + } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); + ss << txTo.vout[nIn]; + hashOutputs = ss.GetHash(); + } + + if (!txTo.vjoinsplit.empty()) { + hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo); + } + + uint32_t leConsensusBranchId = htole32(consensusBranchId); + unsigned char personalization[16] = {}; + memcpy(personalization, "ZcashSigHash", 12); + memcpy(personalization+12, &leConsensusBranchId, 4); + + CBLAKE2bWriter ss(SER_GETHASH, 0, personalization); + // Header + ss << txTo.GetHeader(); + // Version group ID + ss << txTo.nVersionGroupId; + // Input prevouts/nSequence (none/all, depending on flags) + ss << hashPrevouts; + ss << hashSequence; + // Outputs (none/one/all, depending on flags) + ss << hashOutputs; + // JoinSplits + ss << hashJoinSplits; + // Locktime + ss << txTo.nLockTime; + // Expiry height + ss << txTo.nExpiryHeight; + // Sighash type + ss << nHashType; + + // If this hash is for a transparent input signature + // (i.e. not for txTo.joinSplitSig): + if (nIn != NOT_AN_INPUT){ + // The input being signed (replacing the scriptSig with scriptCode + amount) + // The prevout may already be contained in hashPrevout, and the nSequence + // may already be contained in hashSequence. + ss << txTo.vin[nIn].prevout; + ss << scriptCode; + ss << amount; + ss << txTo.vin[nIn].nSequence; + } + + return ss.GetHash(); + } + // Check for invalid use of SIGHASH_SINGLE if ((nHashType & 0x1f) == SIGHASH_SINGLE) { if (nIn >= txTo.vout.size()) { @@ -1076,12 +1216,17 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } -bool TransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const +bool TransactionSignatureChecker::VerifySignature( + const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const { return pubkey.Verify(sighash, vchSig); } -bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn, const vector& vchPubKey, const CScript& scriptCode) const +bool TransactionSignatureChecker::CheckSig( + const vector& vchSigIn, + const vector& vchPubKey, + const CScript& scriptCode, + uint32_t consensusBranchId) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1096,7 +1241,7 @@ bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn uint256 sighash; try { - sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType); + sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata); } catch (logic_error ex) { return false; } @@ -1144,7 +1289,13 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) +bool VerifyScript( + const CScript& scriptSig, + const CScript& scriptPubKey, + unsigned int flags, + const BaseSignatureChecker& checker, + uint32_t consensusBranchId, + ScriptError* serror) { set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); @@ -1153,12 +1304,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne } vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker, serror)) + if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror)) // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) + if (!EvalScript(stack, scriptPubKey, flags, checker, consensusBranchId, serror)) // serror is set return false; if (stack.empty()) @@ -1185,7 +1336,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); - if (!EvalScript(stack, pubKey2, flags, checker, serror)) + if (!EvalScript(stack, pubKey2, flags, checker, consensusBranchId, serror)) // serror is set return false; if (stack.empty()) diff --git a/src/script/interpreter.h b/src/script/interpreter.h index f467f08fc..7f2956eec 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -88,12 +88,36 @@ enum SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), }; -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); +struct PrecomputedTransactionData +{ + uint256 hashPrevouts, hashSequence, hashOutputs, hashJoinSplits; + + PrecomputedTransactionData(const CTransaction& tx); +}; + +enum SigVersion +{ + SIGVERSION_SPROUT = 0, + SIGVERSION_OVERWINTER = 1, +}; + +uint256 SignatureHash( + const CScript &scriptCode, + const CTransaction& txTo, + unsigned int nIn, + int nHashType, + const CAmount& amount, + uint32_t consensusBranchId, + const PrecomputedTransactionData* cache = NULL); class BaseSignatureChecker { public: - virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const + virtual bool CheckSig( + const std::vector& scriptSig, + const std::vector& vchPubKey, + const CScript& scriptCode, + uint32_t consensusBranchId) const { return false; } @@ -111,13 +135,16 @@ class TransactionSignatureChecker : public BaseSignatureChecker private: const CTransaction* txTo; unsigned int nIn; + const CAmount amount; + const PrecomputedTransactionData* txdata; protected: virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; public: - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const; + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {} + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CheckLockTime(const CScriptNum& nLockTime) const; }; @@ -127,10 +154,22 @@ private: const CTransaction txTo; public: - MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {} + MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {} }; -bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); +bool EvalScript( + std::vector >& stack, + const CScript& script, + unsigned int flags, + const BaseSignatureChecker& checker, + uint32_t consensusBranchId, + ScriptError* error = NULL); +bool VerifyScript( + const CScript& scriptSig, + const CScript& scriptPubKey, + unsigned int flags, + const BaseSignatureChecker& checker, + uint32_t consensusBranchId, + ScriptError* serror = NULL); #endif // BITCOIN_SCRIPT_INTERPRETER_H diff --git a/src/script/sigcache.h b/src/script/sigcache.h index b299038da..134b72a2d 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -18,7 +18,7 @@ private: bool store; public: - CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn), store(storeIn) {} + CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {} bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; }; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 75e6c6d9d..1aade8477 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -17,9 +17,9 @@ using namespace std; typedef vector valtype; -TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {} +TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} -bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode) const +bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId) const { CKey key; if (!keystore->GetKey(address, key)) @@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, uint256 hash; try { - hash = SignatureHash(scriptCode, *txTo, nIn, nHashType); + hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId); } catch (logic_error ex) { return false; } @@ -38,16 +38,16 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, return true; } -static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet) +static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, uint32_t consensusBranchId) { vector vchSig; - if (!creator.CreateSig(vchSig, address, scriptCode)) + if (!creator.CreateSig(vchSig, address, scriptCode, consensusBranchId)) return false; - scriptSigRet << vchSig; + ret.push_back(vchSig); return true; } -static bool SignN(const vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet) +static bool SignN(const vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, uint32_t consensusBranchId) { int nSigned = 0; int nRequired = multisigdata.front()[0]; @@ -55,7 +55,7 @@ static bool SignN(const vector& multisigdata, const BaseSignatureCreato { const valtype& pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); - if (Sign1(keyID, creator, scriptCode, scriptSigRet)) + if (Sign1(keyID, creator, scriptCode, ret, consensusBranchId)) ++nSigned; } return nSigned==nRequired; @@ -68,9 +68,11 @@ static bool SignN(const vector& multisigdata, const BaseSignatureCreato * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey, - CScript& scriptSigRet, txnouttype& whichTypeRet) + std::vector& ret, txnouttype& whichTypeRet, uint32_t consensusBranchId) { - scriptSigRet.clear(); + CScript scriptRet; + uint160 h160; + ret.clear(); vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) @@ -84,85 +86,127 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - return Sign1(keyID, creator, scriptPubKey, scriptSigRet); + return Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet)) + if (!Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId)) return false; else { CPubKey vch; creator.KeyStore().GetPubKey(keyID, vch); - scriptSigRet << ToByteVector(vch); + ret.push_back(ToByteVector(vch)); } return true; case TX_SCRIPTHASH: - return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet); + if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) { + ret.push_back(std::vector(scriptRet.begin(), scriptRet.end())); + return true; + } + return false; case TX_MULTISIG: - scriptSigRet << OP_0; // workaround CHECKMULTISIG bug - return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet)); + ret.push_back(valtype()); // workaround CHECKMULTISIG bug + return (SignN(vSolutions, creator, scriptPubKey, ret, consensusBranchId)); + + default: + return false; } - return false; } -bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig) +static CScript PushAll(const vector& values) { + CScript result; + BOOST_FOREACH(const valtype& v, values) { + if (v.size() == 0) { + result << OP_0; + } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { + result << CScript::EncodeOP_N(v[0]); + } else { + result << v; + } + } + return result; +} + +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata, uint32_t consensusBranchId) +{ + CScript script = fromPubKey; + bool solved = true; + std::vector result; txnouttype whichType; - if (!SignStep(creator, fromPubKey, scriptSig, whichType)) - return false; + solved = SignStep(creator, script, result, whichType, consensusBranchId); + CScript subscript; - if (whichType == TX_SCRIPTHASH) + if (solved && whichType == TX_SCRIPTHASH) { - // Solver returns the subscript that need to be evaluated; + // Solver returns the subscript that needs to be evaluated; // the final scriptSig is the signatures from that // and then the serialized subscript: - CScript subscript = scriptSig; - - txnouttype subType; - bool fSolved = - SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH; - // Append serialized subscript whether or not it is completely signed: - scriptSig << static_cast(subscript); - if (!fSolved) return false; + script = subscript = CScript(result[0].begin(), result[0].end()); + solved = solved && SignStep(creator, script, result, whichType, consensusBranchId) && whichType != TX_SCRIPTHASH; + result.push_back(std::vector(subscript.begin(), subscript.end())); } + sigdata.scriptSig = PushAll(result); + // Test solution - return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); + return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker(), consensusBranchId); +} + +SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn) +{ + SignatureData data; + assert(tx.vin.size() > nIn); + data.scriptSig = tx.vin[nIn].scriptSig; + return data; } -bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType) +void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data) +{ + assert(tx.vin.size() > nIn); + tx.vin[nIn].scriptSig = data.scriptSig; +} + +bool SignSignature( + const CKeyStore &keystore, + const CScript& fromPubKey, + CMutableTransaction& txTo, + unsigned int nIn, + const CAmount& amount, + int nHashType, + uint32_t consensusBranchId) { assert(nIn < txTo.vin.size()); - CTxIn& txin = txTo.vin[nIn]; CTransaction txToConst(txTo); - TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType); + TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType); - return ProduceSignature(creator, fromPubKey, txin.scriptSig); + SignatureData sigdata; + bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId); + UpdateTransaction(txTo, nIn, sigdata); + return ret; } -bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) +bool SignSignature( + const CKeyStore &keystore, + const CTransaction& txFrom, + CMutableTransaction& txTo, + unsigned int nIn, + int nHashType, + uint32_t consensusBranchId) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; assert(txin.prevout.n < txFrom.vout.size()); const CTxOut& txout = txFrom.vout[txin.prevout.n]; - return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType); + return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, consensusBranchId); } -static CScript PushAll(const vector& values) -{ - CScript result; - BOOST_FOREACH(const valtype& v, values) - result << v; - return result; -} - -static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, +static vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const vector& vSolutions, - const vector& sigs1, const vector& sigs2) + const vector& sigs1, const vector& sigs2, uint32_t consensusBranchId) { // Combine all the signatures we've got: set allsigs; @@ -190,7 +234,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (checker.CheckSig(sig, pubkey, scriptPubKey)) + if (checker.CheckSig(sig, pubkey, scriptPubKey, consensusBranchId)) { sigs[pubkey] = sig; break; @@ -199,87 +243,100 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC } // Now build a merged CScript: unsigned int nSigsHave = 0; - CScript result; result << OP_0; // pop-one-too-many workaround + std::vector result; result.push_back(valtype()); // pop-one-too-many workaround for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) { if (sigs.count(vSolutions[i+1])) { - result << sigs[vSolutions[i+1]]; + result.push_back(sigs[vSolutions[i+1]]); ++nSigsHave; } } // Fill any missing with OP_0: for (unsigned int i = nSigsHave; i < nSigsRequired; i++) - result << OP_0; + result.push_back(valtype()); return result; } -static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, +namespace +{ +struct Stacks +{ + std::vector script; + + Stacks() {} + explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_) {} + explicit Stacks(const SignatureData& data, uint32_t consensusBranchId) { + EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), consensusBranchId); + } + + SignatureData Output() const { + SignatureData result; + result.scriptSig = PushAll(script); + return result; + } +}; +} + +static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const txnouttype txType, const vector& vSolutions, - vector& sigs1, vector& sigs2) + Stacks sigs1, Stacks sigs2, uint32_t consensusBranchId) { switch (txType) { case TX_NONSTANDARD: case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: - if (sigs1.size() >= sigs2.size()) - return PushAll(sigs1); - return PushAll(sigs2); + if (sigs1.script.size() >= sigs2.script.size()) + return sigs1; + return sigs2; case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: - if (sigs1.empty() || sigs1[0].empty()) - return PushAll(sigs2); - return PushAll(sigs1); + if (sigs1.script.empty() || sigs1.script[0].empty()) + return sigs2; + return sigs1; case TX_SCRIPTHASH: - if (sigs1.empty() || sigs1.back().empty()) - return PushAll(sigs2); - else if (sigs2.empty() || sigs2.back().empty()) - return PushAll(sigs1); + if (sigs1.script.empty() || sigs1.script.back().empty()) + return sigs2; + else if (sigs2.script.empty() || sigs2.script.back().empty()) + return sigs1; else { // Recur to combine: - valtype spk = sigs1.back(); + valtype spk = sigs1.script.back(); CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; vector > vSolutions2; Solver(pubKey2, txType2, vSolutions2); - sigs1.pop_back(); - sigs2.pop_back(); - CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2); - result << spk; + sigs1.script.pop_back(); + sigs2.script.pop_back(); + Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, consensusBranchId); + result.script.push_back(spk); return result; } case TX_MULTISIG: - return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2); + return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, consensusBranchId)); + default: + return Stacks(); } - - return CScript(); } -CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, - const CScript& scriptSig1, const CScript& scriptSig2) -{ - TransactionSignatureChecker checker(&txTo, nIn); - return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2); -} - -CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const CScript& scriptSig1, const CScript& scriptSig2) +SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, + const SignatureData& scriptSig1, const SignatureData& scriptSig2, + uint32_t consensusBranchId) { txnouttype txType; vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); - vector stack1; - EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); - vector stack2; - EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); - - return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2); + return CombineSignatures( + scriptPubKey, checker, txType, vSolutions, + Stacks(scriptSig1, consensusBranchId), + Stacks(scriptSig2, consensusBranchId), + consensusBranchId).Output(); } namespace { @@ -289,7 +346,11 @@ class DummySignatureChecker : public BaseSignatureChecker public: DummySignatureChecker() {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const + bool CheckSig( + const std::vector& scriptSig, + const std::vector& vchPubKey, + const CScript& scriptCode, + uint32_t consensusBranchId) const { return true; } @@ -302,7 +363,11 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const return dummyChecker; } -bool DummySignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const +bool DummySignatureCreator::CreateSig( + std::vector& vchSig, + const CKeyID& keyid, + const CScript& scriptCode, + uint32_t consensusBranchId) const { // Create a dummy signature that is a valid DER-encoding vchSig.assign(72, '\000'); diff --git a/src/script/sign.h b/src/script/sign.h index 13f45007d..edd913d7f 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -27,7 +27,7 @@ public: virtual const BaseSignatureChecker& Checker() const =0; /** Create a singular (non-script) signature. */ - virtual bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0; + virtual bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const =0; }; /** A signature creator for transactions. */ @@ -35,12 +35,20 @@ class TransactionSignatureCreator : public BaseSignatureCreator { const CTransaction* txTo; unsigned int nIn; int nHashType; + CAmount amount; const TransactionSignatureChecker checker; public: - TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL); + TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); const BaseSignatureChecker& Checker() const { return checker; } - bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const; + bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const; +}; + +class MutableTransactionSignatureCreator : public TransactionSignatureCreator { + CTransaction tx; + +public: + MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {} }; /** A signature creator that just produces 72-byte empty signatyres. */ @@ -48,20 +56,46 @@ class DummySignatureCreator : public BaseSignatureCreator { public: DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {} const BaseSignatureChecker& Checker() const; - bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode) const; + bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const; +}; + +struct SignatureData { + CScript scriptSig; + + SignatureData() {} + explicit SignatureData(const CScript& script) : scriptSig(script) {} }; /** Produce a script signature using a generic signature creator. */ -bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig); +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata, uint32_t consensusBranchId); /** Produce a script signature for a transaction. */ -bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); +bool SignSignature( + const CKeyStore &keystore, + const CScript& fromPubKey, + CMutableTransaction& txTo, + unsigned int nIn, + const CAmount& amount, + int nHashType, + uint32_t consensusBranchId); +bool SignSignature( + const CKeyStore& keystore, + const CTransaction& txFrom, + CMutableTransaction& txTo, + unsigned int nIn, + int nHashType, + uint32_t consensusBranchId); /** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */ -CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2); +SignatureData CombineSignatures( + const CScript& scriptPubKey, + const BaseSignatureChecker& checker, + const SignatureData& scriptSig1, + const SignatureData& scriptSig2, + uint32_t consensusBranchId); -/** Combine two script signatures on transactions. */ -CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); +/** Extract signature data from a transaction, and insert it. */ +SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); +void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data); #endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/script/zcashconsensus.cpp b/src/script/zcashconsensus.cpp index 277b805e5..dbec305fc 100644 --- a/src/script/zcashconsensus.cpp +++ b/src/script/zcashconsensus.cpp @@ -5,6 +5,7 @@ #include "zcashconsensus.h" +#include "consensus/upgrades.h" #include "primitives/transaction.h" #include "pubkey.h" #include "script/interpreter.h" @@ -84,8 +85,16 @@ int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int // Regardless of the verification result, the tx did not error. set_error(err, zcashconsensus_ERR_OK); - - return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL); + PrecomputedTransactionData txdata(tx); + CAmount am(0); + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + return VerifyScript( + tx.vin[nIn].scriptSig, + CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), + flags, + TransactionSignatureChecker(&tx, nIn, am, txdata), + consensusBranchId, + NULL); } catch (const std::exception&) { return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing } diff --git a/src/script/zcashconsensus.h b/src/script/zcashconsensus.h index 65e40bbb6..ff13471c6 100644 --- a/src/script/zcashconsensus.h +++ b/src/script/zcashconsensus.h @@ -6,6 +6,8 @@ #ifndef BITCOIN_ZCASHCONSENSUS_H #define BITCOIN_ZCASHCONSENSUS_H +#include + #if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H) #include "config/bitcoin-config.h" #if defined(_WIN32) diff --git a/src/snark/Makefile b/src/snark/Makefile index 1583facf7..b865f992f 100644 --- a/src/snark/Makefile +++ b/src/snark/Makefile @@ -17,7 +17,7 @@ CXXFLAGS += -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wno-comment -Wfatal- DEPSRC = depsrc DEPINST = depinst -CXXFLAGS += -I$(DEPINST)/include -Isrc +CXXFLAGS += -I$(DEPINST)/include -Ilibsnark LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib LDLIBS += -lgmpxx -lgmp -lboost_program_options-mt -lsodium # List of .a files to include within libsnark.a and libsnark.so: @@ -44,23 +44,23 @@ ifneq ($(NO_SUPERCOP),1) endif LIB_SRCS = \ - src/algebra/curves/alt_bn128/alt_bn128_g1.cpp \ - src/algebra/curves/alt_bn128/alt_bn128_g2.cpp \ - src/algebra/curves/alt_bn128/alt_bn128_init.cpp \ - src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \ - src/algebra/curves/alt_bn128/alt_bn128_pp.cpp \ - src/common/profiling.cpp \ - src/common/utils.cpp \ - src/gadgetlib1/constraint_profiling.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \ + libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp \ + libsnark/common/profiling.cpp \ + libsnark/common/utils.cpp \ + libsnark/gadgetlib1/constraint_profiling.cpp \ ifeq ($(CURVE),BN128) LIB_SRCS += \ - src/algebra/curves/bn128/bn128_g1.cpp \ - src/algebra/curves/bn128/bn128_g2.cpp \ - src/algebra/curves/bn128/bn128_gt.cpp \ - src/algebra/curves/bn128/bn128_init.cpp \ - src/algebra/curves/bn128/bn128_pairing.cpp \ - src/algebra/curves/bn128/bn128_pp.cpp + libsnark/algebra/curves/bn128/bn128_g1.cpp \ + libsnark/algebra/curves/bn128/bn128_g2.cpp \ + libsnark/algebra/curves/bn128/bn128_gt.cpp \ + libsnark/algebra/curves/bn128/bn128_init.cpp \ + libsnark/algebra/curves/bn128/bn128_pairing.cpp \ + libsnark/algebra/curves/bn128/bn128_pp.cpp CXXFLAGS += -DBN_SUPPORT_SNARK AR_LIBS += $(DEPINST)/lib/libzm.a @@ -68,56 +68,56 @@ endif # FIXME: most of these are broken due to removed code. DISABLED_EXECUTABLES = \ - src/common/routing_algorithms/profiling/profile_routing_algorithms \ - src/common/routing_algorithms/tests/test_routing_algorithms \ - src/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \ - src/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \ - src/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \ - src/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \ - src/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \ - src/reductions/ram_to_r1cs/examples/demo_arithmetization \ - src/relations/arithmetic_programs/ssp/tests/test_ssp \ - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \ - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \ - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \ - src/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \ - src/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \ - src/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \ - src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \ - src/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \ - src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \ - src/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \ - src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \ - src/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \ - src/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \ - src/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \ - src/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \ - src/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark + libsnark/common/routing_algorithms/profiling/profile_routing_algorithms \ + libsnark/common/routing_algorithms/tests/test_routing_algorithms \ + libsnark/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \ + libsnark/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \ + libsnark/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \ + libsnark/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \ + libsnark/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \ + libsnark/reductions/ram_to_r1cs/examples/demo_arithmetization \ + libsnark/relations/arithmetic_programs/ssp/tests/test_ssp \ + libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \ + libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \ + libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \ + libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \ + libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \ + libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \ + libsnark/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \ + libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark EXECUTABLES = EXECUTABLES_WITH_GTEST = EXECUTABLES_WITH_SUPERCOP = \ - src/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark + libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark -GTEST_TESTS = src/gtests +GTEST_TESTS = libsnark/gtests GTEST_SRCS = \ - src/algebra/curves/tests/test_bilinearity.cpp \ - src/algebra/curves/tests/test_groups.cpp \ - src/algebra/fields/tests/test_bigint.cpp \ - src/algebra/fields/tests/test_fields.cpp \ - src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp \ - src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp \ - src/relations/arithmetic_programs/qap/tests/test_qap.cpp \ - src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp \ - src/gtests.cpp + libsnark/algebra/curves/tests/test_bilinearity.cpp \ + libsnark/algebra/curves/tests/test_groups.cpp \ + libsnark/algebra/fields/tests/test_bigint.cpp \ + libsnark/algebra/fields/tests/test_fields.cpp \ + libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp \ + libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp \ + libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp \ + libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp \ + libsnark/gtests.cpp DOCS = README.html @@ -192,7 +192,7 @@ $(LIB_OBJS) $(if $(NO_GTEST),,$(GTEST_OBJS)) $(EXEC_OBJS): %.o: %.cpp LIBGTEST_A = $(DEPINST)/lib/libgtest.a -$(LIBGTEST_A): $(GTESTDIR)/src/gtest-all.cc $(DEPINST_EXISTS) +$(LIBGTEST_A): $(GTESTDIR)/libsnark/gtest-all.cc $(DEPINST_EXISTS) $(CXX) -o $(DEPINST)/lib/gtest-all.o -I $(GTESTDIR) -c -isystem $(GTESTDIR)/include $< $(CXXFLAGS) $(AR) -rv $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o @@ -205,13 +205,13 @@ $(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS) libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS) $(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS) -src/gadgetlib2/tests/gadgetlib2_test: \ - src/gadgetlib2/tests/adapters_UTEST.cpp \ - src/gadgetlib2/tests/constraint_UTEST.cpp \ - src/gadgetlib2/tests/gadget_UTEST.cpp \ - src/gadgetlib2/tests/integration_UTEST.cpp \ - src/gadgetlib2/tests/protoboard_UTEST.cpp \ - src/gadgetlib2/tests/variable_UTEST.cpp +libsnark/gadgetlib2/tests/gadgetlib2_test: \ + libsnark/gadgetlib2/tests/adapters_UTEST.cpp \ + libsnark/gadgetlib2/tests/constraint_UTEST.cpp \ + libsnark/gadgetlib2/tests/gadget_UTEST.cpp \ + libsnark/gadgetlib2/tests/integration_UTEST.cpp \ + libsnark/gadgetlib2/tests/protoboard_UTEST.cpp \ + libsnark/gadgetlib2/tests/variable_UTEST.cpp $(EXECUTABLES): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) @@ -243,10 +243,10 @@ ifeq ($(PREFIX),) install: $(error Please provide PREFIX. E.g. make install PREFIX=/usr) else -HEADERS_SRC=$(shell find src -name '*.hpp' -o -name '*.tcc') -HEADERS_DEST=$(patsubst src/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC)) +HEADERS_SRC=$(shell find libsnark -name '*.hpp' -o -name '*.tcc') +HEADERS_DEST=$(patsubst libsnark/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC)) -$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: src/% +$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: libsnark/% mkdir -p $(shell dirname $@) cp $< $@ diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_g1.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_g2.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_init.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_init.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_pairing.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp diff --git a/src/snark/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp similarity index 100% rename from src/snark/src/algebra/curves/alt_bn128/alt_bn128_pp.hpp rename to src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp diff --git a/src/snark/src/algebra/curves/curve_utils.hpp b/src/snark/libsnark/algebra/curves/curve_utils.hpp similarity index 100% rename from src/snark/src/algebra/curves/curve_utils.hpp rename to src/snark/libsnark/algebra/curves/curve_utils.hpp diff --git a/src/snark/src/algebra/curves/curve_utils.tcc b/src/snark/libsnark/algebra/curves/curve_utils.tcc similarity index 100% rename from src/snark/src/algebra/curves/curve_utils.tcc rename to src/snark/libsnark/algebra/curves/curve_utils.tcc diff --git a/src/snark/src/algebra/curves/public_params.hpp b/src/snark/libsnark/algebra/curves/public_params.hpp similarity index 100% rename from src/snark/src/algebra/curves/public_params.hpp rename to src/snark/libsnark/algebra/curves/public_params.hpp diff --git a/src/snark/src/algebra/curves/tests/test_bilinearity.cpp b/src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp similarity index 100% rename from src/snark/src/algebra/curves/tests/test_bilinearity.cpp rename to src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp diff --git a/src/snark/src/algebra/curves/tests/test_groups.cpp b/src/snark/libsnark/algebra/curves/tests/test_groups.cpp similarity index 100% rename from src/snark/src/algebra/curves/tests/test_groups.cpp rename to src/snark/libsnark/algebra/curves/tests/test_groups.cpp diff --git a/src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp similarity index 100% rename from src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain.hpp rename to src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp diff --git a/src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc similarity index 100% rename from src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain.tcc rename to src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc diff --git a/src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp similarity index 100% rename from src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp rename to src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp diff --git a/src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc similarity index 100% rename from src/snark/src/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc rename to src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc diff --git a/src/snark/src/algebra/evaluation_domain/evaluation_domain.hpp b/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp similarity index 100% rename from src/snark/src/algebra/evaluation_domain/evaluation_domain.hpp rename to src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp diff --git a/src/snark/src/algebra/evaluation_domain/evaluation_domain.tcc b/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc similarity index 100% rename from src/snark/src/algebra/evaluation_domain/evaluation_domain.tcc rename to src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc diff --git a/src/snark/src/algebra/exponentiation/exponentiation.hpp b/src/snark/libsnark/algebra/exponentiation/exponentiation.hpp similarity index 100% rename from src/snark/src/algebra/exponentiation/exponentiation.hpp rename to src/snark/libsnark/algebra/exponentiation/exponentiation.hpp diff --git a/src/snark/src/algebra/exponentiation/exponentiation.tcc b/src/snark/libsnark/algebra/exponentiation/exponentiation.tcc similarity index 100% rename from src/snark/src/algebra/exponentiation/exponentiation.tcc rename to src/snark/libsnark/algebra/exponentiation/exponentiation.tcc diff --git a/src/snark/src/algebra/fields/bigint.hpp b/src/snark/libsnark/algebra/fields/bigint.hpp similarity index 100% rename from src/snark/src/algebra/fields/bigint.hpp rename to src/snark/libsnark/algebra/fields/bigint.hpp diff --git a/src/snark/src/algebra/fields/bigint.tcc b/src/snark/libsnark/algebra/fields/bigint.tcc similarity index 99% rename from src/snark/src/algebra/fields/bigint.tcc rename to src/snark/libsnark/algebra/fields/bigint.tcc index 9aaea0aed..95c658b19 100644 --- a/src/snark/src/algebra/fields/bigint.tcc +++ b/src/snark/libsnark/algebra/fields/bigint.tcc @@ -104,7 +104,7 @@ bool bigint::is_zero() const template size_t bigint::num_bits() const { - +/* for (long long i = max_bits(); i >= 0; --i) { if (this->test_bit(i)) @@ -114,7 +114,7 @@ size_t bigint::num_bits() const } return 0; -/* +*/ for (long long i = n-1; i >= 0; --i) { mp_limb_t x = this->data[i]; @@ -128,7 +128,6 @@ size_t bigint::num_bits() const } } return 0; -*/ } template diff --git a/src/snark/src/algebra/fields/field_utils.hpp b/src/snark/libsnark/algebra/fields/field_utils.hpp similarity index 100% rename from src/snark/src/algebra/fields/field_utils.hpp rename to src/snark/libsnark/algebra/fields/field_utils.hpp diff --git a/src/snark/src/algebra/fields/field_utils.tcc b/src/snark/libsnark/algebra/fields/field_utils.tcc similarity index 100% rename from src/snark/src/algebra/fields/field_utils.tcc rename to src/snark/libsnark/algebra/fields/field_utils.tcc diff --git a/src/snark/src/algebra/fields/fp.hpp b/src/snark/libsnark/algebra/fields/fp.hpp similarity index 100% rename from src/snark/src/algebra/fields/fp.hpp rename to src/snark/libsnark/algebra/fields/fp.hpp diff --git a/src/snark/src/algebra/fields/fp.tcc b/src/snark/libsnark/algebra/fields/fp.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp.tcc rename to src/snark/libsnark/algebra/fields/fp.tcc diff --git a/src/snark/src/algebra/fields/fp12_2over3over2.hpp b/src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp similarity index 100% rename from src/snark/src/algebra/fields/fp12_2over3over2.hpp rename to src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp diff --git a/src/snark/src/algebra/fields/fp12_2over3over2.tcc b/src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp12_2over3over2.tcc rename to src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc diff --git a/src/snark/src/algebra/fields/fp2.hpp b/src/snark/libsnark/algebra/fields/fp2.hpp similarity index 100% rename from src/snark/src/algebra/fields/fp2.hpp rename to src/snark/libsnark/algebra/fields/fp2.hpp diff --git a/src/snark/src/algebra/fields/fp2.tcc b/src/snark/libsnark/algebra/fields/fp2.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp2.tcc rename to src/snark/libsnark/algebra/fields/fp2.tcc diff --git a/src/snark/src/algebra/fields/fp6_3over2.hpp b/src/snark/libsnark/algebra/fields/fp6_3over2.hpp similarity index 100% rename from src/snark/src/algebra/fields/fp6_3over2.hpp rename to src/snark/libsnark/algebra/fields/fp6_3over2.hpp diff --git a/src/snark/src/algebra/fields/fp6_3over2.tcc b/src/snark/libsnark/algebra/fields/fp6_3over2.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp6_3over2.tcc rename to src/snark/libsnark/algebra/fields/fp6_3over2.tcc diff --git a/src/snark/src/algebra/fields/fp_aux.tcc b/src/snark/libsnark/algebra/fields/fp_aux.tcc similarity index 100% rename from src/snark/src/algebra/fields/fp_aux.tcc rename to src/snark/libsnark/algebra/fields/fp_aux.tcc diff --git a/src/snark/src/algebra/fields/tests/test_bigint.cpp b/src/snark/libsnark/algebra/fields/tests/test_bigint.cpp similarity index 100% rename from src/snark/src/algebra/fields/tests/test_bigint.cpp rename to src/snark/libsnark/algebra/fields/tests/test_bigint.cpp diff --git a/src/snark/src/algebra/fields/tests/test_fields.cpp b/src/snark/libsnark/algebra/fields/tests/test_fields.cpp similarity index 100% rename from src/snark/src/algebra/fields/tests/test_fields.cpp rename to src/snark/libsnark/algebra/fields/tests/test_fields.cpp diff --git a/src/snark/src/algebra/knowledge_commitment/knowledge_commitment.hpp b/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp similarity index 100% rename from src/snark/src/algebra/knowledge_commitment/knowledge_commitment.hpp rename to src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp diff --git a/src/snark/src/algebra/knowledge_commitment/knowledge_commitment.tcc b/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc similarity index 100% rename from src/snark/src/algebra/knowledge_commitment/knowledge_commitment.tcc rename to src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc diff --git a/src/snark/src/algebra/scalar_multiplication/kc_multiexp.hpp b/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/kc_multiexp.hpp rename to src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp diff --git a/src/snark/src/algebra/scalar_multiplication/kc_multiexp.tcc b/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/kc_multiexp.tcc rename to src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc diff --git a/src/snark/src/algebra/scalar_multiplication/multiexp.hpp b/src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/multiexp.hpp rename to src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp diff --git a/src/snark/src/algebra/scalar_multiplication/multiexp.tcc b/src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/multiexp.tcc rename to src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc diff --git a/src/snark/src/algebra/scalar_multiplication/wnaf.hpp b/src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/wnaf.hpp rename to src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp diff --git a/src/snark/src/algebra/scalar_multiplication/wnaf.tcc b/src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc similarity index 100% rename from src/snark/src/algebra/scalar_multiplication/wnaf.tcc rename to src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc diff --git a/src/snark/src/common/assert_except.hpp b/src/snark/libsnark/common/assert_except.hpp similarity index 100% rename from src/snark/src/common/assert_except.hpp rename to src/snark/libsnark/common/assert_except.hpp diff --git a/src/snark/src/common/data_structures/accumulation_vector.hpp b/src/snark/libsnark/common/data_structures/accumulation_vector.hpp similarity index 100% rename from src/snark/src/common/data_structures/accumulation_vector.hpp rename to src/snark/libsnark/common/data_structures/accumulation_vector.hpp diff --git a/src/snark/src/common/data_structures/accumulation_vector.tcc b/src/snark/libsnark/common/data_structures/accumulation_vector.tcc similarity index 100% rename from src/snark/src/common/data_structures/accumulation_vector.tcc rename to src/snark/libsnark/common/data_structures/accumulation_vector.tcc diff --git a/src/snark/src/common/data_structures/merkle_tree.hpp b/src/snark/libsnark/common/data_structures/merkle_tree.hpp similarity index 100% rename from src/snark/src/common/data_structures/merkle_tree.hpp rename to src/snark/libsnark/common/data_structures/merkle_tree.hpp diff --git a/src/snark/src/common/data_structures/merkle_tree.tcc b/src/snark/libsnark/common/data_structures/merkle_tree.tcc similarity index 100% rename from src/snark/src/common/data_structures/merkle_tree.tcc rename to src/snark/libsnark/common/data_structures/merkle_tree.tcc diff --git a/src/snark/src/common/data_structures/sparse_vector.hpp b/src/snark/libsnark/common/data_structures/sparse_vector.hpp similarity index 100% rename from src/snark/src/common/data_structures/sparse_vector.hpp rename to src/snark/libsnark/common/data_structures/sparse_vector.hpp diff --git a/src/snark/src/common/data_structures/sparse_vector.tcc b/src/snark/libsnark/common/data_structures/sparse_vector.tcc similarity index 100% rename from src/snark/src/common/data_structures/sparse_vector.tcc rename to src/snark/libsnark/common/data_structures/sparse_vector.tcc diff --git a/src/snark/src/common/default_types/ec_pp.hpp b/src/snark/libsnark/common/default_types/ec_pp.hpp similarity index 100% rename from src/snark/src/common/default_types/ec_pp.hpp rename to src/snark/libsnark/common/default_types/ec_pp.hpp diff --git a/src/snark/src/common/default_types/r1cs_ppzksnark_pp.hpp b/src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp similarity index 100% rename from src/snark/src/common/default_types/r1cs_ppzksnark_pp.hpp rename to src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp diff --git a/src/snark/src/common/profiling.cpp b/src/snark/libsnark/common/profiling.cpp similarity index 100% rename from src/snark/src/common/profiling.cpp rename to src/snark/libsnark/common/profiling.cpp diff --git a/src/snark/src/common/profiling.hpp b/src/snark/libsnark/common/profiling.hpp similarity index 100% rename from src/snark/src/common/profiling.hpp rename to src/snark/libsnark/common/profiling.hpp diff --git a/src/snark/src/common/serialization.hpp b/src/snark/libsnark/common/serialization.hpp similarity index 100% rename from src/snark/src/common/serialization.hpp rename to src/snark/libsnark/common/serialization.hpp diff --git a/src/snark/src/common/serialization.tcc b/src/snark/libsnark/common/serialization.tcc similarity index 100% rename from src/snark/src/common/serialization.tcc rename to src/snark/libsnark/common/serialization.tcc diff --git a/src/snark/src/common/template_utils.hpp b/src/snark/libsnark/common/template_utils.hpp similarity index 100% rename from src/snark/src/common/template_utils.hpp rename to src/snark/libsnark/common/template_utils.hpp diff --git a/src/snark/src/common/utils.cpp b/src/snark/libsnark/common/utils.cpp similarity index 100% rename from src/snark/src/common/utils.cpp rename to src/snark/libsnark/common/utils.cpp diff --git a/src/snark/src/common/utils.hpp b/src/snark/libsnark/common/utils.hpp similarity index 100% rename from src/snark/src/common/utils.hpp rename to src/snark/libsnark/common/utils.hpp diff --git a/src/snark/src/common/utils.tcc b/src/snark/libsnark/common/utils.tcc similarity index 100% rename from src/snark/src/common/utils.tcc rename to src/snark/libsnark/common/utils.tcc diff --git a/src/snark/src/gadgetlib1/constraint_profiling.cpp b/src/snark/libsnark/gadgetlib1/constraint_profiling.cpp similarity index 100% rename from src/snark/src/gadgetlib1/constraint_profiling.cpp rename to src/snark/libsnark/gadgetlib1/constraint_profiling.cpp diff --git a/src/snark/src/gadgetlib1/constraint_profiling.hpp b/src/snark/libsnark/gadgetlib1/constraint_profiling.hpp similarity index 100% rename from src/snark/src/gadgetlib1/constraint_profiling.hpp rename to src/snark/libsnark/gadgetlib1/constraint_profiling.hpp diff --git a/src/snark/src/gadgetlib1/examples/simple_example.hpp b/src/snark/libsnark/gadgetlib1/examples/simple_example.hpp similarity index 100% rename from src/snark/src/gadgetlib1/examples/simple_example.hpp rename to src/snark/libsnark/gadgetlib1/examples/simple_example.hpp diff --git a/src/snark/src/gadgetlib1/examples/simple_example.tcc b/src/snark/libsnark/gadgetlib1/examples/simple_example.tcc similarity index 100% rename from src/snark/src/gadgetlib1/examples/simple_example.tcc rename to src/snark/libsnark/gadgetlib1/examples/simple_example.tcc diff --git a/src/snark/src/gadgetlib1/gadget.hpp b/src/snark/libsnark/gadgetlib1/gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadget.tcc b/src/snark/libsnark/gadgetlib1/gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/basic_gadgets.hpp b/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/basic_gadgets.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/basic_gadgets.tcc b/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/basic_gadgets.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp b/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/gadget_from_r1cs.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc b/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/gadget_from_r1cs.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/hash_io.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/hash_io.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/hash_io.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/hash_io.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py diff --git a/src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp rename to src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc diff --git a/src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp similarity index 100% rename from src/snark/src/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp rename to src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp diff --git a/src/snark/src/gadgetlib1/pb_variable.hpp b/src/snark/libsnark/gadgetlib1/pb_variable.hpp similarity index 100% rename from src/snark/src/gadgetlib1/pb_variable.hpp rename to src/snark/libsnark/gadgetlib1/pb_variable.hpp diff --git a/src/snark/src/gadgetlib1/pb_variable.tcc b/src/snark/libsnark/gadgetlib1/pb_variable.tcc similarity index 100% rename from src/snark/src/gadgetlib1/pb_variable.tcc rename to src/snark/libsnark/gadgetlib1/pb_variable.tcc diff --git a/src/snark/src/gadgetlib1/protoboard.hpp b/src/snark/libsnark/gadgetlib1/protoboard.hpp similarity index 100% rename from src/snark/src/gadgetlib1/protoboard.hpp rename to src/snark/libsnark/gadgetlib1/protoboard.hpp diff --git a/src/snark/src/gadgetlib1/protoboard.tcc b/src/snark/libsnark/gadgetlib1/protoboard.tcc similarity index 100% rename from src/snark/src/gadgetlib1/protoboard.tcc rename to src/snark/libsnark/gadgetlib1/protoboard.tcc diff --git a/src/snark/src/gtests.cpp b/src/snark/libsnark/gtests.cpp similarity index 100% rename from src/snark/src/gtests.cpp rename to src/snark/libsnark/gtests.cpp diff --git a/src/snark/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp b/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp similarity index 100% rename from src/snark/src/reductions/r1cs_to_qap/r1cs_to_qap.hpp rename to src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp diff --git a/src/snark/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc b/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc similarity index 100% rename from src/snark/src/reductions/r1cs_to_qap/r1cs_to_qap.tcc rename to src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc diff --git a/src/snark/src/relations/arithmetic_programs/qap/qap.hpp b/src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp similarity index 100% rename from src/snark/src/relations/arithmetic_programs/qap/qap.hpp rename to src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp diff --git a/src/snark/src/relations/arithmetic_programs/qap/qap.tcc b/src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc similarity index 100% rename from src/snark/src/relations/arithmetic_programs/qap/qap.tcc rename to src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc diff --git a/src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp b/src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp similarity index 100% rename from src/snark/src/relations/arithmetic_programs/qap/tests/test_qap.cpp rename to src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp diff --git a/src/snark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp similarity index 100% rename from src/snark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp rename to src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp diff --git a/src/snark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc similarity index 100% rename from src/snark/src/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc rename to src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc diff --git a/src/snark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp similarity index 100% rename from src/snark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp rename to src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp diff --git a/src/snark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc similarity index 100% rename from src/snark/src/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc rename to src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc diff --git a/src/snark/src/relations/variable.hpp b/src/snark/libsnark/relations/variable.hpp similarity index 100% rename from src/snark/src/relations/variable.hpp rename to src/snark/libsnark/relations/variable.hpp diff --git a/src/snark/src/relations/variable.tcc b/src/snark/libsnark/relations/variable.tcc similarity index 100% rename from src/snark/src/relations/variable.tcc rename to src/snark/libsnark/relations/variable.tcc diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp diff --git a/src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp similarity index 100% rename from src/snark/src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp rename to src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp diff --git a/src/txdb.cpp b/src/txdb.cpp index c188a5ac4..8e3004ec6 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -517,9 +517,15 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nNonce = diskindex.nNonce; pindexNew->nSolution = diskindex.nSolution; pindexNew->nStatus = diskindex.nStatus; + pindexNew->nCachedBranchId = diskindex.nCachedBranchId; pindexNew->nTx = diskindex.nTx; pindexNew->nSproutValue = diskindex.nSproutValue; + // Consistency checks + auto header = pindexNew->GetBlockHeader(); + if (header.GetHash() != pindexNew->GetBlockHash()) + return error("LoadBlockIndex(): block header inconsistency detected: on-disk = %s, in-memory = %s", + diskindex.ToString(), pindexNew->ToString()); if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); diff --git a/src/txdb.h b/src/txdb.h index 3e01becc2..6623eee9e 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -32,8 +32,8 @@ struct CSpentIndexValue; class uint256; //! -dbcache default (MiB) -static const int64_t nDefaultDbCache = 100; -//! max. -dbcache in (MiB) +static const int64_t nDefaultDbCache = 450; +//! max. -dbcache (MiB) static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024; //! min. -dbcache in (MiB) static const int64_t nMinDbCache = 4; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 71dcab0d6..a9e354c62 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -11,6 +11,7 @@ #include "main.h" #include "policy/fees.h" #include "streams.h" +#include "timedata.h" #include "util.h" #include "utilmoneystr.h" #include "version.h" @@ -18,20 +19,24 @@ using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(): - nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), hadNoDependencies(false) + nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), + hadNoDependencies(false), spendsCoinbase(false) { nHeight = MEMPOOL_HEIGHT; } CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _dPriority, - unsigned int _nHeight, bool poolHasNoInputsOf): + unsigned int _nHeight, bool poolHasNoInputsOf, + bool _spendsCoinbase, uint32_t _nBranchId): tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight), - hadNoDependencies(poolHasNoInputsOf) + hadNoDependencies(poolHasNoInputsOf), + spendsCoinbase(_spendsCoinbase), nBranchId(_nBranchId) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); nModSize = tx.CalculateModifiedSize(nTxSize); nUsageSize = RecursiveDynamicUsage(tx); + feeRate = CFeeRate(nFee, nTxSize); } CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) @@ -54,7 +59,7 @@ CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : // Sanity checks off by default for performance, because otherwise // accepting transactions becomes O(N^2) where N is the number // of transactions in the pool - fSanityCheck = false; + nCheckFrequency = 0; minerPolicyEstimator = new CBlockPolicyEstimator(_minRelayFee); } @@ -96,8 +101,8 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, // Used by main.cpp AcceptToMemoryPool(), which DOES do // all the appropriate checks. LOCK(cs); - mapTx[hash] = entry; - const CTransaction& tx = mapTx[hash].GetTx(); + mapTx.insert(entry); + const CTransaction& tx = mapTx.find(hash)->GetTx(); for (unsigned int i = 0; i < tx.vin.size(); i++) mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { @@ -277,7 +282,7 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem txToRemove.pop_front(); if (!mapTx.count(hash)) continue; - const CTransaction& tx = mapTx[hash].GetTx(); + const CTransaction& tx = mapTx.find(hash)->GetTx(); if (fRecursive) { for (unsigned int i = 0; i < tx.vout.size(); i++) { std::map::iterator it = mapNextTx.find(COutPoint(hash, i)); @@ -295,8 +300,8 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem } removed.push_back(tx); - totalTxSize -= mapTx[hash].GetTxSize(); - cachedInnerUsage -= mapTx[hash].DynamicMemoryUsage(); + totalTxSize -= mapTx.find(hash)->GetTxSize(); + cachedInnerUsage -= mapTx.find(hash)->DynamicMemoryUsage(); mapTx.erase(hash); nTransactionsUpdated++; minerPolicyEstimator->removeTx(hash); @@ -306,22 +311,26 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem } } -void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight) +void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) { - // Remove transactions spending a coinbase which are now immature + // Remove transactions spending a coinbase which are now immature and no-longer-final transactions LOCK(cs); list transactionsToRemove; - for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { - const CTransaction& tx = it->second.GetTx(); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { - std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); - if (it2 != mapTx.end()) - continue; - const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); - if (fSanityCheck) assert(coins); - if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { - transactionsToRemove.push_back(tx); - break; + for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { + const CTransaction& tx = it->GetTx(); + if (!CheckFinalTx(tx, flags)) { + transactionsToRemove.push_back(tx); + } else if (it->GetSpendsCoinbase()) { + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); + if (it2 != mapTx.end()) + continue; + const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); + if (nCheckFrequency != 0) assert(coins); + if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) { + transactionsToRemove.push_back(tx); + break; + } } } } @@ -341,8 +350,8 @@ void CTxMemPool::removeWithAnchor(const uint256 &invalidRoot) LOCK(cs); list transactionsToRemove; - for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { - const CTransaction& tx = it->second.GetTx(); + for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { + const CTransaction& tx = it->GetTx(); BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) { if (joinsplit.anchor == invalidRoot) { transactionsToRemove.push_back(tx); @@ -387,6 +396,24 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list } } +void CTxMemPool::removeExpired(unsigned int nBlockHeight) +{ + // Remove expired txs from the mempool + LOCK(cs); + list transactionsToRemove; + for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) + { + const CTransaction& tx = it->GetTx(); + if (IsExpiredTx(tx, nBlockHeight)) { + transactionsToRemove.push_back(tx); + } + } + for (const CTransaction& tx : transactionsToRemove) { + list removed; + remove(tx, removed, true); + } +} + /** * Called when a block is connected. Removes from mempool and updates the miner fee estimator. */ @@ -398,8 +425,10 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i BOOST_FOREACH(const CTransaction& tx, vtx) { uint256 hash = tx.GetHash(); - if (mapTx.count(hash)) - entries.push_back(mapTx[hash]); + + indexed_transaction_set::iterator i = mapTx.find(hash); + if (i != mapTx.end()) + entries.push_back(*i); } BOOST_FOREACH(const CTransaction& tx, vtx) { @@ -412,6 +441,28 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); } +/** + * Called whenever the tip changes. Removes transactions which don't commit to + * the given branch ID from the mempool. + */ +void CTxMemPool::removeWithoutBranchId(uint32_t nMemPoolBranchId) +{ + LOCK(cs); + std::list transactionsToRemove; + + for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { + const CTransaction& tx = it->GetTx(); + if (it->GetValidatedBranchId() != nMemPoolBranchId) { + transactionsToRemove.push_back(tx); + } + } + + for (const CTransaction& tx : transactionsToRemove) { + std::list removed; + remove(tx, removed, true); + } +} + void CTxMemPool::clear() { LOCK(cs); @@ -424,7 +475,10 @@ void CTxMemPool::clear() void CTxMemPool::check(const CCoinsViewCache *pcoins) const { - if (!fSanityCheck) + if (nCheckFrequency == 0) + return; + + if (insecure_rand() >= nCheckFrequency) return; LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); @@ -433,20 +487,21 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const uint64_t innerUsage = 0; CCoinsViewCache mempoolDuplicate(const_cast(pcoins)); + const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate); LOCK(cs); list waitingOnDependants; - for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { + for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { unsigned int i = 0; - checkTotal += it->second.GetTxSize(); - innerUsage += it->second.DynamicMemoryUsage(); - const CTransaction& tx = it->second.GetTx(); + checkTotal += it->GetTxSize(); + innerUsage += it->DynamicMemoryUsage(); + const CTransaction& tx = it->GetTx(); bool fDependsWait = false; BOOST_FOREACH(const CTxIn &txin, tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. - std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); + indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) { - const CTransaction& tx2 = it2->second.GetTx(); + const CTransaction& tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); fDependsWait = true; } else { @@ -484,11 +539,13 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const intermediates.insert(std::make_pair(tree.root(), tree)); } if (fDependsWait) - waitingOnDependants.push_back(&it->second); + waitingOnDependants.push_back(&(*it)); else { CValidationState state; - assert(ContextualCheckInputs(tx, state, mempoolDuplicate, false, 0, false, Params().GetConsensus(), NULL)); - UpdateCoins(tx, state, mempoolDuplicate, 1000000); + bool fCheckResult = tx.IsCoinBase() || + Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight, Params().GetConsensus()); + assert(fCheckResult); + UpdateCoins(tx, mempoolDuplicate, 1000000); } } unsigned int stepsSinceLastRemove = 0; @@ -501,15 +558,17 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const stepsSinceLastRemove++; assert(stepsSinceLastRemove < waitingOnDependants.size()); } else { - assert(ContextualCheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, Params().GetConsensus(), NULL)); - UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000); + bool fCheckResult = entry->GetTx().IsCoinBase() || + Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight, Params().GetConsensus()); + assert(fCheckResult); + UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000); stepsSinceLastRemove = 0; } } for (std::map::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { uint256 hash = it->second.ptx->GetHash(); - map::const_iterator it2 = mapTx.find(hash); - const CTransaction& tx = it2->second.GetTx(); + indexed_transaction_set::const_iterator it2 = mapTx.find(hash); + const CTransaction& tx = it2->GetTx(); assert(it2 != mapTx.end()); assert(&tx == it->second.ptx); assert(tx.vin.size() > it->second.n); @@ -518,8 +577,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const for (std::map::const_iterator it = mapNullifiers.begin(); it != mapNullifiers.end(); it++) { uint256 hash = it->second->GetHash(); - map::const_iterator it2 = mapTx.find(hash); - const CTransaction& tx = it2->second.GetTx(); + indexed_transaction_set::const_iterator it2 = mapTx.find(hash); + const CTransaction& tx = it2->GetTx(); assert(it2 != mapTx.end()); assert(&tx == it->second); } @@ -534,16 +593,16 @@ void CTxMemPool::queryHashes(vector& vtxid) LOCK(cs); vtxid.reserve(mapTx.size()); - for (map::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) - vtxid.push_back((*mi).first); + for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) + vtxid.push_back(mi->GetTx().GetHash()); } bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const { LOCK(cs); - map::const_iterator i = mapTx.find(hash); + indexed_transaction_set::const_iterator i = mapTx.find(hash); if (i == mapTx.end()) return false; - result = i->second.GetTx(); + result = i->GetTx(); return true; } diff --git a/src/txmempool.h b/src/txmempool.h index b7320115d..668c7a04e 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -15,6 +15,10 @@ #include "primitives/transaction.h" #include "sync.h" +#undef foreach +#include "boost/multi_index_container.hpp" +#include "boost/multi_index/ordered_index.hpp" + class CAutoFile; inline double AllowFreeThreshold() @@ -43,25 +47,54 @@ private: size_t nTxSize; //! ... and avoid recomputing tx size size_t nModSize; //! ... and modified size for priority size_t nUsageSize; //! ... and total memory usage + CFeeRate feeRate; //! ... and fee per kB int64_t nTime; //! Local time when entering the mempool double dPriority; //! Priority when entering the mempool unsigned int nHeight; //! Chain height when entering the mempool bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool + bool spendsCoinbase; //! keep track of transactions that spend a coinbase + uint32_t nBranchId; //! Branch ID this transaction is known to commit to, cached for efficiency public: CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, - int64_t _nTime, double _dPriority, unsigned int _nHeight, bool poolHasNoInputsOf = false); + int64_t _nTime, double _dPriority, unsigned int _nHeight, + bool poolHasNoInputsOf, bool spendsCoinbase, uint32_t nBranchId); CTxMemPoolEntry(); CTxMemPoolEntry(const CTxMemPoolEntry& other); const CTransaction& GetTx() const { return this->tx; } double GetPriority(unsigned int currentHeight) const; CAmount GetFee() const { return nFee; } + CFeeRate GetFeeRate() const { return feeRate; } size_t GetTxSize() const { return nTxSize; } int64_t GetTime() const { return nTime; } unsigned int GetHeight() const { return nHeight; } bool WasClearAtEntry() const { return hadNoDependencies; } size_t DynamicMemoryUsage() const { return nUsageSize; } + + bool GetSpendsCoinbase() const { return spendsCoinbase; } + uint32_t GetValidatedBranchId() const { return nBranchId; } +}; + +// extracts a TxMemPoolEntry's transaction hash +struct mempoolentry_txid +{ + typedef uint256 result_type; + result_type operator() (const CTxMemPoolEntry &entry) const + { + return entry.GetTx().GetHash(); + } +}; + +class CompareTxMemPoolEntryByFee +{ +public: + bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) + { + if (a.GetFeeRate() == b.GetFeeRate()) + return a.GetTime() < b.GetTime(); + return a.GetFeeRate() > b.GetFeeRate(); + } }; class CBlockPolicyEstimator; @@ -93,7 +126,7 @@ public: class CTxMemPool { private: - bool fSanityCheck; //! Normally false, true if -checkmempool or -regtest + uint32_t nCheckFrequency; //! Value n means that n times in 2^32 we check. unsigned int nTransactionsUpdated; CBlockPolicyEstimator* minerPolicyEstimator; @@ -101,8 +134,21 @@ private: uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves) public: + typedef boost::multi_index_container< + CTxMemPoolEntry, + boost::multi_index::indexed_by< + // sorted by txid + boost::multi_index::ordered_unique, + // sorted by fee rate + boost::multi_index::ordered_non_unique< + boost::multi_index::identity, + CompareTxMemPoolEntryByFee + > + > + > indexed_transaction_set; + mutable CCriticalSection cs; - std::map mapTx; + indexed_transaction_set mapTx; private: typedef std::map addressDeltaMap; @@ -132,7 +178,7 @@ public: * check does nothing. */ void check(const CCoinsViewCache *pcoins) const; - void setSanityCheck(bool _fSanityCheck) { fSanityCheck = _fSanityCheck; } + void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967296.0; } bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true); @@ -147,10 +193,12 @@ public: void remove(const CTransaction &tx, std::list& removed, bool fRecursive = false); void removeWithAnchor(const uint256 &invalidRoot); - void removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight); + void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); void removeConflicts(const CTransaction &tx, std::list& removed); + void removeExpired(unsigned int nBlockHeight); void removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, std::list& conflicts, bool fCurrentEstimate = true); + void removeWithoutBranchId(uint32_t nMemPoolBranchId); void clear(); void queryHashes(std::vector& vtxid); void pruneSpent(const uint256& hash, CCoins &coins); diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 054992cfb..0a5fbb3d2 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include using namespace std; @@ -46,6 +47,20 @@ string SanitizeFilename(const string& str) return strResult; } +std::string HexInt(uint32_t val) +{ + std::stringstream ss; + ss << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << val; + return ss.str(); +} + +uint32_t ParseHexToUInt32(const std::string& str) { + std::istringstream converter(str); + uint32_t value; + converter >> std::hex >> value; + return value; +} + const signed char p_util_hexdigit[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index d6973a130..ccdc6a76b 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -24,6 +24,8 @@ std::string SanitizeFilename(const std::string& str); std::string SanitizeString(const std::string& str); +std::string HexInt(uint32_t val); +uint32_t ParseHexToUInt32(const std::string& str); std::vector ParseHex(const char* psz); std::vector ParseHex(const std::string& str); signed char HexDigit(char c); diff --git a/src/utiltest.cpp b/src/utiltest.cpp index e91a796e3..4599cec3c 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -4,6 +4,8 @@ #include "utiltest.h" +#include "consensus/upgrades.h" + CWalletTx GetValidReceive(ZCJoinSplit& params, const libzcash::SpendingKey& sk, CAmount value, bool randomInputs) { @@ -45,9 +47,10 @@ CWalletTx GetValidReceive(ZCJoinSplit& params, mtx.vjoinsplit.push_back(jsdesc); // Empty output script. + uint32_t consensusBranchId = SPROUT_BRANCH_ID; CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, @@ -129,9 +132,10 @@ CWalletTx GetValidSpend(ZCJoinSplit& params, mtx.vjoinsplit.push_back(jsdesc); // Empty output script. + uint32_t consensusBranchId = SPROUT_BRANCH_ID; CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, diff --git a/src/version.h b/src/version.h index 91a464030..25527895d 100644 --- a/src/version.h +++ b/src/version.h @@ -9,7 +9,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 170002; +static const int PROTOCOL_VERSION = 170003; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -24,10 +24,6 @@ static const int MIN_PEER_PROTO_VERSION = 170002; //! if possible, avoid requesting addresses nodes older than this static const int CADDR_TIME_VERSION = 31402; -//! only request blocks from nodes outside this range of versions -static const int NOBLKS_VERSION_START = 32000; -static const int NOBLKS_VERSION_END = 32400; - //! BIP 0031, pong message, is enabled for all versions AFTER this one static const int BIP0031_VERSION = 60000; diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 59cd3a8fb..d4d76b5b0 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -5,6 +5,7 @@ #include "asyncrpcoperation_sendmany.h" #include "asyncrpcqueue.h" #include "amount.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "init.h" #include "main.h" @@ -50,13 +51,14 @@ int find_output(UniValue obj, int n) { } AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany( + CMutableTransaction contextualTx, std::string fromAddress, std::vector tOutputs, std::vector zOutputs, int minDepth, CAmount fee, UniValue contextInfo) : - fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee), contextinfo_(contextInfo) + tx_(contextualTx), fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee), contextinfo_(contextInfo) { assert(fee_ >= 0); @@ -335,6 +337,12 @@ bool AsyncRPCOperation_sendmany::main_impl() { LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total)); LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee)); + // Grab the current consensus branch ID + { + LOCK(cs_main); + consensusBranchId_ = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + } + /** * SCENARIO #1 * @@ -370,7 +378,6 @@ bool AsyncRPCOperation_sendmany::main_impl() { // Prepare raw transaction to handle JoinSplits CMutableTransaction mtx(tx_); - mtx.nVersion = 2; crypto_sign_keypair(joinSplitPubKey_.begin(), joinSplitPrivKey_); mtx.joinSplitPubKey = joinSplitPubKey_; tx_ = CTransaction(mtx); @@ -993,7 +1000,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_); // Add the signature if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index 69bdbe315..113f11f49 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -51,7 +51,7 @@ struct WitnessAnchorData { class AsyncRPCOperation_sendmany : public AsyncRPCOperation { public: - AsyncRPCOperation_sendmany(std::string fromAddress, std::vector tOutputs, std::vector zOutputs, int minDepth, CAmount fee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE, UniValue contextInfo = NullUniValue); + AsyncRPCOperation_sendmany(CMutableTransaction contextualTx, std::string fromAddress, std::vector tOutputs, std::vector zOutputs, int minDepth, CAmount fee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE, UniValue contextInfo = NullUniValue); virtual ~AsyncRPCOperation_sendmany(); // We don't want to be copied or moved around @@ -73,6 +73,7 @@ private: UniValue contextinfo_; // optional data to include in return value from getStatus() + uint32_t consensusBranchId_; CAmount fee_; int mindepth_; std::string fromaddress_; diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index a845c6085..527f810bc 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -4,6 +4,7 @@ #include "asyncrpcqueue.h" #include "amount.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "init.h" #include "main.h" @@ -52,12 +53,15 @@ static int find_output(UniValue obj, int n) { } AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase( + CMutableTransaction contextualTx, std::vector inputs, std::string toAddress, CAmount fee, UniValue contextInfo) : - inputs_(inputs), fee_(fee), contextinfo_(contextInfo) + tx_(contextualTx), inputs_(inputs), fee_(fee), contextinfo_(contextInfo) { + assert(contextualTx.nVersion >= 2); // transaction format version must support vjoinsplit + if (fee < 0 || fee > MAX_MONEY) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee is out of range"); } @@ -213,7 +217,6 @@ bool AsyncRPCOperation_shieldcoinbase::main_impl() { // Prepare raw transaction to handle JoinSplits CMutableTransaction mtx(tx_); - mtx.nVersion = 2; crypto_sign_keypair(joinSplitPubKey_.begin(), joinSplitPrivKey_); mtx.joinSplitPubKey = joinSplitPubKey_; tx_ = CTransaction(mtx); @@ -300,12 +303,15 @@ void AsyncRPCOperation_shieldcoinbase::sign_send_raw_transaction(UniValue obj) UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInfo & info) { + uint32_t consensusBranchId; uint256 anchor; { LOCK(cs_main); + consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); anchor = pcoinsTip->GetBestAnchor(); } + if (anchor.IsNull()) { throw std::runtime_error("anchor is null"); } @@ -367,7 +373,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.h b/src/wallet/asyncrpcoperation_shieldcoinbase.h index 379aa5bd7..c7faf28e8 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.h +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.h @@ -42,7 +42,7 @@ struct ShieldCoinbaseJSInfo class AsyncRPCOperation_shieldcoinbase : public AsyncRPCOperation { public: - AsyncRPCOperation_shieldcoinbase(std::vector inputs, std::string toAddress, CAmount fee = SHIELD_COINBASE_DEFAULT_MINERS_FEE, UniValue contextInfo = NullUniValue); + AsyncRPCOperation_shieldcoinbase(CMutableTransaction contextualTx, std::vector inputs, std::string toAddress, CAmount fee = SHIELD_COINBASE_DEFAULT_MINERS_FEE, UniValue contextInfo = NullUniValue); virtual ~AsyncRPCOperation_shieldcoinbase(); // We don't want to be copied or moved around diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index f73cc1a9a..b39275f67 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -1046,36 +1046,3 @@ TEST(wallet_tests, MarkAffectedTransactionsDirty) { wallet.MarkAffectedTransactionsDirty(wtx2); EXPECT_FALSE(wallet.mapWallet[hash].fDebitCached); } - -TEST(wallet_tests, NoteLocking) { - TestWallet wallet; - - auto sk = libzcash::SpendingKey::random(); - wallet.AddSpendingKey(sk); - - auto wtx = GetValidReceive(sk, 10, true); - auto wtx2 = GetValidReceive(sk, 10, true); - - JSOutPoint jsoutpt {wtx.GetHash(), 0, 0}; - JSOutPoint jsoutpt2 {wtx2.GetHash(),0, 0}; - - // Test selective locking - wallet.LockNote(jsoutpt); - EXPECT_TRUE(wallet.IsLockedNote(jsoutpt.hash, jsoutpt.js, jsoutpt.n)); - EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2.hash, jsoutpt2.js, jsoutpt2.n)); - - // Test selective unlocking - wallet.UnlockNote(jsoutpt); - EXPECT_FALSE(wallet.IsLockedNote(jsoutpt.hash, jsoutpt.js, jsoutpt.n)); - - // Test multiple locking - wallet.LockNote(jsoutpt); - wallet.LockNote(jsoutpt2); - EXPECT_TRUE(wallet.IsLockedNote(jsoutpt.hash, jsoutpt.js, jsoutpt.n)); - EXPECT_TRUE(wallet.IsLockedNote(jsoutpt2.hash, jsoutpt2.js, jsoutpt2.n)); - - // Test unlock all - wallet.UnlockAllNotes(); - EXPECT_FALSE(wallet.IsLockedNote(jsoutpt.hash, jsoutpt.js, jsoutpt.n)); - EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2.hash, jsoutpt2.js, jsoutpt2.n)); -} diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp index 21a5901a1..539cf4b2a 100644 --- a/src/wallet/rpcdisclosure.cpp +++ b/src/wallet/rpcdisclosure.cpp @@ -303,4 +303,3 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp) return o; } - diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index e06c8dde7..2000562bf 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -235,11 +235,11 @@ UniValue z_importwallet(const UniValue& params, bool fHelp) "1. \"filename\" (string, required) The wallet file\n" "\nExamples:\n" "\nDump the wallet\n" - + HelpExampleCli("z_exportwallet", "\"test\"") + + + HelpExampleCli("z_exportwallet", "\"nameofbackup\"") + "\nImport the wallet\n" - + HelpExampleCli("z_importwallet", "\"test\"") + + + HelpExampleCli("z_importwallet", "\"path/to/exportdir/nameofbackup\"") + "\nImport using the json rpc call\n" - + HelpExampleRpc("z_importwallet", "\"test\"") + + HelpExampleRpc("z_importwallet", "\"path/to/exportdir/nameofbackup\"") ); return importwallet_impl(params, fHelp, true); @@ -258,11 +258,11 @@ UniValue importwallet(const UniValue& params, bool fHelp) "1. \"filename\" (string, required) The wallet file\n" "\nExamples:\n" "\nDump the wallet\n" - + HelpExampleCli("dumpwallet", "\"test\"") + + + HelpExampleCli("dumpwallet", "\"nameofbackup\"") + "\nImport the wallet\n" - + HelpExampleCli("importwallet", "\"test\"") + + + HelpExampleCli("importwallet", "\"path/to/exportdir/nameofbackup\"") + "\nImport using the json rpc call\n" - + HelpExampleRpc("importwallet", "\"test\"") + + HelpExampleRpc("importwallet", "\"path/to/exportdir/nameofbackup\"") ); return importwallet_impl(params, fHelp, false); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d9d7aec2b..a2ddc0bf8 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6,6 +6,7 @@ #include "amount.h" #include "base58.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "init.h" #include "main.h" @@ -24,6 +25,7 @@ #include "utiltime.h" #include "asyncrpcoperation.h" #include "asyncrpcqueue.h" +#include "wallet/asyncrpcoperation_mergetoaddress.h" #include "wallet/asyncrpcoperation_sendmany.h" #include "wallet/asyncrpcoperation_shieldcoinbase.h" @@ -85,6 +87,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight)); } uint256 hash = wtx.GetHash(); entry.push_back(Pair("txid", hash.GetHex())); @@ -2719,7 +2722,12 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp) } else if (benchmarktype == "verifyequihash") { sample_times.push_back(benchmark_verify_equihash()); } else if (benchmarktype == "validatelargetx") { - sample_times.push_back(benchmark_large_tx()); + // Number of inputs in the spending transaction that we will simulate + int nInputs = 555; + if (params.size() >= 3) { + nInputs = params[2].get_int(); + } + sample_times.push_back(benchmark_large_tx(nInputs)); } else if (benchmarktype == "trydecryptnotes") { int nAddrs = params[2].get_int(); sample_times.push_back(benchmark_try_decrypt_notes(nAddrs)); @@ -2979,7 +2987,8 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL); + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, @@ -3657,9 +3666,20 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) o.push_back(Pair("fee", std::stod(FormatMoney(nFee)))); UniValue contextInfo = o; + // Contextual transaction we will build on + int nextBlockHeight = chainActive.Height() + 1; + CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight); + bool isShielded = !fromTaddr || zaddrRecipients.size() > 0; + if (contextualTx.nVersion == 1 && isShielded) { + contextualTx.nVersion = 2; // Tx format should support vjoinsplits + } + if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta; + } + // Create operation and add to global queue std::shared_ptr q = getAsyncRPCQueue(); - std::shared_ptr operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) ); + std::shared_ptr operation( new AsyncRPCOperation_sendmany(contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) ); q->addOperation(operation); AsyncRPCOperationId operationId = operation->getId(); return operationId; @@ -3841,9 +3861,20 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) contextInfo.push_back(Pair("toaddress", params[1])); contextInfo.push_back(Pair("fee", ValueFromAmount(nFee))); + // Contextual transaction we will build on + int nextBlockHeight = chainActive.Height() + 1; + CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction( + Params().GetConsensus(), nextBlockHeight); + if (contextualTx.nVersion == 1) { + contextualTx.nVersion = 2; // Tx format should support vjoinsplits + } + if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta; + } + // Create operation and add to global queue std::shared_ptr q = getAsyncRPCQueue(); - std::shared_ptr operation( new AsyncRPCOperation_shieldcoinbase(inputs, destaddress, nFee, contextInfo) ); + std::shared_ptr operation( new AsyncRPCOperation_shieldcoinbase(contextualTx, inputs, destaddress, nFee, contextInfo) ); q->addOperation(operation); AsyncRPCOperationId operationId = operation->getId(); @@ -3858,6 +3889,348 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) } +#define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50 +#define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10 + +#define JOINSPLIT_SIZE JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) + +UniValue z_mergetoaddress(const UniValue& params, bool fHelp) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-zmergetoaddress", false); + std::string strDisabledMsg = ""; + if (!fEnableMergeToAddress) { + strDisabledMsg = "\nWARNING: z_mergetoaddress is DISABLED but can be enabled as an experimental feature.\n"; + } + + if (fHelp || params.size() < 2 || params.size() > 6) + throw runtime_error( + "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n" + + strDisabledMsg + + "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`" + "\nto combine those into a single note." + "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they" + "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs." + "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit" + "\nparameter is set to zero, the -mempooltxinputlimit option will determine the number of UTXOs. Any limit is" + "\nconstrained by the consensus rule defining a maximum transaction size of " + + strprintf("%d bytes.", MAX_TX_SIZE) + + HelpRequiringPassphrase() + "\n" + "\nArguments:\n" + "1. fromaddresses (string, required) A JSON array with addresses.\n" + " The following special strings are accepted inside the array:\n" + " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n" + " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n" + " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n" + " If a special string is given, any given addresses of that type will be ignored.\n" + " [\n" + " \"address\" (string) Can be a t-addr or a z-addr\n" + " ,...\n" + " ]\n" + "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n" + "3. fee (numeric, optional, default=" + + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n" + "4. transparent_limit (numeric, optional, default=" + + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit.\n" + "4. shielded_limit (numeric, optional, default=" + + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n" + "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n" + "\nResult:\n" + "{\n" + " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n" + " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n" + " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n" + " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n" + " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n" + " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n" + " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n" + " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n" + " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("z_mergetoaddress", "'[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf") + + HelpExampleRpc("z_mergetoaddress", "[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + ); + + if (!fEnableMergeToAddress) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled."); + } + + LOCK2(cs_main, pwalletMain->cs_wallet); + + bool useAny = false; + bool useAnyUTXO = false; + bool useAnyNote = false; + std::set taddrs = {}; + std::set zaddrs = {}; + + UniValue addresses = params[0].get_array(); + if (addresses.size()==0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty."); + + // Keep track of addresses to spot duplicates + std::set setAddress; + + // Sources + for (const UniValue& o : addresses.getValues()) { + if (!o.isStr()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string"); + + std::string address = o.get_str(); + if (address == "*") { + useAny = true; + } else if (address == "ANY_TADDR") { + useAnyUTXO = true; + } else if (address == "ANY_ZADDR") { + useAnyNote = true; + } else { + CBitcoinAddress taddr(address); + if (taddr.IsValid()) { + // Ignore any listed t-addrs if we are using all of them + if (!(useAny || useAnyUTXO)) { + taddrs.insert(taddr); + } + } else { + try { + CZCPaymentAddress zaddr(address); + // Ignore listed z-addrs if we are using all of them + if (!(useAny || useAnyNote)) { + zaddrs.insert(zaddr.Get()); + } + } catch (const std::runtime_error&) { + throw JSONRPCError( + RPC_INVALID_PARAMETER, + string("Invalid parameter, unknown address format: ") + address); + } + } + } + + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address); + setAddress.insert(address); + } + + // Validate the destination address + auto destaddress = params[1].get_str(); + bool isToZaddr = false; + CBitcoinAddress taddr(destaddress); + if (!taddr.IsValid()) { + try { + CZCPaymentAddress zaddr(destaddress); + zaddr.Get(); + isToZaddr = true; + } catch (const std::runtime_error&) { + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); + } + } + + // Convert fee from currency format to zatoshis + CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE; + if (params.size() > 2) { + if (params[2].get_real() == 0.0) { + nFee = 0; + } else { + nFee = AmountFromValue( params[2] ); + } + } + + int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT; + if (params.size() > 3) { + nUTXOLimit = params[3].get_int(); + if (nUTXOLimit < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative"); + } + } + + int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT; + if (params.size() > 4) { + nNoteLimit = params[4].get_int(); + if (nNoteLimit < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative"); + } + } + + std::string memo; + if (params.size() > 5) { + memo = params[5].get_str(); + if (!isToZaddr) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr."); + } else if (!IsHex(memo)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format."); + } + if (memo.length() > ZC_MEMO_SIZE*2) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE )); + } + } + + MergeToAddressRecipient recipient(destaddress, memo); + + // Prepare to get UTXOs and notes + std::vector utxoInputs; + std::vector noteInputs; + CAmount mergedUTXOValue = 0; + CAmount mergedNoteValue = 0; + CAmount remainingUTXOValue = 0; + CAmount remainingNoteValue = 0; + size_t utxoCounter = 0; + size_t noteCounter = 0; + bool maxedOutUTXOsFlag = false; + bool maxedOutNotesFlag = false; + size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (size_t)GetArg("-mempooltxinputlimit", 0); + + size_t estimatedTxSize = 200; // tx overhead + wiggle room + if (isToZaddr) { + estimatedTxSize += JOINSPLIT_SIZE; + } + + if (useAny || useAnyUTXO || taddrs.size() > 0) { + // Get available utxos + vector vecOutputs; + pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false); + + // Find unspent utxos and update estimated size + for (const COutput& out : vecOutputs) { + if (!out.fSpendable) { + continue; + } + + CTxDestination address; + if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { + continue; + } + // If taddr is not wildcard "*", filter utxos + if (taddrs.size() > 0 && !taddrs.count(address)) { + continue; + } + + utxoCounter++; + CAmount nValue = out.tx->vout[out.i].nValue; + + if (!maxedOutUTXOsFlag) { + CBitcoinAddress ba(address); + size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE; + if (estimatedTxSize + increase >= MAX_TX_SIZE || + (mempoolLimit > 0 && utxoCounter > mempoolLimit)) + { + maxedOutUTXOsFlag = true; + } else { + estimatedTxSize += increase; + COutPoint utxo(out.tx->GetHash(), out.i); + utxoInputs.emplace_back(utxo, nValue); + mergedUTXOValue += nValue; + } + } + + if (maxedOutUTXOsFlag) { + remainingUTXOValue += nValue; + } + } + } + + if (useAny || useAnyNote || zaddrs.size() > 0) { + // Get available notes + std::vector entries; + pwalletMain->GetFilteredNotes(entries, zaddrs); + + // Find unspent notes and update estimated size + for (CNotePlaintextEntry& entry : entries) { + noteCounter++; + CAmount nValue = entry.plaintext.value; + + if (!maxedOutNotesFlag) { + // If we haven't added any notes yet and the merge is to a + // z-address, we have already accounted for the first JoinSplit. + size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0; + if (estimatedTxSize + increase >= MAX_TX_SIZE || + (nNoteLimit > 0 && noteCounter > nNoteLimit)) + { + maxedOutNotesFlag = true; + } else { + estimatedTxSize += increase; + SpendingKey zkey; + pwalletMain->GetSpendingKey(entry.address, zkey); + noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey); + mergedNoteValue += nValue; + } + } + + if (maxedOutNotesFlag) { + remainingNoteValue += nValue; + } + } + } + + size_t numUtxos = utxoInputs.size(); + size_t numNotes = noteInputs.size(); + + if (numUtxos == 0 && numNotes == 0) { + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge."); + } + + // Sanity check: Don't do anything if: + // - We only have one from address + // - It's equal to toaddress + // - The address only contains a single UTXO or note + if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged."); + } + + CAmount mergedValue = mergedUTXOValue + mergedNoteValue; + if (mergedValue < nFee) { + throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, + strprintf("Insufficient funds, have %s, which is less than miners fee %s", + FormatMoney(mergedValue), FormatMoney(nFee))); + } + + // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee) + CAmount netAmount = mergedValue - nFee; + if (nFee > netAmount) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount))); + } + + // Keep record of parameters in context object + UniValue contextInfo(UniValue::VOBJ); + contextInfo.push_back(Pair("fromaddresses", params[0])); + contextInfo.push_back(Pair("toaddress", params[1])); + contextInfo.push_back(Pair("fee", ValueFromAmount(nFee))); + + // Contextual transaction we will build on + int nextBlockHeight = chainActive.Height() + 1; + CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction( + Params().GetConsensus(), + nextBlockHeight); + bool isShielded = numNotes > 0 || isToZaddr; + if (contextualTx.nVersion == 1 && isShielded) { + contextualTx.nVersion = 2; // Tx format should support vjoinsplit + } + if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta; + } + + // Create operation and add to global queue + std::shared_ptr q = getAsyncRPCQueue(); + std::shared_ptr operation( + new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) ); + q->addOperation(operation); + AsyncRPCOperationId operationId = operation->getId(); + + // Return continuation information + UniValue o(UniValue::VOBJ); + o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos)); + o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue))); + o.push_back(Pair("remainingNotes", noteCounter - numNotes)); + o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue))); + o.push_back(Pair("mergingUTXOs", numUtxos)); + o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue))); + o.push_back(Pair("mergingNotes", numNotes)); + o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue))); + o.push_back(Pair("opid", operationId)); + return o; +} + + UniValue z_listoperationids(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1d1ef114b..8b170817a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -8,7 +8,9 @@ #include "base58.h" #include "checkpoints.h" #include "coincontrol.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" +#include "consensus/consensus.h" #include "init.h" #include "main.h" #include "net.h" @@ -2522,6 +2524,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC CReserveKey reservekey(this); CWalletTx wtx; + if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false)) return false; @@ -2572,8 +2575,21 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt wtxNew.fTimeReceivedIsTxTime = true; wtxNew.BindWallet(this); - CMutableTransaction txNew; - + int nextBlockHeight = chainActive.Height() + 1; + CMutableTransaction txNew = CreateNewContextualCMutableTransaction( + Params().GetConsensus(), nextBlockHeight); + + // Activates after Overwinter network upgrade + // Set nExpiryHeight to expiryDelta (default 20) blocks past current block height + if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (nextBlockHeight + expiryDelta >= TX_EXPIRY_HEIGHT_THRESHOLD){ + strFailReason = _("nExpiryHeight must be less than TX_EXPIRY_HEIGHT_THRESHOLD."); + return false; + } else { + txNew.nExpiryHeight = nextBlockHeight + expiryDelta; + } + } + // Discourage fee sniping. // // However because of a off-by-one-error in previous versions we need to @@ -2767,6 +2783,9 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt } } + // Grab the current consensus branch ID + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + // Sign int nIn = 0; CTransaction txNewConst(txNew); @@ -2774,17 +2793,20 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt { bool signSuccess; const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey; - CScript& scriptSigRes = txNew.vin[nIn].scriptSig; + SignatureData sigdata; if (sign) - signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes); + signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata, consensusBranchId); else - signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes); + signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) { strFailReason = _("Signing transaction failed"); return false; + } else { + UpdateTransaction(txNew, nIn, sigdata); } + nIn++; } @@ -3686,13 +3708,26 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee) */ void CWallet::GetFilteredNotes(std::vector & outEntries, std::string address, int minDepth, bool ignoreSpent, bool ignoreUnspendable) { - bool fFilterAddress = false; - libzcash::PaymentAddress filterPaymentAddress; + std::set filterAddresses; + if (address.length() > 0) { - filterPaymentAddress = CZCPaymentAddress(address).Get(); - fFilterAddress = true; + filterAddresses.insert(CZCPaymentAddress(address).Get()); } + GetFilteredNotes(outEntries, filterAddresses, minDepth, ignoreSpent, ignoreUnspendable); +} + +/** + * Find notes in the wallet filtered by payment addresses, min depth and ability to spend. + * These notes are decrypted and added to the output parameter vector, outEntries. + */ +void CWallet::GetFilteredNotes( + std::vector& outEntries, + std::set& filterAddresses, + int minDepth, + bool ignoreSpent, + bool ignoreUnspendable) +{ LOCK2(cs_main, cs_wallet); for (auto & p : mapWallet) { @@ -3713,7 +3748,7 @@ void CWallet::GetFilteredNotes(std::vector & outEntries, st PaymentAddress pa = nd.address; // skip notes which belong to a different payment address in the wallet - if (fFilterAddress && !(pa == filterPaymentAddress)) { + if (!(filterAddresses.empty() || filterAddresses.count(pa))) { continue; } @@ -3726,11 +3761,6 @@ void CWallet::GetFilteredNotes(std::vector & outEntries, st if (ignoreUnspendable && !HaveSpendingKey(pa)) { continue; } - - // skip locked notes - if (IsLockedNote(jsop.hash, jsop.js, jsop.n)) { - continue; - } int i = jsop.js; // Index into CTransaction.vjoinsplit int j = jsop.n; // Index into JSDescription.ciphertexts @@ -3752,7 +3782,7 @@ void CWallet::GetFilteredNotes(std::vector & outEntries, st hSig, (unsigned char) j); - outEntries.push_back(CNotePlaintextEntry{jsop, plaintext}); + outEntries.push_back(CNotePlaintextEntry{jsop, pa, plaintext}); } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key @@ -3838,4 +3868,4 @@ void CWallet::GetUnspentFilteredNotes( } } } -} +} \ No newline at end of file diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index a117057e0..569701baa 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -8,9 +8,9 @@ #include "amount.h" #include "coins.h" -#include "consensus/consensus.h" #include "key.h" #include "keystore.h" +#include "main.h" #include "primitives/block.h" #include "primitives/transaction.h" #include "tinyformat.h" @@ -58,7 +58,7 @@ static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; //! Size of witness cache // Should be large enough that we can expect not to reorg beyond our cache // unless there is some exceptional network disruption. -static const unsigned int WITNESS_CACHE_SIZE = COINBASE_MATURITY; +static const unsigned int WITNESS_CACHE_SIZE = MAX_REORG_LENGTH + 1; class CBlockIndex; class CCoinControl; @@ -267,6 +267,7 @@ typedef std::map mapNoteData_t; struct CNotePlaintextEntry { JSOutPoint jsop; + libzcash::PaymentAddress address; libzcash::NotePlaintext plaintext; }; diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp index 5482348e3..5e144eabe 100644 --- a/src/wallet/wallet_ismine.cpp +++ b/src/wallet/wallet_ismine.cpp @@ -71,6 +71,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey) } break; } + case TX_MULTISIG: { // Only consider transactions "mine" if we own ALL the diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index bb51cdd6c..2c7e99a67 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -13,6 +13,7 @@ #include "crypto/equihash.h" #include "chain.h" #include "chainparams.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #include "main.h" #include "miner.h" @@ -221,11 +222,8 @@ double benchmark_verify_equihash() return timer_stop(tv_start); } -double benchmark_large_tx() +double benchmark_large_tx(size_t nInputs) { - // Number of inputs in the spending transaction that we will simulate - const size_t NUM_INPUTS = 555; - // Create priv/pub key CKey priv; priv.MakeNewKey(false); @@ -244,26 +242,20 @@ double benchmark_large_tx() auto orig_tx = CTransaction(m_orig_tx); CMutableTransaction spending_tx; + spending_tx.fOverwintered = true; + spending_tx.nVersion = 3; + spending_tx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; + auto input_hash = orig_tx.GetHash(); - // Add NUM_INPUTS inputs - for (size_t i = 0; i < NUM_INPUTS; i++) { + // Add nInputs inputs + for (size_t i = 0; i < nInputs; i++) { spending_tx.vin.emplace_back(input_hash, 0); } // Sign for all the inputs - for (size_t i = 0; i < NUM_INPUTS; i++) { - SignSignature(tempKeystore, prevPubKey, spending_tx, i, SIGHASH_ALL); - } - - // Serialize: - { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << spending_tx; - //std::cout << "SIZE OF SPENDING TX: " << ss.size() << std::endl; - - auto error = MAX_TX_SIZE / 20; // 5% error - assert(ss.size() < MAX_TX_SIZE + error); - assert(ss.size() > MAX_TX_SIZE - error); + auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId; + for (size_t i = 0; i < nInputs; i++) { + SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId); } // Spending tx has all its inputs signed and does not need to be mutated anymore @@ -272,12 +264,14 @@ double benchmark_large_tx() // Benchmark signature verification costs: struct timeval tv_start; timer_start(tv_start); - for (size_t i = 0; i < NUM_INPUTS; i++) { + PrecomputedTransactionData txdata(final_spending_tx); + for (size_t i = 0; i < nInputs; i++) { ScriptError serror = SCRIPT_ERR_OK; assert(VerifyScript(final_spending_tx.vin[i].scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, - TransactionSignatureChecker(&final_spending_tx, i), + TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata), + consensusBranchId, &serror)); } return timer_stop(tv_start); diff --git a/src/zcbenchmarks.h b/src/zcbenchmarks.h index ac87d0326..60a0be848 100644 --- a/src/zcbenchmarks.h +++ b/src/zcbenchmarks.h @@ -12,7 +12,7 @@ extern double benchmark_solve_equihash(); extern std::vector benchmark_solve_equihash_threaded(int nThreads); extern double benchmark_verify_joinsplit(const JSDescription &joinsplit); extern double benchmark_verify_equihash(); -extern double benchmark_large_tx(); +extern double benchmark_large_tx(size_t nInputs); extern double benchmark_try_decrypt_notes(size_t nAddrs); extern double benchmark_increment_note_witnesses(size_t nTxs); extern double benchmark_connectblock_slow();